Changeset a85f539 in Klonkt
- Timestamp:
- 07/16/2026 12:20:51 PM (8 weeks ago)
- Branches:
- main
- Children:
- e276d03
- Parents:
- 8e7f0ec
- git-author:
- Robin <roboburr@…> (07/12/2026 10:30:07 PM)
- git-committer:
- Robin <roboburr@…> (07/16/2026 12:20:51 PM)
- Location:
- src/services
- Files:
-
- 2 edited
-
AudioEmbedService.js (modified) (3 diffs)
-
HtmlSanitizerService.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/services/AudioEmbedService.js
r8e7f0ec ra85f539 82 82 83 83 return null; 84 } 85 86 // Direct media files (video/audio) hosted anywhere → a native <video>/<audio> 87 // player. Kept OUT of detectProvider() on purpose: the timeline/cover callers 88 // switch on provider slugs (youtube/spotify/…) and a bare file has none, so 89 // overloading detectProvider would suppress e.g. a PeerTube fallback. Only 90 // autoembed() and [[embed:…]] use this. 91 static MEDIA_FILE_EXT = { 92 video: ['mp4', 'webm', 'm4v', 'mov', 'ogv'], 93 audio: ['mp3', 'ogg', 'oga', 'wav', 'm4a', 'flac', 'opus', 'aac'], 94 }; 95 96 static detectMediaFile(url) { 97 if (!url || typeof url !== 'string') return null; 98 if (!/^https?:\/\//i.test(url)) return null; 99 let pathname; 100 try { pathname = new URL(url).pathname.toLowerCase(); } catch { return null; } 101 const ext = (pathname.match(/\.([a-z0-9]+)$/) || [])[1]; 102 if (!ext) return null; 103 if (this.MEDIA_FILE_EXT.video.includes(ext)) return { kind: 'video', url }; 104 if (this.MEDIA_FILE_EXT.audio.includes(ext)) return { kind: 'audio', url }; 105 return null; 106 } 107 108 static mediaFileEmbed(url) { 109 const m = this.detectMediaFile(url); 110 if (!m) return null; 111 const src = this.escape(m.url); 112 if (m.kind === 'video') { 113 return `<figure class="folio-embed folio-embed--video"><video src="${src}" controls preload="metadata" playsinline></video></figure>`; 114 } 115 return `<figure class="folio-embed folio-embed--audio"><audio src="${src}" controls preload="metadata"></audio></figure>`; 84 116 } 85 117 … … 238 270 return iframe || match; 239 271 } 272 // Bare media file (…/clip.webm, …/song.mp3) → native player. 273 const media = this.mediaFileEmbed(url); 274 if (media) return media; 240 275 return match; 241 276 } … … 255 290 const detected = this.detectProvider(url); 256 291 if (!detected) { 292 // Bare media file (…/clip.webm, …/song.mp3) → native player. 293 const media = this.mediaFileEmbed(url); 294 if (media) return media; 257 295 return `<div class="post-embed-missing"><em>Embed: niet-ondersteunde of ongeldige URL.</em></div>`; 258 296 } -
src/services/HtmlSanitizerService.js
r8e7f0ec ra85f539 25 25 'strong', 'em', 'b', 'i', 'u', 's', 'mark', 'small', 'sub', 'sup', 26 26 'code', 'a', 'span', 'img', 27 // Native media (bare .webm/.mp4/.mp3 embeds + federated-in players) 28 'video', 'audio', 'source', 27 29 ]; 28 30 29 31 // Per-tag attribute allowlist. '*' applies to every tag. 30 32 const ALLOWED_ATTRS = { 31 '*': ['class', 'id', 'dir', 'lang', 'data-sc'], 32 a: ['href', 'title', 'target', 'rel'], 33 img: ['src', 'alt', 'title', 'width', 'height', 'loading'], 33 '*': ['class', 'id', 'dir', 'lang', 'data-sc'], 34 a: ['href', 'title', 'target', 'rel'], 35 img: ['src', 'alt', 'title', 'width', 'height', 'loading'], 36 video: ['src', 'controls', 'preload', 'poster', 'width', 'height', 'loop', 'muted', 'autoplay', 'playsinline'], 37 audio: ['src', 'controls', 'preload', 'loop', 'muted', 'autoplay'], 38 source: ['src', 'type'], 34 39 }; 35 40 36 41 const ALLOWED_SCHEMES = ['http', 'https', 'mailto', 'tel']; 37 42 const ALLOWED_SCHEMES_BY_TAG = { 38 img: ['http', 'https', 'data'], 39 a: ['http', 'https', 'mailto', 'tel'], 43 img: ['http', 'https', 'data'], 44 a: ['http', 'https', 'mailto', 'tel'], 45 video: ['http', 'https'], 46 audio: ['http', 'https'], 47 source: ['http', 'https'], 40 48 }; 41 49
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)