Update css/player-base.js

This commit is contained in:
ashley 2025-10-17 20:45:58 +02:00
parent 3a4737518f
commit c879b83a77

View File

@ -15,8 +15,7 @@ var versionclient = "youtube.player.web_20250917_22_RC00"
* <https://github.com/mozilla/vtt.js/blob/main/LICENSE> * <https://github.com/mozilla/vtt.js/blob/main/LICENSE>
*/ */
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,
@ -109,6 +108,13 @@ document.addEventListener("DOMContentLoaded", () => {
let userMutedVideo = false; let userMutedVideo = false;
let userMutedAudio = false; let userMutedAudio = false;
// remember if user tried to play while sources werent ready/playable
let pendingUserPlay = false;
// prevent quick “waiting” blips from pausing everything at startup
let waitingTimerVideo = null;
let waitingTimerAudio = null;
try { try {
videoEl.loop = false; videoEl.loop = false;
videoEl.removeAttribute?.('loop'); videoEl.removeAttribute?.('loop');
@ -226,6 +232,12 @@ document.addEventListener("DOMContentLoaded", () => {
} }
} catch {} } catch {}
// if video is playing but audio silently stopped, try to nudge it
try {
if (!video.paused() && audio.paused && bothPlayableAt(vt)) {
audio.play().catch(() => {});
}
} catch {}
}, SYNC_INTERVAL_MS); }, SYNC_INTERVAL_MS);
} }
@ -247,6 +259,11 @@ document.addEventListener("DOMContentLoaded", () => {
} }
} }
function isReadyForStart() {
const t = Number(video.currentTime());
return audioReady && videoReady && isFinite(t) && bothPlayableAt(t);
}
async function tryPlay(el) { async function tryPlay(el) {
try { try {
const p = el.play(); const p = el.play();
@ -259,9 +276,16 @@ document.addEventListener("DOMContentLoaded", () => {
async function playTogether({ allowMutedRetry = true } = {}) { async function playTogether({ allowMutedRetry = true } = {}) {
if (syncing || restarting) return; if (syncing || restarting) return;
const t = Number(video.currentTime());
// do not start anything until both are genuinely playable at this timestamp
if (!isReadyForStart()) {
pendingUserPlay = true;
showError('Buffering… preparing audio and video');
return;
}
syncing = true; syncing = true;
try { try {
const t = Number(video.currentTime());
if (isFinite(t) && Math.abs(Number(audio.currentTime) - t) > 0.05) { if (isFinite(t) && Math.abs(Number(audio.currentTime) - t) > 0.05) {
safeSetCT(audio, t); safeSetCT(audio, t);
} }
@ -286,7 +310,7 @@ document.addEventListener("DOMContentLoaded", () => {
showError('Video failed to start.'); showError('Video failed to start.');
setTimeout(() => { setTimeout(() => {
video.play().catch(() => showError('Video retry failed.')); video.play().catch(() => showError('Video retry failed.'));
}, 3000); }, 1500);
}); });
} catch {} } catch {}
} }
@ -297,6 +321,8 @@ document.addEventListener("DOMContentLoaded", () => {
} }
if (!syncInterval) startSyncLoop(); if (!syncInterval) startSyncLoop();
hideError();
pendingUserPlay = false;
} finally { } finally {
syncing = false; syncing = false;
} }
@ -322,7 +348,6 @@ document.addEventListener("DOMContentLoaded", () => {
errorBox.style.width = 'fit-content'; errorBox.style.width = 'fit-content';
} }
} }
function hideError() { function hideError() {
if (errorBox) { if (errorBox) {
errorBox.style.display = 'none'; errorBox.style.display = 'none';
@ -387,37 +412,54 @@ document.addEventListener("DOMContentLoaded", () => {
function wireResilience(el, label) { function wireResilience(el, label) {
try { try {
el.addEventListener('waiting', () => { el.addEventListener('waiting', () => {
showError(`${label} buffering…`); // small debounce so instant, harmless "waiting" blips don't hard-pause UX
// pause both while buffering const timer = label === 'Video' ? 'video' : 'audio';
try { video.pause(); } catch {} const ref = timer === 'video' ? 'waitingTimerVideo' : 'waitingTimerAudio';
try { audio.pause(); } catch {} if (ref === 'waitingTimerVideo') {
clearTimeout(waitingTimerVideo);
waitingTimerVideo = setTimeout(() => {
showError(`${label} buffering…`);
try { video.pause(); } catch {}
try { audio.pause(); } catch {}
pendingUserPlay = true;
}, 180);
} else {
clearTimeout(waitingTimerAudio);
waitingTimerAudio = setTimeout(() => {
showError(`${label} buffering…`);
try { video.pause(); } catch {}
try { audio.pause(); } catch {}
pendingUserPlay = true;
}, 180);
}
}); });
el.addEventListener('stalled', () => { el.addEventListener('stalled', () => {
showError(`${label} stalled`); showError(`${label} stalled`);
try { video.pause(); } catch {} try { video.pause(); } catch {}
try { audio.pause(); } catch {} try { audio.pause(); } catch {}
pendingUserPlay = true;
}); });
el.addEventListener('emptied', () => { el.addEventListener('emptied', () => {
showError(`${label} source emptied`); showError(`${label} source emptied`);
try { video.pause(); } catch {} try { video.pause(); } catch {}
try { audio.pause(); } catch {} try { audio.pause(); } catch {}
pendingUserPlay = true;
}); });
el.addEventListener('error', () => { el.addEventListener('error', () => {
showError(`${label} error`); showError(`${label} error`);
try { video.pause(); } catch {} try { video.pause(); } catch {}
try { audio.pause(); } catch {} try { audio.pause(); } catch {}
pendingUserPlay = true;
}); });
el.addEventListener('canplay', () => { el.addEventListener('canplay', () => {
// when it becomes playable again, hide error and try resume // playable again: hide messages and resume if user wanted to play
hideError(); hideError();
if (!video.paused() && !audio.paused()) { if (pendingUserPlay && isReadyForStart()) {
// already playing playTogether({ allowMutedRetry: true });
} else {
// auto resume
const t = Number(video.currentTime());
if (bothPlayableAt(t)) {
playTogether({ allowMutedRetry: true });
}
} }
}); });
} catch {} } catch {}
@ -447,7 +489,12 @@ document.addEventListener("DOMContentLoaded", () => {
safeSetCT(audio, t); safeSetCT(audio, t);
} }
if (bothPlayableAt(t)) playTogether({ allowMutedRetry: true }); if (bothPlayableAt(t)) playTogether({ allowMutedRetry: true });
else pauseTogether(); else {
// prevent audio from starting first then pausing — block until both ok
pendingUserPlay = true;
showError('Buffering… preparing audio and video');
pauseTogether();
}
setupMediaSession(); setupMediaSession();
} }
}; };
@ -455,15 +502,13 @@ document.addEventListener("DOMContentLoaded", () => {
attachRetry(audio, pickAudioSrc, () => { audioReady = true; }); attachRetry(audio, pickAudioSrc, () => { audioReady = true; });
attachRetry(videoEl, () => videoSrc, () => { videoReady = true; }); attachRetry(videoEl, () => videoSrc, () => { videoReady = true; });
// manual mute handling kept
video.on('volumechange', () => { video.on('volumechange', () => {
try { try {
const isMuted = video.muted(); const isMuted = video.muted();
if (isMuted !== userMutedVideo) { if (isMuted !== userMutedVideo) {
userMutedVideo = isMuted; userMutedVideo = isMuted;
} }
if (!isMuted && !userMutedVideo) {
audio.muted = false;
}
if (audio) { if (audio) {
audio.muted = isMuted; audio.muted = isMuted;
} }
@ -473,6 +518,7 @@ document.addEventListener("DOMContentLoaded", () => {
} catch {} } catch {}
}); });
// if the audio UI is exposed and user toggles it
audio.addEventListener('volumechange', () => { audio.addEventListener('volumechange', () => {
try { try {
const isMuted = audio.muted; const isMuted = audio.muted;
@ -489,12 +535,28 @@ document.addEventListener("DOMContentLoaded", () => {
try { audio.playbackRate = video.playbackRate(); } catch {} try { audio.playbackRate = video.playbackRate(); } catch {}
}); });
// do not allow one to run without the other
video.on('play', () => { video.on('play', () => {
vIsPlaying = true; vIsPlaying = true;
const t = Number(video.currentTime());
if (!isReadyForStart()) {
pendingUserPlay = true;
showError('Buffering… preparing audio and video');
pauseTogether();
return;
}
if (!aIsPlaying) playTogether(); if (!aIsPlaying) playTogether();
}); });
audio.addEventListener('play', () => { audio.addEventListener('play', () => {
aIsPlaying = true; aIsPlaying = true;
const t = Number(video.currentTime());
if (!isReadyForStart()) {
// stop audio from racing ahead then pausing
try { audio.pause(); } catch {}
pendingUserPlay = true;
return;
}
if (!vIsPlaying) playTogether(); if (!vIsPlaying) playTogether();
}); });
@ -507,10 +569,16 @@ document.addEventListener("DOMContentLoaded", () => {
audio.addEventListener('pause', () => { audio.addEventListener('pause', () => {
aIsPlaying = false; aIsPlaying = false;
if (!restarting) { if (!restarting) {
try { video.pause(); } catch {} // if video is still playing, try a gentle re-play for audio; otherwise keep both paused
if (!video.paused()) {
audio.play().catch(() => {});
} else {
try { video.pause(); } catch {}
}
} }
}); });
// small vs large seeks: small seeks auto-continue, large seeks pause+resync
let wasPlayingBeforeSeek = false; let wasPlayingBeforeSeek = false;
let lastSeekTime = 0; let lastSeekTime = 0;
video.on('seeking', () => { video.on('seeking', () => {
@ -524,7 +592,10 @@ document.addEventListener("DOMContentLoaded", () => {
const newTime = Number(video.currentTime()); const newTime = Number(video.currentTime());
const seekDiff = Math.abs(newTime - lastSeekTime); const seekDiff = Math.abs(newTime - lastSeekTime);
const dur = Number(video.duration()) || 60; const dur = Number(video.duration()) || 60;
const threshold = Math.max(5, Math.min(dur * 0.66, 60));
// small seek limit ≈ max(0.75s, 5% of duration up to 4s)
const smallSeekLimit = Math.min(4, Math.max(0.75, dur * 0.05));
const bigSeekLimit = Math.max(5, Math.min(dur * 0.66, 60));
if (!firstSeekDone) { if (!firstSeekDone) {
safeSetCT(audio, newTime); safeSetCT(audio, newTime);
@ -532,16 +603,23 @@ document.addEventListener("DOMContentLoaded", () => {
return; return;
} }
if (seekDiff > threshold) { if (seekDiff > bigSeekLimit) {
pauseTogether(); pauseTogether();
safeSetCT(audio, newTime); safeSetCT(audio, newTime);
setTimeout(() => { setTimeout(() => {
if (wasPlayingBeforeSeek && bothPlayableAt(newTime)) { if (wasPlayingBeforeSeek && bothPlayableAt(newTime)) {
playTogether({ allowMutedRetry: true }); playTogether({ allowMutedRetry: true });
} }
}, 180); }, 150);
} else { } else {
safeSetCT(audio, newTime); safeSetCT(audio, newTime);
if (seekDiff <= smallSeekLimit && wasPlayingBeforeSeek) {
if (bothPlayableAt(newTime)) playTogether({ allowMutedRetry: true });
else {
pendingUserPlay = true;
showError('Buffering…');
}
}
} }
}); });
@ -552,6 +630,9 @@ document.addEventListener("DOMContentLoaded", () => {
wireResilience(videoEl, 'Video'); wireResilience(videoEl, 'Video');
wireResilience(audio, 'Audio'); wireResilience(audio, 'Audio');
// looping restarts properly
// doesnt work LOOOOOOOOL
// sooo... I guess, TODO: fix the looping??????
async function restartLoop() { async function restartLoop() {
if (restarting) return; if (restarting) return;
restarting = true; restarting = true;
@ -568,6 +649,7 @@ document.addEventListener("DOMContentLoaded", () => {
} }
} }
// okay, this actually, legit, not working idk why guuuh
video.on('ended', () => { video.on('ended', () => {
if (restarting) return; if (restarting) return;
if (performance.now() < suppressEndedUntil) return; if (performance.now() < suppressEndedUntil) return;
@ -582,14 +664,14 @@ document.addEventListener("DOMContentLoaded", () => {
}); });
videoEl.addEventListener('canplay', () => { videoEl.addEventListener('canplay', () => {
if (!video.paused() && !audio.paused()) return; if (pendingUserPlay && isReadyForStart()) {
const t = Number(video.currentTime()); playTogether({ allowMutedRetry: true });
if (bothPlayableAt(t)) playTogether({ allowMutedRetry: true }); }
}); });
audio.addEventListener('canplay', () => { audio.addEventListener('canplay', () => {
if (!video.paused() && !audio.paused()) return; if (pendingUserPlay && isReadyForStart()) {
const t = Number(video.currentTime()); playTogether({ allowMutedRetry: true });
if (bothPlayableAt(t)) playTogether({ allowMutedRetry: true }); }
}); });
try { try {
@ -613,7 +695,6 @@ 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