Changeset fef781e in Klonkt for src/assets/js/embed-player.js


Ignore:
Timestamp:
06/20/2026 04:46:35 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
0d7acdf
Parents:
8ab20b6
Message:

revert: remove YouTube audio functionality (doesn't work)

YouTube blocks audio-only/hidden embed playback with a "Sign in to confirm
you're not a bot" gate → not reliably usable. All YT-audio reverted:

  • embed-player.js + embed.css → state before the feature (audio-only card, YT-album, buildYtAlbum, prewarm, mode-routing removed). Video embeds + the YT/SC volume button remain.
  • audio-player.js → YT backend (ytMode/ensureYT/playYouTube/playYouTubeList/…) removed; only the blob-<audio> player + existing features.
  • AudioEmbedService.js → audio:/video: mode parsing + data-embed-mode removed.
  • audio.js → /yt-title oEmbed proxy removed.
  • post-edit.ejs → audio/video choice on the embed button removed ([[embed:url]]

normal).

busters audio-player.js?v=28, embed-player.js?v=16, embed.css?v=8.

Co-Authored-By: Claude <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/assets/js/embed-player.js

    r8ab20b6 rfef781e  
    162162    if (!provider) return;
    163163
    164     // Audio-only YouTube met een afspeellijst (?list=…) → album-kaart met tracklijst.
    165     if (provider === 'youtube' && el.dataset.embedMode === 'audio') {
    166       const lm = url.match(/[?&]list=([A-Za-z0-9_-]+)/);
    167       if (lm) { try { buildYtAlbum(el, lm[1]); } catch (e) { console.error('[pcms-embed] yt-album faalde', e); } return; }
    168     }
    169 
    170164    el.classList.add('pcms-embed-card', 'pcms-embed-card--' + provider);
    171165    el.classList.remove('pcms-embed-loading');
     
    189183
    190184    // --- UI ophangen (verschilt per provider-type) ---
    191     // Audio-only YouTube (data-embed-mode="audio"): render als audio-kaart met
    192     // onze controls; de YT-speler draait verborgen (off-screen) en levert alleen
    193     // het geluid. Video blijft de default.
    194     const audioOnly = provider === 'youtube' && el.dataset.embedMode === 'audio';
    195     if (audioOnly) el.classList.add('pcms-embed-audio-mode');
    196     const isVideo = provider === 'youtube' && !audioOnly;
    197     // Audio-only YT speelt via de site-onderbalk → geen eigen in-kaart controlebar.
    198     const custom = (provider === 'youtube' || provider === 'soundcloud') && !audioOnly;
     185    const isVideo = provider === 'youtube';
     186    const custom = provider === 'youtube' || provider === 'soundcloud'; // eigen controls
    199187    const poster = provider === 'youtube'
    200188      ? `https://i.ytimg.com/vi/${ytId(ref, url)}/hqdefault.jpg` : '';
    201     // 16:9-thumbnail ZONDER zwarte balken (mqdefault) voor de vierkante cover —
    202     // hqdefault is 4:3 met letterbox en vult een vierkant niet schoon.
    203     const ytThumb = provider === 'youtube'
    204       ? `https://i.ytimg.com/vi/${ytId(ref, url)}/mqdefault.jpg` : '';
    205189
    206190    el.innerHTML = ''
     
    238222    let vol = 100;       // huidige volume 0-100 (wordt op de adapter toegepast)
    239223    let preMuteVol = 100;
    240     // Audio-only YouTube: zet de thumbnail als albumhoes op de audio-kaart.
    241     let ytTitle = '';  // echte videotitel (via same-origin oEmbed-proxy)
    242     if (audioOnly && ytThumb) {
    243       const art0 = el.querySelector('.pcms-embed-art');
    244       if (art0) { art0.style.backgroundImage = `url('${ytThumb}')`; art0.classList.add('has-art'); }
    245       // Speler vast aanmaken → eerste klik valt binnen de user-gesture (autoplay).
    246       if (window.pcmsAudioPlayer && window.pcmsAudioPlayer.prewarmYouTube) window.pcmsAudioPlayer.prewarmYouTube();
    247       // Haal de echte titel op (server-proxy, want YT-oEmbed heeft geen CORS) en
    248       // toon 'm i.p.v. "YouTube".
    249       fetch('/audio/yt-title?url=' + encodeURIComponent(url))
    250         .then((r) => (r.ok ? r.json() : null))
    251         .then((d) => {
    252           if (d && d.title) {
    253             ytTitle = d.title;
    254             const tt = el.querySelector('.pcms-embed-title');
    255             if (tt) tt.textContent = d.title;
    256           }
    257         })
    258         .catch(() => {});
    259     }
    260224
    261225    function setPlayingUI(on) {
     
    332296    // Eerste interactie → adapter mounten + spelen. Daarna toggelt de knop.
    333297    async function ensureMountedAndPlay() {
    334       // Audio-only YouTube → speel via de site-audiospeler (onderbalk): zichtbaar
    335       // én doorspelen bij navigeren. De inline-kaart is enkel de launcher.
    336       if (audioOnly && window.pcmsAudioPlayer && typeof window.pcmsAudioPlayer.playYouTube === 'function') {
    337         window.pcmsAudioPlayer.playYouTube({ id: ytId(ref, url), title: ytTitle || undefined, cover: ytThumb, postUrl: location.pathname + location.search });
    338         el.classList.add('pcms-embed-elsewhere');
    339         return;
    340       }
    341298      if (mounted) { if (adapter) adapter.play(); return; }
    342299      mounted = true;
     
    391348  }
    392349
    393   // Haal de video-IDs van een YouTube-afspeellijst op via een verborgen,
    394   // tijdelijke speler (cuePlaylist → getPlaylist). Geen API-key nodig.
    395   function ytPlaylistIds(listId) {
    396     return ytApi().then((YT) => new Promise((resolve) => {
    397       if (!YT || !YT.Player) { resolve([]); return; }
    398       const host = document.createElement('div');
    399       host.style.cssText = 'position:absolute;left:-99999px;top:0;width:320px;height:180px;opacity:0;pointer-events:none';
    400       const mount = document.createElement('div'); host.appendChild(mount); document.body.appendChild(host);
    401       let done = false;
    402       const finish = (ids) => { if (done) return; done = true; try { p.destroy(); } catch (e) {} try { host.remove(); } catch (e) {} resolve(ids || []); };
    403       const p = new YT.Player(mount, {
    404         host: 'https://www.youtube-nocookie.com', playerVars: { playsinline: 1 },
    405         events: { onReady: () => {
    406           try { p.cuePlaylist({ listType: 'playlist', list: listId }); } catch (e) {}
    407           setTimeout(() => { let ids = []; try { ids = p.getPlaylist() || []; } catch (e) {} finish(ids); }, 2500);
    408         } },
    409       });
    410       setTimeout(() => finish([]), 9000);
    411     }));
    412   }
    413 
    414   // Render een audio-only YouTube-AFSPEELLIJST als album-kaart (zelfde stijl als
    415   // de eigen albums) met tracklijst; afspelen loopt via de site-audiospeler.
    416   async function buildYtAlbum(el, listId) {
    417     el.className = 'folio-embed pcms-ytalbum';  // geen losse card-chrome; .post-album stuurt de stijl
    418     const thumb = (id) => `https://i.ytimg.com/vi/${id}/mqdefault.jpg`;
    419     el.innerHTML = ''
    420       + '<div class="post-album">'
    421       +   '<div class="post-album-header">'
    422       +     '<button type="button" class="post-album-cover-btn" aria-label="Album afspelen">'
    423       +       '<img class="post-album-cover-img" src="" alt="">'
    424       +       '<span class="post-album-play-overlay" aria-hidden="true"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M8 4l12 8-12 8z"/></svg></span>'
    425       +     '</button>'
    426       +     '<div class="post-album-info">'
    427       +       '<h3 class="post-album-title">Album laden…</h3>'
    428       +       '<p class="post-album-artist"></p>'
    429       +       '<p class="post-album-count">YouTube</p>'
    430       +     '</div>'
    431       +   '</div>'
    432       +   '<ol class="post-album-tracks"><li class="pcms-ytalbum-msg">Tracks laden…</li></ol>'
    433       + '</div>';
    434     const coverImg = el.querySelector('.post-album-cover-img');
    435     const titleEl = el.querySelector('.post-album-title');
    436     const countEl = el.querySelector('.post-album-count');
    437     const olEl = el.querySelector('.post-album-tracks');
    438     const coverBtn = el.querySelector('.post-album-cover-btn');
    439 
    440     // Albumnaam via de oEmbed-proxy (playlist-url).
    441     fetch('/audio/yt-title?url=' + encodeURIComponent('https://www.youtube.com/playlist?list=' + listId))
    442       .then((r) => (r.ok ? r.json() : null)).then((d) => { if (d && d.title) titleEl.textContent = d.title; }).catch(() => {});
    443 
    444     let ids = [];
    445     try { ids = await ytPlaylistIds(listId); } catch (e) { ids = []; }
    446     if (!ids.length) { olEl.innerHTML = '<li class="pcms-ytalbum-msg">Kon de afspeellijst niet laden.</li>'; return; }
    447     countEl.textContent = ids.length + ' track' + (ids.length === 1 ? '' : 's');
    448     if (coverImg) coverImg.src = thumb(ids[0]);
    449     // Speler vast aanmaken → eerste klik valt binnen de user-gesture (autoplay).
    450     if (window.pcmsAudioPlayer && window.pcmsAudioPlayer.prewarmYouTube) window.pcmsAudioPlayer.prewarmYouTube();
    451 
    452     olEl.innerHTML = ids.map((id, i) =>
    453       `<li class="post-album-track-compact" id="track-${id}" data-yt-id="${id}" data-yt-index="${i}">`
    454       + `<button type="button" class="pat-row" aria-label="Speel track ${i + 1}">`
    455       +   `<span class="pat-cover" style="background-image:url('${thumb(id)}')" aria-hidden="true"></span>`
    456       +   `<span class="pat-meta"><span class="pat-title">Track ${i + 1}</span><span class="pat-artist"></span></span>`
    457       +   `<span class="pat-duration pat-duration-empty">—:—</span>`
    458       + `</button></li>`
    459     ).join('');
    460 
    461     // Tracktitels lazy invullen (oEmbed-proxy per video).
    462     ids.forEach((id, i) => {
    463       fetch('/audio/yt-title?url=' + encodeURIComponent('https://www.youtube.com/watch?v=' + id))
    464         .then((r) => (r.ok ? r.json() : null))
    465         .then((d) => { if (d && d.title) { const tt = olEl.querySelector(`[data-yt-index="${i}"] .pat-title`); if (tt) tt.textContent = d.title; } })
    466         .catch(() => {});
    467     });
    468 
    469     function playAt(i) {
    470       if (!(window.pcmsAudioPlayer && window.pcmsAudioPlayer.playYouTubeList)) return;
    471       // Expandeer naar losse YT-tracks (betrouwbaarder dan loadPlaylist).
    472       const items = ids.map((id, j) => ({
    473         yt: id,
    474         title: (olEl.querySelector(`[data-yt-index="${j}"] .pat-title`) || {}).textContent || ('Track ' + (j + 1)),
    475         cover: thumb(id),
    476         postUrl: location.pathname + location.search,
    477       }));
    478       window.pcmsAudioPlayer.playYouTubeList(items, i);
    479     }
    480     coverBtn.addEventListener('click', () => playAt(0));
    481     olEl.addEventListener('click', (e) => { const li = e.target.closest('[data-yt-index]'); if (li) playAt(parseInt(li.dataset.ytIndex, 10) || 0); });
    482   }
    483 
    484350  // ============================================================
    485351  // 4. Adapters — normaliseren de 3 zeer verschillende API's naar 1 vorm.
     
    503369          events: {
    504370            onReady() {
    505               let d = 0; const meta = {};
    506               try { d = player.getDuration() || 0; } catch (e) {}
    507               try { const vd = player.getVideoData(); if (vd && vd.title) meta.title = vd.title; } catch (e) {}
    508               meta.duration = d;
    509               hooks.onReady(meta);
     371              let d = 0; try { d = player.getDuration() || 0; } catch (e) {}
     372              hooks.onReady({ duration: d });
    510373              resolve({
    511374                play() { try { player.playVideo(); } catch (e) {} },
Note: See TracChangeset for help on using the changeset viewer.