diff --git a/css/player-base-new.js b/css/player-base-new.js index 8c70a38c..39eb425d 100644 --- a/css/player-base-new.js +++ b/css/player-base-new.js @@ -2,485 +2,468 @@ var _yt_player = videojs; var versionclient = "youtube.player.web_20250917_22_RC00" - + // video.js 8 init - source can be seen in https://poketube.fun/static/vjs.min.js or the vjs.min.js file document.addEventListener("DOMContentLoaded", () => { - const player = videojs("video", { - controls: true, - autoplay: false, - preload: "auto", - errorDisplay: false, - }); + const player = videojs('video', { + controls: true, + autoplay: false, + preload: 'auto', + errorDisplay: false, + }); - const qs = new URLSearchParams(location.search); - const qua = qs.get("quality") || ""; - const vidKey = qs.get("v"); - try { if (vidKey) localStorage.setItem(`progress-${vidKey}`, 0); } catch {} + // todo : remove this code lol + const qs = new URLSearchParams(window.location.search); + const qua = qs.get("quality") || ""; + const vidKey = qs.get('v'); + try { if (vidKey) localStorage.setItem(`progress-${vidKey}`, 0); } catch {} - // raw media nodes - const videoEl = document.getElementById("video"); - const audioEl = document.getElementById("aud"); + // raw media elements + const videoEl = document.getElementById('video'); + const audioEl = document.getElementById('aud'); - // keep the hidden audio truly hidden/quiet - try { - audioEl.controls = false; - audioEl.setAttribute("aria-hidden", "true"); - audioEl.setAttribute("tabindex", "-1"); - audioEl.setAttribute("controlslist", "noplaybackrate nodownload noremoteplayback"); - audioEl.disableRemotePlayback = true; - videoEl.setAttribute("playsinline", ""); - audioEl.setAttribute("playsinline", ""); - audioEl.preload = "auto"; - } catch {} - - // initial source probes - const pickAudioSrc = () => { - const s = audioEl?.getAttribute?.("src"); - if (s) return s; - const child = audioEl?.querySelector?.("source"); - if (child?.getAttribute?.("src")) return child.getAttribute("src"); - if (audioEl?.currentSrc) return audioEl.currentSrc; - return null; - }; - let audioSrc = pickAudioSrc(); - - const srcObj = player.src(); - const initialVideoSrc = Array.isArray(srcObj) ? (srcObj[0] && srcObj[0].src) : srcObj; - const initialVideoType = Array.isArray(srcObj) ? (srcObj[0] && srcObj[0].type) : undefined; - - // small state bag - let audioReady = false, videoReady = false; - let mediaSessionReady = false; - - // sync knobs - const BIG_DRIFT = 0.45; // snap threshold (s) - const MICRO_DRIFT = 0.035; // subtle rate nudge (s) - const EPS = 0.12; // buffer epsilon (s) - - // guards - let volGuard = false; - let syncGuard = false; // block re-entrant sync - let couplingGuard = false; // block play/pause echo - let autosyncTimer = null; - const AUTOSYNC_MS = 400; - - // seeking flags (so pausing audio for seeks won't pause the video) - let audioPauseForSeek = false; - let playerSeekWasPlaying = false; - - // loop detection - let lastVideoTime = 0; - - // helpers - function timeInBuffered(media, t) { + // harden hidden audio so it never steals session/focus try { - const br = media.buffered; - if (!br || br.length === 0 || !isFinite(t)) return false; - for (let i = 0; i < br.length; i++) { - const s = br.start(i) - EPS, e = br.end(i) + EPS; - if (t >= s && t <= e) return true; - } - } catch {} - return false; - } - function canPlayAt(media, t) { - try { - const rs = Number(media.readyState || 0); - if (!isFinite(t)) return false; - if (rs >= 3) return true; // HAVE_FUTURE_DATA - return timeInBuffered(media, t); - } catch { return false; } - } - function bothPlayableAt(t) { return canPlayAt(videoEl, t) && canPlayAt(audioEl, t); } - function safeSetCT(media, t) { try { if (isFinite(t) && t >= 0) media.currentTime = t; } catch {} } - const clamp01 = v => Math.max(0, Math.min(1, Number(v))); - function isLooping() { try { return !!player.loop?.() || !!videoEl.loop; } catch { return !!videoEl.loop; } } - - // keep mute/volume mirrored either way - function mirrorFromPlayerVolumeMute() { - if (volGuard) return; volGuard = true; - try { - const m = !!player.muted(); - const v = clamp01(player.volume()); - audioEl.muted = m; - if (!m) audioEl.volume = v; - try { videoEl.muted = m; } catch {} - } catch {} - volGuard = false; - } - function mirrorFromAudioVolumeMute() { - if (volGuard) return; volGuard = true; - try { - const m = !!audioEl.muted; - const v = clamp01(audioEl.volume); - player.muted(m); - if (!m) player.volume(v); - try { videoEl.muted = m; } catch {} - } catch {} - volGuard = false; - } - player.on("volumechange", mirrorFromPlayerVolumeMute); - audioEl.addEventListener("volumechange", mirrorFromAudioVolumeMute); - player.ready(() => mirrorFromPlayerVolumeMute()); - - // one-button control helpers - function playBoth() { - if (couplingGuard) return; - couplingGuard = true; - player.play()?.catch(()=>{}); - audioEl.play()?.catch(()=>{}); - startAutosync(); - couplingGuard = false; - } - function pauseBoth() { - if (couplingGuard) return; - couplingGuard = true; - player.pause(); - audioEl.pause(); - stopAutosync(); - couplingGuard = false; - } - - // video is the boss: when it plays/pauses, audio mirrors - player.on("play", () => { - if (audioEl.paused) audioEl.play()?.catch(()=>{}); - startAutosync(); - try { if ("mediaSession" in navigator) navigator.mediaSession.playbackState = "playing"; } catch {} - }); - player.on("pause", () => { - if (!audioEl.paused) audioEl.pause(); - stopAutosync(); - try { if ("mediaSession" in navigator) navigator.mediaSession.playbackState = "paused"; } catch {} - }); - - // if the platform tries to play/pause audio alone, route through video - audioEl.addEventListener("play", () => { if (player.paused()) playBoth(); }); - audioEl.addEventListener("pause", () => { - if (audioPauseForSeek) return; // our deliberate pause (do not pause video) - if (!player.paused()) pauseBoth(); // any other pause → keep them in lockstep - }); - - // media-session timeline (keeps OS seekbar calm) - let lastMSPos = 0, lastMSAt = 0; - const MS_THROTTLE_MS = 250; - function getDuration() { - let d = Number(videoEl.duration); - if (!isFinite(d) || d <= 0) d = Number(player.duration()); - if (!isFinite(d) || d <= 0) d = Number(audioEl.duration); - return isFinite(d) && d > 0 ? d : null; - } - function updateMSPositionState(throttle = true) { - if (!("mediaSession" in navigator)) return; - const now = performance.now(); - if (throttle && (now - lastMSAt) < MS_THROTTLE_MS) return; - const dur = getDuration(); - if (!dur) return; - - let pos = Number(player.currentTime()); - if (!isFinite(pos) || pos < 0) pos = 0; - - // avoid flicker; allow jump-back only on real loop wrap - if (pos + 0.2 < lastMSPos && isLooping()) lastMSPos = 0; - else { - if (pos < lastMSPos && (lastMSPos - pos) < 0.2) pos = lastMSPos; - lastMSPos = pos; - } - lastMSAt = now; - - try { - if ("setPositionState" in navigator.mediaSession) { - navigator.mediaSession.setPositionState({ - duration: dur, - playbackRate: Number(player.playbackRate()) || 1, - position: Math.max(0, Math.min(dur, pos)), - }); - } - } catch {} - } - function setupMediaSession() { - if (mediaSessionReady) return; - if (!("mediaSession" in navigator)) return; - - try { - navigator.mediaSession.metadata = new MediaMetadata({ - title: document.title || "Video", - artist: "", - album: "", - artwork: [] - }); + audioEl.controls = false; + audioEl.setAttribute('aria-hidden', 'true'); + audioEl.setAttribute('tabindex', '-1'); + audioEl.setAttribute('controlslist', 'noplaybackrate nodownload noremoteplayback'); + audioEl.disableRemotePlayback = true; + videoEl.setAttribute('playsinline', ''); + audioEl.setAttribute('playsinline', ''); + audioEl.preload = 'auto'; } catch {} - const tagState = () => { - try { navigator.mediaSession.playbackState = player.paused() ? "paused" : "playing"; } catch {} - updateMSPositionState(false); + // resolve initial sources robustly (works whether