(() => { const cfg = window.PLAYER_CONFIG || {}; const VIDEO_LIST = Array.isArray(cfg.videos) ? cfg.videos : []; const DEF_VOL = Number.isFinite(cfg.defaultVolume) ? Math.max(0, Math.min(1, cfg.defaultVolume)) : 0.3; const LSV = cfg.localStorageVolumeKey || "vpref"; const LSM = cfg.localStorageMutedKey || "mpref"; const $ = id => document.getElementById(id); const v = $("video"); const p = $("play"); const m = $("mute"); const s = $("seek"); const o = $("volume"); const c = $("controls"); const r = $("player"); const t = $("tapUnmute"); const x = $("rotate"); const ba = $("prevBtn"); const bb = $("nextBtn"); const F = VIDEO_LIST.filter(item => item && item.src && item.chance > 0); const D = F.length ? F : [ { src: "https://s1ne.com/buttery-stealthx.webm", chance: 100 } ]; const HASLS = (() => { try { const key = "__video_player_storage_test__"; localStorage.setItem(key, "1"); localStorage.removeItem(key); return true; } catch { return false; } })(); let i = 0; let h; let n; let l = -1; let u = false; let y = false; let q = []; let blocked = false; let sideControls = false; let sideEdge = false; const coarsePointer = matchMedia("(pointer:coarse)").matches; const EDGE_HOVER = 92; const storedVolume = HASLS ? Number(localStorage.getItem(LSV)) : NaN; const storedMuted = HASLS ? localStorage.getItem(LSM) : null; function isMobile() { return coarsePointer || innerWidth <= 768; } function updateRangeProgress(el) { const min = Number(el.min) || 0; const max = Number(el.max) || 100; const val = Number(el.value) || 0; const progress = max === min ? 0 : ((val - min) * 100) / (max - min); el.style.setProperty("--range-progress", `${progress}%`); } function weightedPick(seed) { let total = 0; for (const item of D) { total += Number(item.chance) || 0; } if (total <= 0) { return 0; } let roll = seed == null ? Math.random() * total : seed % total; for (let index = 0; index < D.length; index++) { roll -= Number(D[index].chance) || 0; if (roll < 0) { return index; } } return D.length - 1; } function loopIndex(index) { return ((index % D.length) + D.length) % D.length; } function preferredVolume() { return Number.isFinite(storedVolume) ? Math.max(0, Math.min(1, storedVolume)) : DEF_VOL; } function preferredMuted() { return storedMuted === null ? false : storedMuted === "1"; } function savePref() { if (!HASLS) return; try { localStorage.setItem(LSV, String(v.volume || 0)); localStorage.setItem(LSM, v.muted ? "1" : "0"); } catch {} } function sideAllowed() { return !isMobile() && innerWidth > 768; } function updateSide() { r.classList.toggle("side-visible", sideAllowed() && (sideControls || sideEdge)); } function setSideControls(show) { sideControls = Boolean(show); updateSide(); } function setSideEdge(show) { sideEdge = Boolean(show); updateSide(); } function edgeHover(event) { if (!sideAllowed()) { setSideEdge(false); return; } const nearEdge = event.clientX <= EDGE_HOVER || event.clientX >= innerWidth - EDGE_HOVER; setSideEdge(nearEdge); } function setTap(show) { t.classList.toggle("visible", Boolean(show)); } function loadVideo(index) { i = loopIndex(index); v.src = D[i].src; blocked = false; setTap(false); } function trimQueue(arr) { q = arr.slice(-3); } function nextCleanIndex(index) { if (!D.length) return 0; let candidate = loopIndex(index); let tries = 0; while (tries < D.length && q.includes(candidate)) { candidate = loopIndex(candidate + 1); tries++; } return candidate; } function updatePlayButton() { p.textContent = v.paused ? "x" : "▶"; } function updateRotateButton() { x.textContent = y ? "⟲" : "⟳"; } function updateMuteButton() { m.textContent = v.muted || v.volume === 0 ? "u" : "a"; o.value = v.muted ? 0 : v.volume; updateRangeProgress(o); } function showControls() { if (!u) { c.classList.add("visible"); u = true; } setSideControls(true); clearTimeout(h); h = setTimeout(() => { c.classList.remove("visible"); u = false; setSideControls(false); }, isMobile() ? 2200 : 1700); } function resizeVideo() { const videoWidth = v.videoWidth; const videoHeight = v.videoHeight; const windowWidth = innerWidth; const windowHeight = innerHeight; if (!videoWidth || !videoHeight) { v.style.objectFit = "cover"; v.style.transform = "translateZ(0) scale(1.01)"; return; } if (y) { v.style.objectFit = "contain"; v.style.transform = "translateZ(0) rotate(90deg) scale(1.15)"; return; } const videoRatio = videoWidth / videoHeight; const windowRatio = windowWidth / windowHeight; v.style.objectFit = videoRatio > windowRatio ? "contain" : "cover"; v.style.transform = "translateZ(0) scale(1)"; } function toggleRotate() { y = !y; updateRotateButton(); resizeVideo(); showControls(); } function initVolume() { const volume = preferredVolume(); const muted = preferredMuted(); v.muted = muted; v.volume = muted ? 0 : volume; savePref(); } async function start() { blocked = false; initVolume(); updateMuteButton(); updatePlayButton(); updateRotateButton(); try { await v.play(); setTap(!(v.muted === false && v.volume > 0)); return true; } catch { v.muted = true; v.volume = 0; updateMuteButton(); try { await v.play(); blocked = true; setTap(true); return false; } catch { blocked = true; setTap(true); return false; } } } function unmuteFromTap() { v.muted = false; v.volume = Math.max(v.volume || 0, 0.5); blocked = false; setTap(false); updateMuteButton(); updatePlayButton(); savePref(); v.play().catch(() => {}); } function playNextByIndex(index) { loadVideo(nextCleanIndex(index)); q.push(i); trimQueue(q); showControls(); start(); } function loadRandomNext() { let index = weightedPick(); for ( let attempt = 0; attempt < 8 && (index === i || q.includes(index)); attempt++ ) { index = loopIndex(index + 1); } loadVideo(index); q.push(i); trimQueue(q); showControls(); start(); } v.addEventListener("error", () => { playNextByIndex(i + 1); }); v.addEventListener("ended", loadRandomNext); v.addEventListener("play", () => { updatePlayButton(); showControls(); setTap(!(v.muted === false && v.volume > 0)); }); v.addEventListener("pause", () => { updatePlayButton(); showControls(); }); v.addEventListener("loadedmetadata", () => { resizeVideo(); const clearText = () => { const el = document.querySelector(".video-text"); if (el) { el.textContent = ""; } }; if (window.requestIdleCallback) { window.requestIdleCallback(clearText); } else { setTimeout(clearText, 0); } updateMuteButton(); updatePlayButton(); }); v.addEventListener("loadeddata", () => { setTap(!(v.muted === false && v.volume > 0)); }); v.addEventListener("volumechange", savePref); v.addEventListener("timeupdate", () => { if (!v.duration) return; const percent = (100 * v.currentTime / v.duration) | 0; if (percent !== l) { l = percent; s.value = percent; updateRangeProgress(s); } }); p.addEventListener("click", async event => { event.stopPropagation(); if (v.paused) { await v.play().catch(() => {}); } else { v.pause(); } }); m.addEventListener("click", event => { event.stopPropagation(); if (v.muted || v.volume === 0) { v.muted = false; if (v.volume === 0) { v.volume = 0.5; } blocked = false; setTap(false); } else { v.muted = true; } updateMuteButton(); savePref(); }); s.addEventListener("input", event => { event.stopPropagation(); updateRangeProgress(event.target); if (v.duration) { v.currentTime = event.target.value / 100 * v.duration; } }); o.addEventListener("input", event => { event.stopPropagation(); updateRangeProgress(event.target); v.volume = parseFloat(event.target.value); v.muted = v.volume === 0; if (v.volume > 0) { blocked = false; setTap(false); } updateMuteButton(); savePref(); }); x.addEventListener("click", event => { event.stopPropagation(); toggleRotate(); }); t.addEventListener("click", event => { event.stopPropagation(); unmuteFromTap(); }); c.addEventListener("click", event => { event.stopPropagation(); }); r.addEventListener( "click", () => { showControls(); if (blocked && v.muted) { unmuteFromTap(); } }, { passive: true } ); r.addEventListener("mousemove", event => { showControls(); edgeHover(event); }); r.addEventListener("mouseenter", event => { showControls(); edgeHover(event); }); r.addEventListener("mouseleave", () => { setSideEdge(false); }); r.addEventListener("touchstart", showControls, { passive: true }); ba.addEventListener("mouseenter", () => { setSideEdge(true); }); bb.addEventListener("mouseenter", () => { setSideEdge(true); }); ba.addEventListener("click", event => { event.stopPropagation(); playNextByIndex(i - 1); }); bb.addEventListener("click", event => { event.stopPropagation(); playNextByIndex(i + 1); }); addEventListener("resize", () => { clearTimeout(n); n = setTimeout(() => { resizeVideo(); updateSide(); }, 100); }); addEventListener("orientationchange", () => { resizeVideo(); updateSide(); }); updateRangeProgress(s); updateRangeProgress(o); loadVideo(weightedPick()); q = [i]; updatePlayButton(); updateMuteButton(); updateRotateButton(); updateSide(); start(); })();