feat(embeds): apply review findings + fix TikTok portrait padding

From the review-agent audit:
- Dailymotion: move off the Sept-2024-deprecated /embed/video path to
  geo.dailymotion.com/player.html.
- Reddit: point at embed.reddit.com (www.redditmedia.com now 301s there).
- Vimeo: parse the unlisted hash (vimeo.com/{id}/{hash}) and pass &h=…, add dnt=1.
- Tidal: layout=gridify + ~275px height for albums/playlists (fixes narrow player).
- YouTube/Shorts: playsinline=1 (iOS keeps playback inline); parse /live/ +
  music.youtube.com.
- Apple Music: /music-video/ renders 16:9 instead of a fixed audio height.
- Re-add a minimal sandbox to all media iframes (omits allow-top-navigation →
  blocks phishing redirects) — defense-in-depth atop the CSP frame-src allowlist.
- Self-resize Instagram + Reddit post embeds via a shared useIframeAutoHeight hook
  (also now covers the Tweet embed; matches platform.x.com origin too); drop the
  fixed 720/480 heights. Cap tweet/post columns at ~550px, centered.

Also from user feedback: TikTok portrait player dropped music_info/description,
which forced TikTok's wide 'video + info panel' layout and left empty space
beside the video — now a clean 9:16 player that fills the box.

Tests 726 pass. CSP frame-src gains embed.reddit.com (separate desktop commit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 23:56:47 -04:00
co-authored by Claude Opus 4.8
parent b247a0447c
commit 4de2d233ef
4 changed files with 225 additions and 97 deletions
+23 -7
View File
@@ -5,6 +5,7 @@ import {
getYoutubeShortsId,
isYouTubeShorts,
getVimeoVideoId,
getVimeoParts,
getTikTokVideoId,
isTikTokLink,
tiktokIdFromOembed,
@@ -31,14 +32,21 @@ test('YouTube: watch / youtu.be / embed / shorts', () => {
assert.equal(getYouTubeVideoId('https://youtu.be/dQw4w9WgXcQ?t=42'), 'dQw4w9WgXcQ');
assert.equal(getYouTubeVideoId('https://www.youtube.com/embed/dQw4w9WgXcQ'), 'dQw4w9WgXcQ');
assert.equal(getYouTubeVideoId('https://youtube.com/shorts/abc123DEF_-'), 'abc123DEF_-');
assert.equal(getYouTubeVideoId('https://www.youtube.com/live/abcLIVE123'), 'abcLIVE123');
assert.equal(getYouTubeVideoId('https://music.youtube.com/watch?v=musicId12'), 'musicId12');
assert.equal(getYouTubeVideoId('https://vimeo.com/123'), null);
assert.equal(isYouTubeShorts('https://www.youtube.com/shorts/abc123'), true);
assert.equal(getYoutubeShortsId('https://youtube.com/shorts/abc123'), 'abc123');
});
test('Vimeo', () => {
test('Vimeo (incl. unlisted hash)', () => {
assert.equal(getVimeoVideoId('https://vimeo.com/123456789'), '123456789');
assert.equal(getVimeoVideoId('https://vimeo.com/channels/staffpicks'), null);
assert.deepEqual(getVimeoParts('https://vimeo.com/123456789/abc123'), {
id: '123456789',
hash: 'abc123',
});
assert.ok(parseMediaEmbed('https://vimeo.com/123456789/abc123', 'h')?.embedUrl.includes('h=abc123'));
});
test('TikTok: canonical /video/<id> only', () => {
@@ -111,16 +119,23 @@ test('SoundCloud track detection', () => {
test('buildVideoEmbedUrl: cookie-less YouTube + Vimeo', () => {
assert.equal(
buildVideoEmbedUrl('youtube', 'dQw4w9WgXcQ'),
'https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ?autoplay=1&rel=0',
'https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ?autoplay=1&rel=0&playsinline=1',
);
assert.equal(
buildVideoEmbedUrl('vimeo', '42'),
'https://player.vimeo.com/video/42?autoplay=1&dnt=1',
);
assert.equal(
buildVideoEmbedUrl('vimeo', '42', 'h4sh'),
'https://player.vimeo.com/video/42?autoplay=1&dnt=1&h=h4sh',
);
assert.equal(buildVideoEmbedUrl('vimeo', '42'), 'https://player.vimeo.com/video/42?autoplay=1');
});
test('parseMediaEmbed: routes provider + kind, builds embed URLs', () => {
assert.deepEqual(parseMediaEmbed('https://youtube.com/shorts/abc', HOST), {
provider: 'youtube',
kind: 'portrait',
embedUrl: 'https://www.youtube-nocookie.com/embed/abc?autoplay=1&rel=0',
embedUrl: 'https://www.youtube-nocookie.com/embed/abc?autoplay=1&rel=0&playsinline=1',
});
assert.equal(parseMediaEmbed('https://www.youtube.com/watch?v=xyz', HOST)?.kind, 'landscape');
assert.equal(parseMediaEmbed('https://streamable.com/abc', HOST)?.provider, 'streamable');
@@ -162,7 +177,8 @@ test('Tidal: track (audio) vs video (landscape)', () => {
embedUrl: 'https://embed.tidal.com/tracks/12345',
height: 120,
});
assert.equal(getTidalEmbed('https://listen.tidal.com/album/999')?.embedUrl, 'https://embed.tidal.com/albums/999');
assert.equal(getTidalEmbed('https://listen.tidal.com/album/999')?.embedUrl, 'https://embed.tidal.com/albums/999?layout=gridify');
assert.equal(getTidalEmbed('https://listen.tidal.com/album/999')?.height, 275);
assert.equal(getTidalEmbed('https://tidal.com/video/555')?.kind, 'landscape');
assert.equal(getTidalEmbed('https://tidal.com/browse'), null);
});
@@ -177,9 +193,9 @@ test('Instagram: p / reel / tv → embed path', () => {
test('Reddit post embed → redditmedia', () => {
assert.equal(
getRedditPostEmbed('https://www.reddit.com/r/aww/comments/abc123/cute_cat/'),
'https://www.redditmedia.com/r/aww/comments/abc123/?ref_source=embed&ref=share&embed=true&theme=dark',
'https://embed.reddit.com/r/aww/comments/abc123/?ref_source=embed&ref=share&embed=true&theme=dark',
);
assert.equal(getRedditPostEmbed('https://old.reddit.com/r/aww/comments/xyz/'), 'https://www.redditmedia.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
});