// in the beginning.... god made mrrprpmnaynayaynaynayanyuwuuuwmauwnwanwaumawp :p var _yt_player = videojs; var versionclient = "youtube.player.web_20250917_22_RC00" 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 const video = videojs('video', { controls: true, autoplay: false, preload: 'auto', errorDisplay: false, }); // todo : remove this code lol const qs = new URLSearchParams(window.location.search); const qua = qs.get("quality") || ""; const vidKey = qs.get('v'); try { localStorage.setItem(`progress-${vidKey}`, 0); } catch {} // raw media elements const videoEl = document.getElementById('video'); const audio = document.getElementById('aud'); const audioEl = document.getElementById('aud'); let volGuard = false; // FIX: inline playback hint for iOS/Safari try { videoEl.setAttribute('playsinline', ''); videoEl.setAttribute('webkit-playsinline', ''); } catch {} // --- GLOBAL STATE GUARDS ---------------------------------------------------- let syncing = false; // prevents normal ping-pong let restarting = false; // prevents loop-end ping-pong let seekingInProgress = false; // true between seeking/seeked let resumeAfterSeek = false; // whether to auto-resume after seek let didFirstSeek = false; // special handling for the first seek only let vIsPlaying = false; // becomes true on 'playing' let aIsPlaying = false; // becomes true on 'playing' // Mute memory for muted-retry on autoplay policy let prevVideoMuted = false; let prevAudioMuted = false; let pendingUnmute = false; // FIX: explicit loop-state variables let desiredLoop = !!videoEl.loop || qs.get("loop") === "1" || qs.get("loop") === "true" || window.forceLoop === true; // FIX: tracks the short window *during* a loop restart let suppressEndedUntil = 0; // FIX: state arbiter watchdog (forces both to share same paused/playing state) let arbiterTimer = null; const ARBITER_MS = 150; // NEW: suppression window so arbiter ignores the fragile post-seek moment let arbiterSuppressUntil = 0; const now = () => performance.now(); const arbiterSuppressed = () => now() < arbiterSuppressUntil; function startArbiter() { if (arbiterTimer) clearInterval(arbiterTimer); arbiterTimer = setInterval(() => { if (syncing || restarting || seekingInProgress || arbiterSuppressed()) return; // treat "playing" strictly; ended counts as paused const vPlaying = !video.paused() && !video.ended(); const aPlaying = !audio.paused && !audio.ended; // if exactly one is playing, pause the one that is playing (safe + deterministic) if (vPlaying && !aPlaying) { try { video.pause(); } catch {} } else if (aPlaying && !vPlaying) { try { audio.pause(); } catch {} } }, ARBITER_MS); } function stopArbiter() { if (arbiterTimer) { clearInterval(arbiterTimer); arbiterTimer = null; } } // turn OFF native loop so 'ended' fires and we control both tracks together try { videoEl.loop = false; videoEl.removeAttribute?.('loop'); } catch {} try { audio.loop = false; audio.removeAttribute?.('loop'); } catch {} // If someone toggles the