fix stuff + add stuff

This commit is contained in:
ashley 2025-10-06 16:01:17 +02:00
parent 43b660e3ca
commit 82a2afcece

View File

@ -3,8 +3,7 @@ var _yt_player = videojs;
var versionclient = "youtube.player.web_20250917_22_RC00" var versionclient = "youtube.player.web_20250917_22_RC00"
document.addEventListener("DOMContentLoaded", () => {
document.addEventListener("DOMContentLoaded", () => {
// video.js 8 init - source can be seen in https://poketube.fun/static/vjs.min.js or the vjs.min.js file // video.js 8 init - source can be seen in https://poketube.fun/static/vjs.min.js or the vjs.min.js file
const video = videojs('video', { const video = videojs('video', {
controls: true, controls: true,
@ -25,7 +24,7 @@ document.addEventListener("DOMContentLoaded", () => {
const audioEl = document.getElementById('aud'); const audioEl = document.getElementById('aud');
let volGuard = false; let volGuard = false;
// FIX: inline playback hint for iOS/Safari // FIX: ensure inline playback hint for iOS/Safari
try { videoEl.setAttribute('playsinline', ''); videoEl.setAttribute('webkit-playsinline', ''); } catch {} try { videoEl.setAttribute('playsinline', ''); videoEl.setAttribute('webkit-playsinline', ''); } catch {}
// global anti-ping-pong guard // global anti-ping-pong guard
@ -55,10 +54,13 @@ document.addEventListener("DOMContentLoaded", () => {
let seekingInProgress = false; let seekingInProgress = false;
let resumeAfterSeek = false; let resumeAfterSeek = false;
// FIX: settle window after seek to ignore noisy events // NEW FIX: grace window to silence arbiter + bridge immediately after seeks / restarts
let seekSettleUntil = 0; let suppressBridgeUntil = 0;
const SEEK_SETTLE_MS = 500; const nowPerf = () => performance?.now?.() || Date.now();
const inSeekSettle = () => performance.now() < seekSettleUntil; const bridgingSilenced = () => nowPerf() < suppressBridgeUntil;
function silenceBridging(ms = 900) { // tuned: long enough for decoders to settle after a seek
suppressBridgeUntil = nowPerf() + ms;
}
// FIX: state arbiter watchdog (forces both to share same paused/playing state) // FIX: state arbiter watchdog (forces both to share same paused/playing state)
let arbiterTimer = null; let arbiterTimer = null;
@ -66,7 +68,7 @@ document.addEventListener("DOMContentLoaded", () => {
function startArbiter() { function startArbiter() {
if (arbiterTimer) clearInterval(arbiterTimer); if (arbiterTimer) clearInterval(arbiterTimer);
arbiterTimer = setInterval(() => { arbiterTimer = setInterval(() => {
if (syncing || restarting || seekingInProgress || inSeekSettle()) return; if (syncing || restarting || seekingInProgress || bridgingSilenced()) return;
// treat "playing" strictly; ended counts as paused // treat "playing" strictly; ended counts as paused
const vPlaying = !video.paused() && !video.ended(); const vPlaying = !video.paused() && !video.ended();
@ -210,13 +212,16 @@ document.addEventListener("DOMContentLoaded", () => {
// FIX: unified play/pause coordinators (no ping-pong) // FIX: unified play/pause coordinators (no ping-pong)
async function playTogether({ allowMutedRetry = true } = {}) { async function playTogether({ allowMutedRetry = true } = {}) {
if (syncing || restarting || seekingInProgress || inSeekSettle()) return; // FIX: don't start while seeking/settling if (syncing || restarting || seekingInProgress) return; // FIX: don't start while seeking
syncing = true; syncing = true;
try { try {
// align clocks first // line up clocks first
const t = Number(video.currentTime()); const t = Number(video.currentTime());
if (isFinite(t) && Math.abs(Number(audio.currentTime) - t) > 0.05) safeSetCT(audio, t); if (isFinite(t) && Math.abs(Number(audio.currentTime) - t) > 0.05) safeSetCT(audio, t);
// Silence arbiter/bridging briefly while we spin both up in tandem
silenceBridging(800);
// first attempt: keep existing mute states // first attempt: keep existing mute states
let vOk = true, aOk = true; let vOk = true, aOk = true;
try { const p = video.play(); if (p && p.then) await p; } catch { vOk = false; } try { const p = video.play(); if (p && p.then) await p; } catch { vOk = false; }
@ -258,6 +263,7 @@ document.addEventListener("DOMContentLoaded", () => {
const t = Number(video.currentTime()); const t = Number(video.currentTime());
if (isFinite(t) && Math.abs(Number(audio.currentTime) - t) > 0.1) safeSetCT(audio, t); if (isFinite(t) && Math.abs(Number(audio.currentTime) - t) > 0.1) safeSetCT(audio, t);
if (bothPlayableAt(t)) { if (bothPlayableAt(t)) {
silenceBridging(700); // NEW: brief grace on very first start
playTogether({ allowMutedRetry: true }); playTogether({ allowMutedRetry: true });
} else { } else {
pauseTogether(); pauseTogether();
@ -372,31 +378,31 @@ document.addEventListener("DOMContentLoaded", () => {
video.on('ratechange', () => { try { audio.playbackRate = video.playbackRate(); } catch {} }); video.on('ratechange', () => { try { audio.playbackRate = video.playbackRate(); } catch {} });
// FIX: sync-safe event bridging using the coordinators (no ping-pong) // sync-safe event bridging using the coordinators (no ping-pong)
video.on('play', () => { video.on('play', () => {
if (syncing || restarting || seekingInProgress || inSeekSettle()) return; // FIX if (seekingInProgress || bridgingSilenced()) return; // FIX
vIsPlaying = true; vIsPlaying = true;
if (!aIsPlaying) playTogether({ allowMutedRetry: true }); if (!aIsPlaying) playTogether({ allowMutedRetry: true });
}); });
audio.addEventListener('play', () => { audio.addEventListener('play', () => {
if (syncing || restarting || seekingInProgress || inSeekSettle()) return; // FIX if (seekingInProgress || bridgingSilenced()) return; // FIX
aIsPlaying = true; aIsPlaying = true;
if (!vIsPlaying) playTogether({ allowMutedRetry: true }); if (!vIsPlaying) playTogether({ allowMutedRetry: true });
}); });
video.on('pause', () => { video.on('pause', () => {
if (syncing || restarting || seekingInProgress || inSeekSettle()) return; // FIX if (restarting || seekingInProgress || bridgingSilenced()) return; // FIX
vIsPlaying = false; vIsPlaying = false;
pauseTogether(); pauseTogether();
}); });
audio.addEventListener('pause', () => { audio.addEventListener('pause', () => {
if (syncing || restarting || seekingInProgress || inSeekSettle()) return; // FIX if (restarting || seekingInProgress || bridgingSilenced()) return; // FIX
aIsPlaying = false; aIsPlaying = false;
pauseTogether(); pauseTogether();
}); });
video.on('waiting', () => { video.on('waiting', () => {
if (syncing || restarting || seekingInProgress || inSeekSettle()) return; // FIX if (restarting || seekingInProgress || bridgingSilenced()) return; // FIX
vIsPlaying = false; vIsPlaying = false;
try { audio.pause(); } catch{}; try { audio.pause(); } catch{};
clearSyncLoop(); clearSyncLoop();
@ -435,40 +441,20 @@ document.addEventListener("DOMContentLoaded", () => {
// suppress spurious 'ended' right after seeks (mobile/browser quirk guard) // suppress spurious 'ended' right after seeks (mobile/browser quirk guard)
let wasPlayingBeforeSeek = false; let wasPlayingBeforeSeek = false;
// FIX: track *audio* seeks too // NEW: also track audio seeking to keep state tight
audio.addEventListener('seeking', () => { audio.addEventListener('seeking', () => { markANotPlaying(); });
if (restarting) return; audio.addEventListener('seeked', () => { /* noop; video 'seeked' handles alignment */ });
seekingInProgress = true;
seekSettleUntil = performance.now() + SEEK_SETTLE_MS;
try { video.pause(); } catch {}
try { audio.pause(); } catch {}
clearSyncLoop();
aIsPlaying = false; vIsPlaying = false;
});
audio.addEventListener('seeked', async () => {
if (restarting) return;
seekSettleUntil = performance.now() + SEEK_SETTLE_MS;
const vt = Number(video.currentTime());
if (Math.abs(vt - Number(audio.currentTime)) > 0.05) safeSetCT(audio, vt);
// only resume if we were playing before the seek gesture;
// resumeAfterSeek is keyed off the video 'seeking' handler below.
if (resumeAfterSeek) {
await waitUntilPlayable(vt, 1000);
playTogether({ allowMutedRetry: false });
} else {
pauseTogether();
}
seekingInProgress = false;
});
video.on('seeking', () => { video.on('seeking', () => {
if (restarting) return; if (restarting) return;
seekingInProgress = true; // FIX seekingInProgress = true; // FIX
seekSettleUntil = performance.now() + SEEK_SETTLE_MS; // FIX
wasPlayingBeforeSeek = !video.paused(); wasPlayingBeforeSeek = !video.paused();
resumeAfterSeek = wasPlayingBeforeSeek; // FIX resumeAfterSeek = wasPlayingBeforeSeek; // FIX
try { video.pause(); } catch {} // FIX: pause both while scrubbing
try { audio.pause(); } catch {} // FIX // Silence arbiter/bridging *immediately* as the seek begins
silenceBridging(1200);
try { audio.pause(); } catch {}
clearSyncLoop(); clearSyncLoop();
const vt = Number(video.currentTime()); const vt = Number(video.currentTime());
if (Math.abs(vt - Number(audio.currentTime)) > 0.1) safeSetCT(audio, vt); if (Math.abs(vt - Number(audio.currentTime)) > 0.1) safeSetCT(audio, vt);
@ -477,14 +463,15 @@ document.addEventListener("DOMContentLoaded", () => {
video.on('seeked', async () => { video.on('seeked', async () => {
if (restarting) return; if (restarting) return;
seekSettleUntil = performance.now() + SEEK_SETTLE_MS; // FIX
const vt = Number(video.currentTime()); const vt = Number(video.currentTime());
if (Math.abs(vt - Number(audio.currentTime)) > 0.05) safeSetCT(audio, vt); if (Math.abs(vt - Number(audio.currentTime)) > 0.05) safeSetCT(audio, vt);
// FIX: only resume once the new point is playable; avoid first-load ping-pong // FIX: only resume once the new point is playable; avoid first-load ping-pong
if (resumeAfterSeek) { if (resumeAfterSeek) {
await waitUntilPlayable(vt, 1000); // keep silenced while we wait, then a touch more while starting
playTogether({ allowMutedRetry: false }); // user was already playing silenceBridging(1100);
await waitUntilPlayable(vt, 1200);
playTogether({ allowMutedRetry: false });
} else { } else {
pauseTogether(); pauseTogether();
} }
@ -494,12 +481,12 @@ document.addEventListener("DOMContentLoaded", () => {
}); });
video.on('canplaythrough', () => { video.on('canplaythrough', () => {
if (restarting || seekingInProgress || inSeekSettle()) return; // FIX if (restarting || seekingInProgress) return; // FIX
const vt = Number(video.currentTime()); const vt = Number(video.currentTime());
if (Math.abs(vt - Number(audio.currentTime)) > 0.1) safeSetCT(audio, vt); if (Math.abs(vt - Number(audio.currentTime)) > 0.1) safeSetCT(audio, vt);
}); });
audio.addEventListener('canplaythrough', () => { audio.addEventListener('canplaythrough', () => {
if (restarting || seekingInProgress || inSeekSettle()) return; // FIX if (restarting || seekingInProgress) return; // FIX
const vt = Number(video.currentTime()); const vt = Number(video.currentTime());
if (Math.abs(vt - Number(audio.currentTime)) > 0.1) safeSetCT(audio, vt); if (Math.abs(vt - Number(audio.currentTime)) > 0.1) safeSetCT(audio, vt);
}); });
@ -514,7 +501,10 @@ document.addEventListener("DOMContentLoaded", () => {
// tiny offset so 'ended' doesn't immediately refire // tiny offset so 'ended' doesn't immediately refire
const startAt = 0.001; const startAt = 0.001;
suppressEndedUntil = performance.now() + 800; suppressEndedUntil = nowPerf() + 800;
// NEW: silence bridge while we reset to head
silenceBridging(900);
video.currentTime(startAt); video.currentTime(startAt);
safeSetCT(audio, startAt); safeSetCT(audio, startAt);
@ -528,13 +518,13 @@ document.addEventListener("DOMContentLoaded", () => {
video.on('ended', () => { video.on('ended', () => {
if (restarting) return; if (restarting) return;
if (performance.now() < suppressEndedUntil) return; if (nowPerf() < suppressEndedUntil) return;
if (desiredLoop) restartLoop(); if (desiredLoop) restartLoop();
else { pauseTogether(); } else { pauseTogether(); }
}); });
audio.addEventListener('ended', () => { audio.addEventListener('ended', () => {
if (restarting) return; if (restarting) return;
if (performance.now() < suppressEndedUntil) return; if (nowPerf() < suppressEndedUntil) return;
if (desiredLoop) restartLoop(); if (desiredLoop) restartLoop();
else { pauseTogether(); } else { pauseTogether(); }
}); });
@ -550,6 +540,7 @@ document.addEventListener("DOMContentLoaded", () => {
} }
}); });
// https://codeberg.org/ashley/poke/src/branch/main/src/libpoketube/libpoketube-youtubei-objects.json // https://codeberg.org/ashley/poke/src/branch/main/src/libpoketube/libpoketube-youtubei-objects.json