feat(embeds): fullscreen, wider cards, Instagram/Tidal/Reddit; fix TikTok/X/Twitch
CI / Build & Quality Checks (push) Successful in 10m35s
CI / Trigger Desktop Build (push) Successful in 8s

Feedback fixes + new platforms:
- Fullscreen: add a universal 'Fullscreen' button on video embeds (requests
  fullscreen on the media container) so Shorts/TikTok/etc. can go fullscreen
  regardless of each player's own controls. Portrait media enlarged (220->300).
- Drop the iframe sandbox (CSP-allowlisted trusted hosts; sandbox was breaking
  player features and likely TikTok).
- Wider, responsive embed/tweet cards (min(34rem,92vw)) so Twitch player chrome
  isn't cramped and X posts stop getting clipped.
- Instagram (p/reel/tv), Tidal (track/album/playlist/video), and Reddit posts
  now embed. Reddit uses redditmedia.com to bypass the homeserver's blocked
  preview (Reddit serves it a bot-check 'please wait for verification' page);
  a bot-wall title filter keeps that garbage out of any caption.

New pure parsers unit-tested (videoEmbed.test.ts, 17 cases). Desktop + live web
CSP frame-src updated for instagram.com, embed.tidal.com, redditmedia.com.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 20:55:47 -04:00
parent 791b1cb5ea
commit fbaa921f83
4 changed files with 185 additions and 27 deletions
+36
View File
@@ -13,6 +13,9 @@ import {
isSoundCloudTrack,
getAppleMusicEmbed,
getTweetId,
getTidalEmbed,
getInstagramEmbed,
getRedditPostEmbed,
buildVideoEmbedUrl,
spotifyEmbedHeight,
parseMediaEmbed,
@@ -136,6 +139,39 @@ test('parseMediaEmbed: Apple Music → audio', () => {
assert.equal(m?.height, 175);
});
test('Tidal: track (audio) vs video (landscape)', () => {
assert.deepEqual(getTidalEmbed('https://tidal.com/browse/track/12345'), {
kind: 'audio',
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://tidal.com/video/555')?.kind, 'landscape');
assert.equal(getTidalEmbed('https://tidal.com/browse'), null);
});
test('Instagram: p / reel / tv → embed path', () => {
assert.equal(getInstagramEmbed('https://www.instagram.com/p/AbC123_-/'), 'https://www.instagram.com/p/AbC123_-/embed/');
assert.equal(getInstagramEmbed('https://instagram.com/reel/XyZ/'), 'https://www.instagram.com/reel/XyZ/embed/');
assert.equal(getInstagramEmbed('https://www.instagram.com/reels/XyZ/'), 'https://www.instagram.com/reel/XyZ/embed/');
assert.equal(getInstagramEmbed('https://www.instagram.com/someuser/'), null);
});
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',
);
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://www.reddit.com/r/aww/'), null); // subreddit, not a post
});
test('parseMediaEmbed: Instagram/Reddit → rich, Tidal → audio', () => {
assert.equal(parseMediaEmbed('https://www.instagram.com/p/abc/', 'h')?.kind, 'rich');
assert.equal(parseMediaEmbed('https://www.reddit.com/r/x/comments/y/z/', 'h')?.provider, 'reddit');
assert.equal(parseMediaEmbed('https://tidal.com/browse/track/1', 'h')?.provider, 'tidal');
});
test('parseMediaEmbed: Twitch embed carries the parent host', () => {
const chan = parseMediaEmbed('https://twitch.tv/streamer', HOST);
assert.equal(chan?.provider, 'twitch');