// in the beginning.... god made mrrprpmnaynayaynaynayanyuwuuuwmauwnwanwaumawp :p var _yt_player = videojs; var versionclient = "youtube.player.web_20250917_22_RC00" /** * @license * Video.js 8.x * Copyright Brightcove, Inc. * Available under Apache License Version 2.0 * * * Includes vtt.js * Available under Apache License Version 2.0 * */ 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, }); 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'); video.ready(() => { const metaTitle = document.querySelector('meta[name="title"]')?.content || ""; const metaDesc = document.querySelector('meta[name="twitter:description"]')?.content || ""; const metaAuthor = document.querySelector('meta[name="twitter:author"]')?.content || ""; const videoinfostuffidklol = { metaTitle, metaDesc, metaAuthor }; let stats = ""; const match = metaDesc.match(/👍\s*[^|]+\|\s*👎\s*[^|]+\|\s*📈\s*[^💬]+/); if (match) { stats = match[0] .replace(/👍/g, "👍") .replace(/👎/g, "• 👎") .replace(/📈/g, "• 📈") .replace(/\s*\|\s*/g, " "); } const createTitleBar = () => { const existing = video.getChild("TitleBar"); if (!existing) { const titleBar = video.addChild("TitleBar"); titleBar.update({ title: metaTitle, description: stats }); } }; const removeTitleBar = () => { const existing = video.getChild("TitleBar"); if (existing) video.removeChild(existing); }; const handleFullscreen = () => { const fs = document.fullscreenElement || document.webkitFullscreenElement; if (fs) createTitleBar(); else removeTitleBar(); }; document.addEventListener("fullscreenchange", handleFullscreen); document.addEventListener("webkitfullscreenchange", handleFullscreen); handleFullscreen(); }); // inline playback works on iOS/Safari try { videoEl.setAttribute('playsinline', ''); videoEl.setAttribute('webkit-playsinline', ''); } catch {} // global state let syncing = false; let restarting = false; let firstSeekDone = false; // loop param or tag is respected let desiredLoop = !!videoEl.loop || qs.get("loop") === "1" || qs.get("loop") === "true" || window.forceLoop === true; let suppressEndedUntil = 0; let vIsPlaying = false; let aIsPlaying = false; let prevVideoMuted = false; let prevAudioMuted = false; let pendingUnmute = false; // user intent + buffering flags let userWantsPlay = false; // true when user pressed play (we’ll start as soon as it’s valid) let videoBuffering = false; let audioBuffering = false; // New state: track whether user explicitly muted/unmuted let userMutedVideo = false; let userMutedAudio = false; try { videoEl.loop = false; videoEl.removeAttribute?.('loop'); } catch {} try { audio.loop = false; audio.removeAttribute?.('loop'); } catch {} // we pick the right audio src const pickAudioSrc = () => { const s = audio?.getAttribute?.('src'); if (s) return s; const child = audio?.querySelector?.('source'); if (child?.getAttribute?.('src')) return child.getAttribute('src'); if (audio?.currentSrc) return audio.currentSrc; return null; }; const srcObj = video.src(); const videoSrc = Array.isArray(srcObj) ? (srcObj[0] && srcObj[0].src) : srcObj; let audioReady = false, videoReady = false; let syncInterval = null; // sync constants const BIG_DRIFT = 0.5; const MICRO_DRIFT = 0.05; const SYNC_INTERVAL_MS = 250; const EPS = 0.15; const RESYNC_DRIFT_LIMIT = 3.5; // seconds difference that triggers pause+play reset // we check if given time is buffered function timeInBuffered(media, t) { 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; } // we can tell if a timestamp is playable function canPlayAt(media, t) { try { const rs = Number(media.readyState || 0); if (!isFinite(t)) return false; if (rs >= 3) return true; return timeInBuffered(media, t); } catch { return false; } } // we check both elements readiness function bothPlayableAt(t) { return canPlayAt(videoEl, t) && canPlayAt(audio, t); } function safeSetCT(media, t) { try { if (!isFinite(t) || t < 0) return; media.currentTime = t; } catch {} } // status / notice box (uses your loopedIndicator element) const noticeBox = document.getElementById('loopedIndicator'); let statusHideTimer = null; function showNotice(msg) { if (!noticeBox) return; try { noticeBox.textContent = msg; noticeBox.style.display = 'block'; noticeBox.style.width = 'fit-content'; if (statusHideTimer) { clearTimeout(statusHideTimer); statusHideTimer = null; } } catch {} } function hideNotice(withDelay = 300) { if (!noticeBox) return; try { if (statusHideTimer) clearTimeout(statusHideTimer); statusHideTimer = setTimeout(() => { noticeBox.style.display = 'none'; }, Math.max(0, withDelay)); } catch {} } // sync loop is cleared function clearSyncLoop() { if (syncInterval) { clearInterval(syncInterval); syncInterval = null; try { audio.playbackRate = 1; } catch {} } } // helpers to decide if we can start or continue playback function readyForPlayback() { const t = Number(video.currentTime()); return videoReady && audioReady && bothPlayableAt(t) && !videoBuffering && !audioBuffering; } function ensurePausedTogether() { try { video.pause(); } catch {} try { audio.pause(); } catch {} clearSyncLoop(); vIsPlaying = false; aIsPlaying = false; } // playback is kept in sync between both elements function startSyncLoop() { clearSyncLoop(); syncInterval = setInterval(() => { const vt = Number(video.currentTime()); const at = Number(audio.currentTime); if (!isFinite(vt) || !isFinite(at)) return; const delta = vt - at; // if drift is huge (desync >3.5s), resync both if (Math.abs(delta) > RESYNC_DRIFT_LIMIT) { pauseTogether(); setTimeout(() => playTogether({ allowMutedRetry: true }), 150); return; } if (Math.abs(delta) > BIG_DRIFT) { safeSetCT(audio, vt); try { audio.playbackRate = 1; } catch {} return; } if (Math.abs(delta) > MICRO_DRIFT) { const targetRate = 1 + (delta * 0.12); try { audio.playbackRate = Math.max(0.85, Math.min(1.15, targetRate)); } catch {} } else { try { audio.playbackRate = 1; } catch {} } // if one gets muted unexpectedly we fix it (but only if not user-muted) if (!userMutedVideo && video.muted() && !prevVideoMuted) { try { video.muted(false); } catch {} } if (!userMutedAudio && audio.muted && !prevAudioMuted) { try { audio.muted = false; } catch {} } // keep Media Session position state fresh (when available) try { if ('mediaSession' in navigator && navigator.mediaSession.setPositionState) { navigator.mediaSession.setPositionState({ duration: Number(video.duration()) || 0, playbackRate: Number(video.playbackRate()) || 1, position: vt }); } } catch {} }, SYNC_INTERVAL_MS); } // we track playback state const markVPlaying = () => { vIsPlaying = true; maybeUnmuteRestore(); }; const markAPlaying = () => { aIsPlaying = true; maybeUnmuteRestore(); }; const markVNotPlaying = () => { vIsPlaying = false; }; const markANotPlaying = () => { aIsPlaying = false; }; // we know both are active function bothActivelyPlaying() { return vIsPlaying && aIsPlaying; } // both get unmuted when ready function maybeUnmuteRestore() { if (!pendingUnmute) return; if (bothActivelyPlaying()) { pendingUnmute = false; setTimeout(() => { if (!userMutedVideo && video.muted() && !prevVideoMuted) try { video.muted(false); } catch {} if (!userMutedAudio && audio.muted && !prevAudioMuted) try { audio.muted = false; } catch {} }, 120); } } // helper: promise play with result async function tryPlay(el) { try { const p = el.play(); if (p && p.then) await p; return true; } catch { return false; } } // gate play attempts while loading/buffering function blockIfNotReadyThenQueue() { if (!readyForPlayback()) { userWantsPlay = true; // remember intent showNotice('Buffering…'); ensurePausedTogether(); return true; // blocked } hideNotice(200); return false; // not blocked } // both play in sync async function playTogether({ allowMutedRetry = true } = {}) { if (syncing || restarting) return; // don’t let it play when audio is loading or video is loading if (blockIfNotReadyThenQueue()) return; syncing = true; userWantsPlay = true; // explicit intent to be playing try { const t = Number(video.currentTime()); if (isFinite(t) && Math.abs(Number(audio.currentTime) - t) > 0.05) { safeSetCT(audio, t); } let vOk = true, aOk = true; try { const p = video.play(); if (p && p.then) await p; } catch { vOk = false; } aOk = await tryPlay(audio); // If either fails, consider muted retry if (allowMutedRetry && (!vOk || !aOk)) { prevVideoMuted = !!video.muted(); prevAudioMuted = !!audio.muted; pendingUnmute = true; try { video.muted(true); } catch {} try { audio.muted = true; } catch {} try { const p = video.play(); if (p && p.then) await p; } catch {} await tryPlay(audio); } // If video succeeded but audio failed, show error if (!vOk && aOk) { try { video.play().catch(() => { showNotice('Video failed to start.'); setTimeout(() => { video.play().catch(() => showNotice('Video retry failed.')); }, 3000); }); } catch {} } if (vOk && !aOk) { try { audio.play().catch(() => showNotice('Audio failed to start.')); } catch {} } if (!syncInterval) startSyncLoop(); } finally { syncing = false; } } // both pause at once function pauseTogether() { if (syncing) return; syncing = true; try { userWantsPlay = false; // user paused explicitly video.pause(); audio.pause(); clearSyncLoop(); showNotice('Paused'); hideNotice(600); } finally { syncing = false; } } // soooo i know what ur gonna say, its a looped indicator but ur using for errors, and what? // like, why not i use the same element for both its not illegal...i think? // search it up lol const errorBox = document.getElementById('loopedIndicator'); function showError(msg) { if (errorBox) { errorBox.textContent = msg; errorBox.style.display = 'block'; errorBox.style.width = 'fit-content'; } } const clamp = v => Math.max(0, Math.min(1, Number(v))); // media session controls work, these are legit so anoying to work with function setupMediaSession() { if ('mediaSession' in navigator) { try { navigator.mediaSession.metadata = new MediaMetadata({ title: document.title || 'Video', artist: typeof authorchannelname !== "undefined" ? authorchannelname : "", artwork: [ { src: `https://i.ytimg.com/vi/${vidKey}/maxresdefault.jpg`, sizes: "1280x720", type: "image/jpeg" } ] }); } catch {} navigator.mediaSession.setActionHandler('play', () => playTogether()); navigator.mediaSession.setActionHandler('pause', pauseTogether); try { navigator.mediaSession.setActionHandler('seekforward', (d) => { const inc = Number(d?.seekOffset) || 10; video.currentTime(Math.min((video.currentTime() || 0) + inc, Number(video.duration()) || 0)); }); } catch {} try { navigator.mediaSession.setActionHandler('seekbackward', (d) => { const dec = Number(d?.seekOffset) || 10; video.currentTime(Math.max((video.currentTime() || 0) - dec, 0)); }); } catch {} try { navigator.mediaSession.setActionHandler('seekto', (d) => { if (!d || typeof d.seekTime !== 'number') return; video.currentTime(Math.max(0, Math.min(Number(video.duration()) || 0, d.seekTime))); }); } catch {} } } // progress save/restore (safe bounds) const PROGRESS_KEY = `progress-${vidKey}`; function restoreProgress() { try { const saved = Number(localStorage.getItem(PROGRESS_KEY)); const dur = Number(video.duration()) || 0; if (isFinite(saved) && saved > 3 && dur && saved < (dur - 10)) { video.currentTime(saved); safeSetCT(audio, saved); firstSeekDone = true; // prevent immediate reseek jitter } } catch {} } function saveProgressThrottled() { // simple throttle by modulo of seconds try { const t = Math.floor(Number(video.currentTime()) || 0); if (t % 2 === 0) localStorage.setItem(PROGRESS_KEY, String(t)); } catch {} } // network resilience (stall/waiting recovery) function wireResilience(el, label, isVideo) { try { el.addEventListener('waiting', () => { // when video or audio goes into waiting, pause both to avoid audio ghosting showNotice('Buffering…'); if (isVideo) videoBuffering = true; else audioBuffering = true; ensurePausedTogether(); }); el.addEventListener('stalled', () => { showNotice(`${label} stalled`); if (isVideo) videoBuffering = true; else audioBuffering = true; ensurePausedTogether(); }); el.addEventListener('suspend', () => { /* no-op; advisory */ }); el.addEventListener('emptied', () => { showNotice(`${label} source emptied`); if (isVideo) videoBuffering = true; else audioBuffering = true; ensurePausedTogether(); }); el.addEventListener('error', () => { showNotice(`${label} error`); if (isVideo) videoBuffering = true; else audioBuffering = true; ensurePausedTogether(); }); // clear buffering flags on canplay / playing el.addEventListener('canplay', () => { if (isVideo) videoBuffering = false; else audioBuffering = false; if (readyForPlayback() && userWantsPlay) { hideNotice(150); playTogether({ allowMutedRetry: true }); } }); el.addEventListener('playing', () => { if (isVideo) videoBuffering = false; else audioBuffering = false; if (readyForPlayback()) hideNotice(200); }); el.addEventListener('canplaythrough', () => { if (isVideo) videoBuffering = false; else audioBuffering = false; if (readyForPlayback() && userWantsPlay) { hideNotice(150); playTogether({ allowMutedRetry: true }); } }); } catch {} } // guards to ensure elements exist before heavy sync logic const hasExternalAudio = !!audio && audio.tagName === 'AUDIO' && !!pickAudioSrc(); if (qua !== "medium" && hasExternalAudio) { const attachRetry = (elm, resolveSrc, markReady) => { let done = false; const onLoaded = () => { if (done) return; done = true; markReady(); tryStart(); }; elm.addEventListener('loadeddata', onLoaded, { once: true }); elm.addEventListener('loadedmetadata', onLoaded, { once: true }); elm.addEventListener('canplay', onLoaded, { once: true }); }; const tryStart = () => { if (audioReady && videoReady && !restarting) { // restore progress once we know duration/metadata restoreProgress(); const t = Number(video.currentTime()); if (isFinite(t) && Math.abs(Number(audio.currentTime) - t) > 0.1) { safeSetCT(audio, t); } if (bothPlayableAt(t)) { // don’t auto-play unless user asked; just sync readiness if (userWantsPlay) playTogether({ allowMutedRetry: true }); } else { ensurePausedTogether(); } setupMediaSession(); } }; attachRetry(audio, pickAudioSrc, () => { audioReady = true; }); attachRetry(videoEl, () => videoSrc, () => { videoReady = true; }); // todo: fiixxx mute stuff lol video.on('volumechange', () => { try { const isMuted = video.muted(); // If user toggles mute, record intent userMutedVideo = !!isMuted; if (audio) { audio.muted = isMuted; } if (!isMuted) { audio.volume = clamp(video.volume()); } } catch {} }); // Listen manual mute/unmute on audio (if exposed somewhere) audio.addEventListener('volumechange', () => { try { userMutedAudio = !!audio.muted; } catch {} }); video.on('ratechange', () => { try { audio.playbackRate = video.playbackRate(); } catch {} }); // capture user play intent; if not ready, queue and block actual play so one click is enough video.on('play', () => { userWantsPlay = true; if (!readyForPlayback()) { showNotice('Buffering…'); ensurePausedTogether(); // will auto-resume on canplay/canplaythrough return; } markVPlaying(); if (!aIsPlaying) playTogether(); }); audio.addEventListener('play', () => { aIsPlaying = true; if (!vIsPlaying) playTogether(); }); video.on('pause', () => { vIsPlaying = false; if (!restarting) { // ensure audio also pauses try { audio.pause(); } catch {} } }); audio.addEventListener('pause', () => { aIsPlaying = false; if (!restarting) { try { video.pause(); } catch {} } }); // large seeks pause and resync let wasPlayingBeforeSeek = false; let lastSeekTime = 0; video.on('seeking', () => { if (restarting) return; wasPlayingBeforeSeek = !video.paused(); lastSeekTime = Number(video.currentTime()); // while seeking, block start until canplay showNotice('Buffering…'); ensurePausedTogether(); }); video.on('seeked', () => { if (restarting) return; const newTime = Number(video.currentTime()); const seekDiff = Math.abs(newTime - lastSeekTime); const dur = Number(video.duration()) || 60; const threshold = Math.max(5, Math.min(dur * 0.66, 60)); if (!firstSeekDone) { safeSetCT(audio, newTime); firstSeekDone = true; return; } if (seekDiff > threshold) { ensurePausedTogether(); safeSetCT(audio, newTime); setTimeout(() => { if (wasPlayingBeforeSeek) { userWantsPlay = true; if (readyForPlayback()) playTogether({ allowMutedRetry: true }); else showNotice('Buffering…'); } }, 180); } else { safeSetCT(audio, newTime); if (wasPlayingBeforeSeek) { userWantsPlay = true; if (readyForPlayback()) playTogether({ allowMutedRetry: true }); else showNotice('Buffering…'); } } }); // save progress periodically try { video.on('timeupdate', saveProgressThrottled); } catch {} // wire stall/err resilience wireResilience(videoEl, 'Video', true); wireResilience(audio, 'Audio', false); // looping restarts properly // doesnt work LOOOOOOOOL // sooo... I guess, TODO: fix the looping?????? async function restartLoop() { if (restarting) return; restarting = true; try { clearSyncLoop(); ensurePausedTogether(); const startAt = 0.001; suppressEndedUntil = performance.now() + 800; video.currentTime(startAt); safeSetCT(audio, startAt); userWantsPlay = true; await playTogether(); } finally { restarting = false; } } // okay, this actually, legit, not working idk why guuuh video.on('ended', () => { if (restarting) return; if (performance.now() < suppressEndedUntil) return; if (desiredLoop) restartLoop(); else pauseTogether(); }); audio.addEventListener('ended', () => { if (restarting) return; if (performance.now() < suppressEndedUntil) return; if (desiredLoop) restartLoop(); else pauseTogether(); }); // try to resume if media becomes playable again after waiting videoEl.addEventListener('canplay', () => { videoBuffering = false; if (readyForPlayback() && userWantsPlay) { hideNotice(150); playTogether({ allowMutedRetry: true }); } }); audio.addEventListener('canplay', () => { audioBuffering = false; if (readyForPlayback() && userWantsPlay) { hideNotice(150); playTogether({ allowMutedRetry: true }); } }); // clean up on unload to avoid stray timers try { window.addEventListener('pagehide', () => { clearSyncLoop(); }); window.addEventListener('beforeunload', () => { try { localStorage.setItem(PROGRESS_KEY, String(Math.floor(Number(video.currentTime()) || 0))); } catch {} }); } catch {} } else { // fallback when medium quality (no external