Prompt to start blocked synced YouTube playback

This commit is contained in:
codex
2026-06-10 20:33:59 +02:00
parent a0810e1147
commit 2f002c304e
3 changed files with 60 additions and 0 deletions
+40
View File
@@ -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");
+8
View File
@@ -21,6 +21,14 @@
<div class="watch-main">
<div class="youtube-shell" id="youtube-shell">
<div id="youtube-player"></div>
<button
id="youtube-start-button"
class="youtube-start-button"
type="button"
hidden
>
Start synced playback
</button>
</div>
</div>
<aside class="playlist-panel">
+12
View File
@@ -199,6 +199,7 @@ button[aria-pressed="false"] {
}
.youtube-shell {
position: relative;
display: none;
overflow: hidden;
min-height: 0;
@@ -217,6 +218,17 @@ button[aria-pressed="false"] {
height: 100%;
}
.youtube-start-button {
position: absolute;
left: 50%;
bottom: 18px;
z-index: 2;
width: auto;
min-width: 180px;
transform: translateX(-50%);
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.38);
}
.watch-resize-handle {
position: relative;
min-width: 0;