diff --git a/mise.toml b/mise.toml new file mode 100644 index 000000000..6a0493c69 --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +node = "22" diff --git a/src/lib/Icon.svelte b/src/lib/Icon.svelte index fc65f8af2..7eb3f6765 100644 --- a/src/lib/Icon.svelte +++ b/src/lib/Icon.svelte @@ -30,7 +30,11 @@ | 'instagram' | 'threads' | 'thumbtack' - | 'youtube'; + | 'youtube' + | 'headphones' + | 'video' + | 'fullscreen' + | 'undock'; -
+ + +
{/if} - {show.number} + {#if !has_youtube} + {show.number} + {/if}

@@ -143,6 +165,15 @@

+ + {#if has_youtube} +
+ #{show.number} + +
+ {/if}
diff --git a/src/lib/videos/YoutubeEmbed.svelte b/src/lib/videos/YoutubeEmbed.svelte new file mode 100644 index 000000000..1614a1e75 --- /dev/null +++ b/src/lib/videos/YoutubeEmbed.svelte @@ -0,0 +1,136 @@ + + +{#if watch_url} + + + +
+ + + +
+{/if} + + diff --git a/src/lib/videos/YoutubeVideo.svelte b/src/lib/videos/YoutubeVideo.svelte new file mode 100644 index 000000000..fa42b02a0 --- /dev/null +++ b/src/lib/videos/YoutubeVideo.svelte @@ -0,0 +1,78 @@ + + + + + diff --git a/src/lib/videos/video_actions.ts b/src/lib/videos/video_actions.ts new file mode 100644 index 000000000..d17269f4f --- /dev/null +++ b/src/lib/videos/video_actions.ts @@ -0,0 +1,37 @@ +import { tick } from 'svelte'; +import { get } from 'svelte/store'; +import { goto } from '$app/navigation'; +import { youtube_player, type YoutubeVideoElementLike } from '$state/youtube_player'; +import get_show_path from '$utilities/slug'; + +// Actions on the global YouTube video, shared by its own overlay buttons and the player bar's + +// The show page's embed can register a little after navigation finishes +const SLOT_RETRY_MS = 100; +const SLOT_RETRIES = 20; + +/** + * Moves the video out of the bar and onto the episode's embed at the top of its show page + */ +export async function open_show_page() { + const show = get(youtube_player).active_show; + if (!show) return; + const path = get_show_path(show); + if (location.pathname !== path) await goto(path); + await tick(); + for (let attempt = 0; attempt < SLOT_RETRIES; attempt++) { + if (await youtube_player.play_on_show_page(show)) return; + await new Promise((resolve) => setTimeout(resolve, SLOT_RETRY_MS)); + } + // No embed on the page, the video keeps playing in the bar +} + +export function enter_fullscreen() { + const el = get(youtube_player).active_element as + | (YoutubeVideoElementLike & { webkitRequestFullscreen?: () => void }) + | null; + if (!el) return; + // Safari on iPad only has the prefixed version. iPhone can't full screen anything but