feat(embeds): TikTok URL trim, SoundCloud on. + redd.it short links

- TikTok player URL trimmed to ?autoplay=1&rel=0 (the control params were all
  default-on no-ops).
- SoundCloud on.soundcloud.com share short links now embed (widget follows the
  redirect via w.soundcloud.com).
- redd.it short links now embed via embed.reddit.com/comments/<id>/ (the redirect
  target is reddit.com/comments/<id>, no subreddit needed).

No CSP change (hosts already allowlisted). Vimeo event/ondemand deferred — the
embed format/host couldn't be verified from a fake id and would need a CSP
change; leaving it for the review agents to research. Tests 21.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 00:32:09 -04:00
parent 3694a3612d
commit a28c305835
2 changed files with 22 additions and 10 deletions
+6 -2
View File
@@ -89,7 +89,7 @@ test('tiktokIdFromOembed + player url', () => {
assert.equal(tiktokIdFromOembed({ embed_product_id: '7659555276823006478' }), '7659555276823006478'); assert.equal(tiktokIdFromOembed({ embed_product_id: '7659555276823006478' }), '7659555276823006478');
assert.equal(tiktokIdFromOembed({ html: '<blockquote data-video-id="123456">' }), '123456'); assert.equal(tiktokIdFromOembed({ html: '<blockquote data-video-id="123456">' }), '123456');
assert.equal(tiktokIdFromOembed({}), null); assert.equal(tiktokIdFromOembed({}), null);
assert.ok(tiktokPlayerEmbedUrl('999').startsWith('https://www.tiktok.com/player/v1/999?autoplay=1')); assert.equal(tiktokPlayerEmbedUrl('999'), 'https://www.tiktok.com/player/v1/999?autoplay=1&rel=0');
}); });
test('Dailymotion + Streamable', () => { test('Dailymotion + Streamable', () => {
@@ -132,9 +132,11 @@ test('Spotify target + height', () => {
assert.equal(spotifyEmbedHeight('album'), 352); assert.equal(spotifyEmbedHeight('album'), 352);
}); });
test('SoundCloud track detection', () => { test('SoundCloud track detection (+ on. short link)', () => {
assert.equal(isSoundCloudTrack('https://soundcloud.com/artist/some-track'), true); assert.equal(isSoundCloudTrack('https://soundcloud.com/artist/some-track'), true);
assert.equal(isSoundCloudTrack('https://soundcloud.com/artist'), false); // bare profile assert.equal(isSoundCloudTrack('https://soundcloud.com/artist'), false); // bare profile
assert.equal(isSoundCloudTrack('https://on.soundcloud.com/abc123'), true); // share short link
assert.equal(parseMediaEmbed('https://on.soundcloud.com/abc123', 'h')?.provider, 'soundcloud');
}); });
test('buildVideoEmbedUrl: cookie-less YouTube + Vimeo', () => { test('buildVideoEmbedUrl: cookie-less YouTube + Vimeo', () => {
@@ -218,6 +220,8 @@ test('Reddit post embed → redditmedia', () => {
); );
assert.equal(getRedditPostEmbed('https://old.reddit.com/r/aww/comments/xyz/'), 'https://embed.reddit.com/r/aww/comments/xyz/?ref_source=embed&ref=share&embed=true&theme=dark'); assert.equal(getRedditPostEmbed('https://old.reddit.com/r/aww/comments/xyz/'), 'https://embed.reddit.com/r/aww/comments/xyz/?ref_source=embed&ref=share&embed=true&theme=dark');
assert.equal(getRedditPostEmbed('https://www.reddit.com/r/aww/'), null); // subreddit, not a post assert.equal(getRedditPostEmbed('https://www.reddit.com/r/aww/'), null); // subreddit, not a post
// redd.it short link → comments-only embed (no subreddit in the redirect)
assert.equal(getRedditPostEmbed('https://redd.it/1abc23'), 'https://embed.reddit.com/comments/1abc23/?ref_source=embed&ref=share&embed=true&theme=dark');
}); });
test('parseMediaEmbed: Instagram/Reddit → rich, Tidal → audio', () => { test('parseMediaEmbed: Instagram/Reddit → rich, Tidal → audio', () => {
+16 -8
View File
@@ -163,12 +163,10 @@ export function extractEmbedHeight(data: unknown): number | undefined {
} }
export function tiktokPlayerEmbedUrl(id: string): string { export function tiktokPlayerEmbedUrl(id: string): string {
// Pure 9:16 video player. NOTE: music_info/description are intentionally OFF — // Pure 9:16 video player. music_info/description default OFF (they'd switch
// they switch TikTok to a wide "video + info panel" layout that leaves empty // TikTok to a wide "video + info panel" layout); controls/progress/play/volume/
// space beside the video in a portrait box. // fullscreen buttons all default ON, so only autoplay + rel are load-bearing.
return `https://www.tiktok.com/player/v1/${encodeURIComponent( return `https://www.tiktok.com/player/v1/${encodeURIComponent(id)}?autoplay=1&rel=0`;
id,
)}?autoplay=1&controls=1&progress_bar=1&play_button=1&volume_control=1&fullscreen_button=1&rel=0`;
} }
// --- Dailymotion ---------------------------------------------------------- // --- Dailymotion ----------------------------------------------------------
@@ -249,7 +247,10 @@ export function getSpotifyEmbedTarget(url: string): { type: SpotifyType; id: str
export function isSoundCloudTrack(url: string): boolean { export function isSoundCloudTrack(url: string): boolean {
try { try {
const { hostname, pathname } = new URL(url); const { hostname, pathname } = new URL(url);
if (hostname.replace(/^www\./, '') !== 'soundcloud.com') return false; const h = hostname.replace(/^www\./, '');
// on.soundcloud.com/<code> is a share short link — the widget follows it.
if (h === 'on.soundcloud.com') return pathname.replace(/^\/+|\/+$/g, '').length > 0;
if (h !== 'soundcloud.com') return false;
// /<artist>/<track|sets/set> — at least two segments, not a bare profile // /<artist>/<track|sets/set> — at least two segments, not a bare profile
const parts = pathname.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean); const parts = pathname.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
return parts.length >= 2; return parts.length >= 2;
@@ -346,15 +347,22 @@ export function getInstagramEmbed(url: string): string | null {
// --- Reddit (post embed via redditmedia — bypasses the homeserver's blocked // --- Reddit (post embed via redditmedia — bypasses the homeserver's blocked
// preview fetch, which Reddit serves a bot-check "please wait" page to) --- // preview fetch, which Reddit serves a bot-check "please wait" page to) ---
const REDDIT_EMBED_QS = '?ref_source=embed&ref=share&embed=true&theme=dark';
export function getRedditPostEmbed(url: string): string | null { export function getRedditPostEmbed(url: string): string | null {
try { try {
const u = new URL(url); const u = new URL(url);
const h = u.hostname.replace(/^(www|old|new|np|i)\./, ''); const h = u.hostname.replace(/^(www|old|new|np|i)\./, '');
// redd.it/<id> short link → reddit.com/comments/<id> (no subreddit needed).
if (h === 'redd.it') {
const id = u.pathname.replace(/^\/+|\/+$/g, '').split('/')[0];
return id ? `https://embed.reddit.com/comments/${id}/${REDDIT_EMBED_QS}` : null;
}
if (h !== 'reddit.com') return null; if (h !== 'reddit.com') return null;
const m = u.pathname.match(/^\/r\/([A-Za-z0-9_]+)\/comments\/([A-Za-z0-9]+)/); const m = u.pathname.match(/^\/r\/([A-Za-z0-9_]+)\/comments\/([A-Za-z0-9]+)/);
if (!m) return null; if (!m) return null;
// embed.reddit.com is the current host (www.redditmedia.com now 301s here). // embed.reddit.com is the current host (www.redditmedia.com now 301s here).
return `https://embed.reddit.com/r/${m[1]}/comments/${m[2]}/?ref_source=embed&ref=share&embed=true&theme=dark`; return `https://embed.reddit.com/r/${m[1]}/comments/${m[2]}/${REDDIT_EMBED_QS}`;
} catch { } catch {
return null; return null;
} }