diff --git a/public/app.js b/public/app.js index 10425c7..3558e6f 100644 --- a/public/app.js +++ b/public/app.js @@ -13,6 +13,7 @@ const statusText = document.querySelector("#status"); const youtubeForm = document.querySelector("#youtube-form"); const youtubeInput = document.querySelector("#youtube-input"); const youtubeShell = document.querySelector("#youtube-shell"); +const youtubeStartButton = document.querySelector("#youtube-start-button"); const watchPanel = document.querySelector(".watch-panel"); const watchResizeHandle = document.querySelector("#watch-resize-handle"); const watchCollapseButton = document.querySelector("#watch-collapse-button"); @@ -376,9 +377,14 @@ function loadYoutubeVideo(player, videoId, position) { }); } +function setYoutubeStartPromptVisible(visible) { + youtubeStartButton.hidden = !visible; +} + function requestYoutubePlayback(player, videoId, position) { const requestId = ++youtubePlaybackRequestId; const startedAt = Date.now(); + setYoutubeStartPromptVisible(false); for (const delay of [0, 150, 750, 1500, 3000]) { setTimeout(() => { @@ -408,6 +414,17 @@ function requestYoutubePlayback(player, videoId, position) { player.playVideo(); }, delay); } + + setTimeout(() => { + if ( + requestId === youtubePlaybackRequestId && + desiredYoutubePlaying && + currentYoutubeVideoId === videoId && + player.getPlayerState?.() !== YT.PlayerState.PLAYING + ) { + setYoutubeStartPromptVisible(true); + } + }, 3300); } async function sendWatchState({ @@ -462,6 +479,9 @@ function handleYoutubeStateChange(event) { requestYoutubePlayback(youtubePlayer, currentYoutubeVideoId, currentYoutubeSnapshot().position); return; } + if (event.data === YT.PlayerState.PLAYING) { + setYoutubeStartPromptVisible(false); + } if (![YT.PlayerState.PLAYING, YT.PlayerState.PAUSED, YT.PlayerState.ENDED].includes(event.data)) { return; @@ -480,6 +500,9 @@ function handleYoutubeStateChange(event) { desiredYoutubePlaying = action === "play"; if (desiredYoutubePlaying) { syncedPlaybackRetryUntil = 0; + setYoutubeStartPromptVisible(false); + } else { + setYoutubeStartPromptVisible(false); } const state = currentWatchState(action === "play"); if (state) { @@ -517,6 +540,7 @@ async function applyWatchState(state, { suppressEvents = true } = {}) { desiredYoutubePlaying = false; youtubePlaybackRequestId++; syncedPlaybackRetryUntil = 0; + setYoutubeStartPromptVisible(false); youtubePlayer?.stopVideo?.(); youtubeShell.classList.remove("is-active"); setWatchCollapsed(true); @@ -548,6 +572,7 @@ async function applyWatchState(state, { suppressEvents = true } = {}) { } else { youtubePlaybackRequestId++; syncedPlaybackRetryUntil = 0; + setYoutubeStartPromptVisible(false); pauseEnforcementUntil = Math.max(pauseEnforcementUntil, Date.now() + 3000); } @@ -1119,6 +1144,21 @@ announcementForm.addEventListener("submit", (event) => { }); }); +youtubeStartButton.addEventListener("click", () => { + if (!youtubePlayer || !currentYoutubeVideoId) return; + + const position = currentYoutubeSnapshot().position; + if (youtubePlayer.getVideoData?.().video_id !== currentYoutubeVideoId) { + loadYoutubeVideo(youtubePlayer, currentYoutubeVideoId, position); + } else { + youtubePlayer.seekTo?.(position, true); + } + youtubePlayer.unMute?.(); + youtubePlayer.playVideo?.(); + requestYoutubePlayback(youtubePlayer, currentYoutubeVideoId, position); + setYoutubeStartPromptVisible(false); +}); + cameraButton.addEventListener("click", () => { const enabled = cameraButton.getAttribute("aria-pressed") !== "true"; updateToggleButton(cameraButton, enabled, "Turn camera off", "Turn camera on"); diff --git a/public/index.html b/public/index.html index 06c6cfc..603e28c 100644 --- a/public/index.html +++ b/public/index.html @@ -21,6 +21,14 @@
+