/* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2023 metamuffin */ globalThis.addEventListener("load", () => { for (const e of document.getElementsByTagName("video")) patch_video(e) }) function patch_video(e) { // move the video to a div const d = document.createElement("div") const p = e.parentElement p.removeChild(e) d.appendChild(e) p.prepend(d) e.removeAttribute("controls") d.classList.add("js-player") const controls = document.createElement("div") controls.classList.add("controls") const pause_button = document.createElement("button") pause_button.textContent = "|>" const fullscreen_button = document.createElement("button") fullscreen_button.textContent = "X" const status_display = document.createElement("p") status_display.classList.add("status") const pri = document.createElement("div") pri.classList.add("pri") const pri_current = document.createElement("div") pri_current.style.width = "0px" pri_current.classList.add("pri-current") pri.append(pri_current) controls.append(pause_button, status_display, pri, fullscreen_button) d.append(controls) e.onloadedmetadata = () => { } e.ondurationchange = () => { } e.ontimeupdate = () => { status_display.innerHTML = display_time(e.currentTime) + "
" + display_time(e.currentTime - e.duration); // TODO can we have
with textContent?! pri_current.style.width = (e.currentTime / e.duration * 100) + "%" } e.onplay = () => { pause_button.textContent = "..." } e.onwaiting = () => { pause_button.textContent = "..." } e.onplaying = () => { pause_button.textContent = "||" } e.onpause = () => { pause_button.textContent = "|>" } const toggle_playing = () => e.paused ? e.play() : e.pause() mouse_idle(e, 1000, idle => { controls.style.opacity = idle ? 0 : 1 e.style.cursor = idle ? "none" : "default" }) e.addEventListener("click", toggle_playing) pause_button.addEventListener("click", toggle_playing) fullscreen_button.addEventListener("click", () => { if (document.fullscreenElement) document.exitFullscreen() else document.documentElement.requestFullscreen() }) const seek_ev = ev => { const r = pri.getBoundingClientRect() const p = (ev.clientX - r.left) / (r.right - r.left) e.currentTime = p * e.duration } pri.addEventListener("mousedown", ev => { seek_ev(ev) }) document.body.addEventListener("keydown", k => { if (k.code == "Period") e.seekToNextFrame() else if (k.code == "Space") toggle_playing() else if (k.code == "ArrowLeft") e.currentTime -= 5 else if (k.code == "ArrowRight") e.currentTime += 5 else if (k.code == "ArrowUp") e.currentTime -= 60 else if (k.code == "ArrowDown") e.currentTime += 60 else return; k.preventDefault() }) } function mouse_idle(e, timeout, cb) { let ct; let idle = false e.onmouseleave = () => { clearTimeout(ct) } e.onmousemove = () => { clearTimeout(ct) if (idle) { idle = false cb(idle) } ct = setTimeout(() => { idle = true cb(idle) }, timeout) } } function display_time(t) { if (t < 0) return "-" + display_time(-t) let h = 0, m = 0, s = 0; while (t > 3600) t -= 3600, h++; while (t > 60) t -= 60, m++; while (t > 1) t -= 1, s++; return (h ? h + "h" : "") + (m ? m + "m" : "") + (s ? s + "s" : "") }