Skip to content

feat: add YouTube episode embeds, mini-player, and synchronized player controls - #2289

Open
w3cj wants to merge 6 commits into
mainfrom
feat/youtube-episode-embeds
Open

w3cj wants to merge 6 commits into
mainfrom
feat/youtube-episode-embeds

Conversation

@w3cj

@w3cj w3cj commented Oct 7, 2026

Copy link
Copy Markdown
Member
  • Youtube embeds on home page list of recent episodes
  • Youtube embeds on every page of /shows
  • Youtube embed on individual /show/ page
  • Miniplayer shows at bottom right when scrolling embed out of view
    • Navigating away from a page where video play started, keeps episode playing mini player in bottom right
  • Seek / play activity saved to local storage so you can resume an episode
  • Bottom play bar controls and stays in sync with currently playing video

@vercel

vercel Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
syntax-website Ready Ready Preview Oct 16, 2026 11:38pm UTC

Request Review

…ine handling

- Replace per-embed scroll listeners and intervals with a shared
  IntersectionObserver and a single playback ticker
- Keep the mini-player mounted (hidden) to avoid iframe reloads; on list
  pages it keeps playing until the card is played directly
- Add video/audio preference toggle (default video, audio when offline)
- Track audio and video positions separately; route audio-timeline
  timestamps (show notes, transcript, ?t=) to video only when durations match
- Throttle position saves, sync player with youtube_player via store
  subscription, type the media-chrome media swap
- Mini-player follows the bottom player height; layout fixes scoped to
  video cards; dedupe show header with a snippet
- Move store tests to src/state and add media_timeline tests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 69.48kB (0.84%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
website-client-esm 2.33MB 33.39kB (1.46%) ⬆️
website-server-esm 6.03MB 36.09kB (0.6%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: website-server-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
chunks/Icon.js 2.59kB 37.12kB 7.51% ⚠️
chunks/player.js 22.24kB 31.13kB 250.03% ⚠️
_app/immutable/assets/_layout.*.css 4.52kB 16.74kB 36.95% ⚠️
_app/immutable/assets/_layout.*.css 868 bytes 12.24kB 7.64% ⚠️
entries/pages/(site)/show/_show_number_/_slug_/_layout.svelte.js 1.43kB 11.91kB 13.69% ⚠️
entries/pages/(site)/show/_show_number_/_slug_/transcript/_page.svelte.js -222 bytes 8.09kB -2.67%
chunks/ShowCard.js 820 bytes 6.88kB 13.53% ⚠️
entries/pages/(site)/_page.svelte.js 25 bytes 5.53kB 0.45%
_app/immutable/assets/ShowCard.*.css 869 bytes 4.3kB 25.34% ⚠️
_app/immutable/assets/_page.*.css 93 bytes 3.35kB 2.86%
chunks/YoutubeEmbed.js (New) 2.22kB 2.22kB 100.0% 🚀
_app/immutable/assets/YoutubeEmbed.*.css (New) 637 bytes 637 bytes 100.0% 🚀

Files in chunks/Icon.js:

  • ./src/lib/Icon.svelte → Total Size: 36.12kB

Files in chunks/player.js:

  • ./src/utilities/youtube.ts → Total Size: 418 bytes

  • ./src/state/media_preference.ts → Total Size: 627 bytes

  • ./src/state/youtube_player.ts → Total Size: 10.94kB

  • ./src/state/player_utils.ts → Total Size: 1.09kB

  • ./src/state/media_timeline.ts → Total Size: 3.89kB

  • ./src/state/player.ts → Total Size: 11.64kB

Files in entries/pages/(site)/show/_show_number_/_slug_/_layout.svelte.js:

  • ./src/routes/(site)/show/[show_number]/[slug]/+layout.svelte → Total Size: 6.61kB

Files in entries/pages/(site)/show/_show_number_/_slug_/transcript/_page.svelte.js:

  • ./src/lib/transcript/Transcript.svelte → Total Size: 5.52kB

  • ./src/routes/(site)/show/[show_number]/[slug]/transcript/+page.svelte → Total Size: 406 bytes

Files in chunks/ShowCard.js:

  • ./src/lib/ShowCard.svelte → Total Size: 5.25kB

Files in entries/pages/(site)/_page.svelte.js:

  • ./src/routes/(site)/+page.svelte → Total Size: 904 bytes

Files in chunks/YoutubeEmbed.js:

  • ./src/lib/videos/YoutubeEmbed.svelte → Total Size: 1.53kB

App Routes Affected:

App Route Size Change Total Size Change (%)
/(site) 25 bytes 27.71kB 0.09%
/(site)/show/[show_number]/[slug] 1.43kB 19.55kB 7.92% ⚠️
/(site)/show/[show_number]/[slug]/transcript -222 bytes 9.48kB -2.29%
view changes for bundle: website-client-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
_app/immutable/entry/app.D_jO-s6v.js (New) 217.88kB 217.88kB 100.0% 🚀
_app/immutable/nodes/32.*.js -296 bytes 47.29kB -0.62%
_app/immutable/nodes/3.*.js 8.78kB 42.67kB 25.89% ⚠️
_app/immutable/chunks/Icon.*.js 2.37kB 34.88kB 7.28% ⚠️
_app/immutable/chunks/entry.*.js (New) 30.25kB 30.25kB 100.0% 🚀
_app/immutable/chunks/player.*.js 10.52kB 18.92kB 125.38% ⚠️
_app/immutable/chunks/runtime.*.js 43 bytes 17.19kB 0.25%
_app/immutable/assets/3.*.css 4.54kB 16.74kB 37.19% ⚠️
_app/immutable/assets/5.*.css 868 bytes 12.24kB 7.64% ⚠️
_app/immutable/nodes/5.*.js 1.0kB 11.94kB 9.19% ⚠️
_app/immutable/nodes/10.*.js (New) 9.15kB 9.15kB 100.0% 🚀
_app/immutable/nodes/13.*.js (New) 8.27kB 8.27kB 100.0% 🚀
_app/immutable/chunks/HairButton.*.js 5 bytes 8.21kB 0.06%
_app/immutable/chunks/ShowCard.*.js 980 bytes 7.23kB 15.67% ⚠️
_app/immutable/nodes/33.*.js (New) 5.45kB 5.45kB 100.0% 🚀
_app/immutable/nodes/11.*.js 24 bytes 5.39kB 0.45%
_app/immutable/nodes/16.B_OBGrL8.js (New) 4.89kB 4.89kB 100.0% 🚀
_app/immutable/assets/ShowCard.*.css 869 bytes 4.3kB 25.34% ⚠️
_app/immutable/chunks/events.*.js 90 bytes 3.67kB 2.51%
_app/immutable/chunks/props.BnrWHa_x.js (New) 3.25kB 3.25kB 100.0% 🚀
_app/immutable/assets/11.*.css (New) 3.24kB 3.24kB 100.0% 🚀
_app/immutable/nodes/25._YFPUvOf.js (New) 3.01kB 3.01kB 100.0% 🚀
_app/immutable/chunks/style.VR_AMOuW.js (New) 2.48kB 2.48kB 100.0% 🚀
_app/immutable/chunks/render.*.js (New) 2.37kB 2.37kB 100.0% 🚀
_app/immutable/chunks/YoutubeEmbed.*.js (New) 2.37kB 2.37kB 100.0% 🚀
_app/immutable/chunks/30.*.js 5 bytes 2.32kB 0.22%
_app/immutable/nodes/42.C6tpHP_u.js (New) 2.21kB 2.21kB 100.0% 🚀
_app/immutable/nodes/40.*.js -1.2kB 1.94kB -38.3%
_app/immutable/chunks/HostSocialLink.*.js 5 bytes 1.68kB 0.3%
_app/immutable/chunks/size.CkUh_S70.js (New) 1.64kB 1.64kB 100.0% 🚀
_app/immutable/nodes/28.*.js (New) 1.48kB 1.48kB 100.0% 🚀
_app/immutable/nodes/45.*.js (New) 1.37kB 1.37kB 100.0% 🚀
_app/immutable/chunks/if.*.js (New) 985 bytes 985 bytes 100.0% 🚀
_app/immutable/chunks/this.*.js (New) 680 bytes 680 bytes 100.0% 🚀
_app/immutable/chunks/AdminActions.*.js (New) 678 bytes 678 bytes 100.0% 🚀
_app/immutable/assets/YoutubeEmbed.*.css (New) 659 bytes 659 bytes 100.0% 🚀
_app/immutable/nodes/38.BBfx0_HL.js (New) 476 bytes 476 bytes 100.0% 🚀
_app/immutable/chunks/style.*.js (Deleted) -2.48kB 0 bytes -100.0% 🗑️
_app/immutable/entry/app.*.js (Deleted) -217.88kB 0 bytes -100.0% 🗑️
_app/immutable/chunks/entry._jlTdCpW.js (Deleted) -30.22kB 0 bytes -100.0% 🗑️
_app/immutable/nodes/10.CG1VJ4v_.js (Deleted) -9.15kB 0 bytes -100.0% 🗑️
_app/immutable/nodes/13.BKslsVN_.js (Deleted) -8.27kB 0 bytes -100.0% 🗑️
_app/immutable/nodes/33.ChI_Od9q.js (Deleted) -5.45kB 0 bytes -100.0% 🗑️
_app/immutable/nodes/16.*.js (Deleted) -4.89kB 0 bytes -100.0% 🗑️
_app/immutable/chunks/props.*.js (Deleted) -3.25kB 0 bytes -100.0% 🗑️
_app/immutable/assets/11.C_xYLnZG.css (Deleted) -3.15kB 0 bytes -100.0% 🗑️
_app/immutable/nodes/25.*.js (Deleted) -3.01kB 0 bytes -100.0% 🗑️
_app/immutable/chunks/render._rL2vgCR.js (Deleted) -2.37kB 0 bytes -100.0% 🗑️
_app/immutable/nodes/42.B_Zqqi2s.js (Deleted) -2.21kB 0 bytes -100.0% 🗑️
_app/immutable/nodes/28.BH85T_g6.js (Deleted) -1.48kB 0 bytes -100.0% 🗑️
_app/immutable/nodes/45.BHg_nolH.js (Deleted) -1.37kB 0 bytes -100.0% 🗑️
_app/immutable/chunks/if.CgY06X_h.js (Deleted) -985 bytes 0 bytes -100.0% 🗑️
_app/immutable/chunks/this.VS0MA_Aa.js (Deleted) -680 bytes 0 bytes -100.0% 🗑️
_app/immutable/chunks/AdminActions.EDJ_cqfJ.js (Deleted) -678 bytes 0 bytes -100.0% 🗑️
_app/immutable/nodes/38.*.js (Deleted) -476 bytes 0 bytes -100.0% 🗑️

Files in _app/immutable/nodes/32.*.js:

  • ./src/lib/transcript/Transcript.svelte → Total Size: 7.27kB

  • ./src/routes/(site)/show/[show_number]/[slug]/transcript/+page.svelte → Total Size: 823 bytes

Files in _app/immutable/nodes/3.*.js:

  • ./src/lib/videos/video_actions.ts → Total Size: 678 bytes

  • ./src/lib/player/Player.svelte → Total Size: 13.6kB

  • ./src/routes/(site)/+layout.svelte → Total Size: 2.81kB

  • ./src/lib/videos/YoutubeVideo.svelte → Total Size: 2.26kB

  • ./src/lib/videos/GlobalYoutubePlayer.svelte → Total Size: 8.64kB

Files in _app/immutable/chunks/Icon.*.js:

  • ./src/lib/Icon.svelte → Total Size: 42.72kB

Files in _app/immutable/chunks/player.*.js:

  • ./src/state/media_timeline.ts → Total Size: 3.89kB

  • ./src/utilities/youtube.ts → Total Size: 418 bytes

  • ./src/state/player.ts → Total Size: 11.62kB

  • ./src/state/youtube_player.ts → Total Size: 10.94kB

  • ./src/state/player_utils.ts → Total Size: 1.09kB

  • ./src/state/media_preference.ts → Total Size: 627 bytes

Files in _app/immutable/nodes/5.*.js:

  • ./src/routes/(site)/show/[show_number]/[slug]/+layout.svelte → Total Size: 11.33kB

Files in _app/immutable/chunks/ShowCard.*.js:

  • ./src/lib/ShowCard.svelte → Total Size: 9.57kB

Files in _app/immutable/nodes/11.*.js:

  • ./src/routes/(site)/+page.svelte → Total Size: 1.1kB

Files in _app/immutable/chunks/YoutubeEmbed.*.js:

  • ./src/lib/videos/YoutubeEmbed.svelte → Total Size: 3.45kB

App Routes Affected:

App Route Size Change Total Size Change (%)
/(site) 8.8kB 48.06kB 22.41% ⚠️
/(site)/login -5 bytes 3.01kB -0.17%
/(site)/show/[show_number]/[slug] 1.0kB 15.76kB 6.81% ⚠️
/(site)/system/components -1.2kB 1.94kB -38.3%
/(site)/show/[show_number]/[slug]/transcript -296 bytes 47.29kB -0.62%

- snake_case renames in Transcript (incl. ai_show_note prop), ShowCard,
  and show layout
- Remove unused vars/catch bindings
- Make show page JSON-LD schema $derived so it updates when navigating
  between episodes, and fix the parse error from the inline template

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@wesbos

wesbos commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

On mobile, playing a video and then scrolling stops the youtube video from playing and then re-embeds it without resuming the play.

@wesbos

wesbos commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

On mobile, the overlaid video is too large. Really we should be using the PIP APIs here. Can we do that with a youtube video?

IMG_2283 IMG_2282

@wesbos

wesbos commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator
Screenshot 2026-10-13 at 3 38 08 PM

Can we get rid of some of the UI on the mini player embed? Its too much for such a small player

@wesbos

wesbos commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

Should the mini player not go here? ITs confusing having two things fixed

Screenshot 2026-10-13 at 3 39 32 PM

@w3cj

w3cj commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

Should the mini player not go here? ITs confusing having two things fixed
Screenshot 2026-10-13 at 3 39 32 PM

Yeah I'll make it look more like Spotify mobile.

Screenshot_20261013-134542

Replace the separate mini-player with a single global <youtube-video> that is
positioned over the episode's embed or docked in the player bar, so moving
between them never reloads the iframe.

- Mobile (<= 809px) player bar: video beside the play/seek buttons, seek bar
  with rate button, then volume and combined timestamp
- Docked video: click to play/pause, buttons to watch on the episode page and
  go full screen; show page embed gets dock and full screen buttons
- Record video durations from embed previews so timestamps can still tell
  whether audio and video timelines match
- Stop a switched video from staying in a "switching" state forever, and only
  mark a video loaded once it's actually loading
- Coalesce IntersectionObserver rebuilds when the bar changes height
- Add --stacked-video-bar custom media, aria-hide duplicate controls

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
w3cj and others added 2 commits October 16, 2026 17:35
- 120px video to the left of the controls, play/seek buttons left of the
  seek bar, timestamp right under it, half-width volume aligned with the
  seek bar
- Episode page and full screen buttons centered under the play buttons on
  mobile instead of over the small video, sharing code via video_actions.ts
- New undock icon for "watch on episode page", distinct from share
- Title back at the top of the bar on mobile, ellipsized before the
  action bar buttons

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@w3cj

w3cj commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

Styles and scroll behavior updated. Let me know what you think.

This branch was successfully deployed

1 active deployment
Preview — 05c3e831 Deployed Oct 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants