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:
@@ -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', () => {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user