Changeset 834bcc3 in Klonkt for src/services/AudioEmbedService.js
- Timestamp:
- 06/23/2026 06:14:27 PM (3 months ago)
- Branches:
- main
- Children:
- d774679
- Parents:
- bb42dfb
- File:
-
- 1 edited
-
src/services/AudioEmbedService.js (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/AudioEmbedService.js
rbb42dfb r834bcc3 11 11 */ 12 12 13 // "Open in" -iconen (brand-gekleurd via CSS .pat-link--*).13 // "Open in" icons (brand-colored via CSS .pat-link--). 14 14 const OPEN_IN_SVG = { 15 15 spotify: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2a10 10 0 100 20 10 10 0 000-20zm4.6 14.42a.62.62 0 01-.86.21c-2.35-1.44-5.3-1.76-8.79-.96a.62.62 0 11-.28-1.21c3.8-.87 7.07-.5 9.71 1.11.3.18.39.57.22.85zm1.23-2.73a.78.78 0 01-1.07.26c-2.69-1.66-6.79-2.14-9.97-1.17a.78.78 0 11-.45-1.49c3.63-1.1 8.15-.56 11.24 1.33.36.22.48.7.25 1.07zm.1-2.85C14.66 8.95 9.4 8.78 6.3 9.72a.93.93 0 11-.54-1.79c3.56-1.08 9.37-.87 13.07 1.33a.94.94 0 01-.96 1.61z"/></svg>', … … 19 19 20 20 class AudioEmbedService { 21 // Kleine "open in"-links voor een track (Spotify/YouTube/SoundCloud). De hrefs22 // zijn server-side al gevalideerd (alleen https + juiste host). Geeft '' als er23 // geen links zijn. Wordt naast de play-knop gezet (buiten de knop → geen24 // conflict met afspelen).21 // Small "open in" links for a track (Spotify/YouTube/SoundCloud). The hrefs 22 // are already validated server-side (https + correct host only). Returns '' 23 // when no links exist. Placed next to the play button (outside the button → 24 // no conflict with playback). 25 25 static openInLinks(t) { 26 26 if (!t) return ''; … … 40 40 url = url.trim(); 41 41 42 // Alleen http(s)-URL's embedden. De provider-regexes hieronder zijn NIET43 // verankerd, dus zonder deze check zou bv. `javascript:alert(1)//youtu.be/x`44 // matchen en als embed-URL belanden (stored XSS via een [[embed:...]]-45 // shortcode — die tekst gaat niet langs de HTML-sanitizer omdat 'ie in een46 // text -node zit). De scheme-guard sluit javascript:/data:/vbscript: enz. uit.42 // Only embed http(s) URLs. The provider regexes below are NOT anchored, 43 // so without this check e.g. `javascript:alert(1)//youtu.be/x` would match 44 // and land as an embed URL (stored XSS via an [[embed:...]] shortcode — 45 // that text never passes through the HTML sanitizer because it lives in a 46 // text node). The scheme guard excludes javascript:/data:/vbscript: etc. 47 47 if (!/^https?:\/\//i.test(url)) return null; 48 48 … … 68 68 } 69 69 70 // YouTube — video -id is altijd exact 11 tekens (lijnt uit met de client-side71 // ytId() in embed-player.js, die ook {11} verwacht).70 // YouTube — video id is always exactly 11 characters (aligns with the client-side 71 // ytId() in embed-player.js, which also expects {11}). 72 72 if (/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/shorts\/|youtube\.com\/live\/)([A-Za-z0-9_-]{11})/i.test(url)) { 73 73 const match = url.match(/(?:v=|youtu\.be\/|embed\/|shorts\/|live\/)([A-Za-z0-9_-]{11})/i); … … 86 86 static generateIframe(provider, config) { 87 87 switch (provider) { 88 // Eigen custom-spelers (client-side via embed-player.js + de echte89 // platform-API's). We renderen een placeholder met data-attributen i.p.v.90 // het kale platform-iframe, zodat de embed in ÓNZE huisstijl verschijnt.88 // Custom players (client-side via embed-player.js + the real platform APIs). 89 // We render a placeholder with data attributes instead of the bare platform 90 // iframe, so the embed appears in OUR brand style. 91 91 case 'youtube': 92 92 return this.embedPlaceholder('youtube', config.id, 'video', … … 97 97 return this.embedPlaceholder('spotify', `spotify:${config.type}:${config.id}`, 98 98 config.type, config.url || `https://open.spotify.com/${config.type}/${config.id}`); 99 // Geen JS-API (Bandcamp/Apple) of niet-prioritair (Vimeo): blijven een100 // iframe; mutual-exclusion loopt voor deze via de blur-fallback.99 // No JS API (Bandcamp/Apple) or low priority (Vimeo): remain as iframes; 100 // mutual exclusion for these runs via the blur fallback. 101 101 case 'bandcamp': 102 102 return this.bandcampIframe(config); … … 111 111 112 112 /** 113 * Placeholder voor een eigen custom-speler. embed-player.js pikt114 * .folio-embed[data-embed-provider] op en bouwt de kaart + speler client-side.115 * ALL E waarden via escape() — post.content_html wordt ongeescaped uitgevoerd.113 * Placeholder for a custom player. embed-player.js picks up 114 * .folio-embed[data-embed-provider] and builds the card + player client-side. 115 * ALL values go through escape() — post.content_html is executed unescaped. 116 116 */ 117 117 static embedPlaceholder(provider, ref, type, url) { … … 244 244 245 245 /** 246 * Replace [[embed:<url>]] shortcodes met de platform-iframe (YouTube, Spotify,247 * SoundCloud, Apple Music, Bandcamp, Vimeo). De editor-knop voegt deze248 * shortcode in; losse URL-regels embedden ook automatischvia autoembed().249 * Niet-ondersteunde/ongeldige URLs krijgen een nette inline-melding.246 * Replace [[embed:<url>]] shortcodes with the platform iframe (YouTube, Spotify, 247 * SoundCloud, Apple Music, Bandcamp, Vimeo). The editor button inserts this 248 * shortcode; bare URL lines also embed automatically via autoembed(). 249 * Unsupported/invalid URLs get a clean inline notice. 250 250 */ 251 251 static embedMediaShortcodes(html) { … … 274 274 const artistH0 = this.escape(t.artist || ''); 275 275 const creditBits0 = [this.escape(t.credit || ''), this.escape(t.license || '')].filter(Boolean).join(' · '); 276 // Link-only track ( geen audiobestand): geen afspeelknop, wel info + open-in.276 // Link-only track (no audio file): no play button, but info + open-in links. 277 277 if (!t.url) { 278 278 const coverH0 = this.escape(t.cover || ''); … … 302 302 const artistH = this.escape(t.artist || ''); 303 303 const urlH = this.escape(t.url); 304 // Zichtbare eigenaar/licentie-regel onder de track.304 // Visible owner/license line below the track. 305 305 const creditBits = [this.escape(t.credit || ''), this.escape(t.license || '')].filter(Boolean).join(' · '); 306 306 const dataAttr = trackJson 307 307 .replace(/&/g, '&').replace(/'/g, ''').replace(/</g, '<'); 308 // id="track-<id>" = an ker zodat de mini-speler hierheen kan scrollen.308 // id="track-<id>" = anchor so the mini-player can scroll to this element. 309 309 return `<div class="post-audio-track" id="track-${id}" data-pcms-track-id="${id}" data-pcms-track-url="${urlH}" data-pcms-track='${dataAttr}'> 310 310 <button type="button" class="pat-play" aria-label="Play ${titleH}"> … … 337 337 // Stable DOM id for this rendering — used as data-pcms-album-id on tracks 338 338 const albumDomId = 'album-' + Math.random().toString(36).slice(2, 10); 339 // Alleen afspeelbare tracks (met url) in de queue; link-only tracks staan340 // wel in de lijst maar niet in de afspeel-JSON.339 // Only playable tracks (with url) in the queue; link-only tracks appear 340 // in the list but not in the playback JSON. 341 341 const albumJson = JSON.stringify(album.tracks.filter((t) => t.url)) 342 342 .replace(/&/g, '&').replace(/'/g, ''').replace(/</g, '<'); … … 348 348 const tTitle = this.escape(t.title || ('Track ' + (i + 1))); 349 349 const tArtist = this.escape(t.artist || ''); 350 // Link-only track: geen afspeelknop, wel nummer + info + open-in.350 // Link-only track: no play button, but track number + info + open-in links. 351 351 if (!t.url) { 352 352 return ` <li class="post-audio-track post-audio-track--static"${t.id ? ` id="track-${t.id}"` : ''}> … … 436 436 // Audio-player.js reads data-pcms-album for queue. Same shape as 437 437 // embedAlbumShortcodes — keep both in sync. 438 // Alleen afspeelbare tracks in de queue; link-only tracks staan wel in de439 // lijst maar niet in de afspeel-JSON.438 // Only playable tracks in the queue; link-only tracks appear in the list 439 // but not in the playback JSON. 440 440 const tracksData = pl.tracks.filter(t => t.url).map(t => ({ 441 441 id: t.id, … … 479 479 : `<span class="pat-num">${i + 1}</span>`; 480 480 481 // Link-only track: geen klikbare afspeel-rij (statische div), wel open-in.481 // Link-only track: no clickable play row (static div), but open-in links. 482 482 if (!t.url) { 483 483 return ` <li class="post-album-track-compact post-album-track-compact--static"${t.id ? ` id="track-${t.id}"` : ''}> … … 594 594 * Replace [[link:url]] or [[link:url|Custom Label]] shortcodes with a 595 595 * branded "Open in <Platform>" anchor (no iframe). Opens in new tab. 596 * Per Robin's v9: "Extern e link, klik = open platform (target _blank)".596 * Per Robin's v9: "External link, click = open platform (target _blank)". 597 597 */ 598 598 static embedExternalLinkShortcodes(html) {
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)