aboutsummaryrefslogtreecommitdiff
path: root/web/script
diff options
context:
space:
mode:
Diffstat (limited to 'web/script')
-rw-r--r--web/script/js-player.js125
-rw-r--r--web/script/main.ts1
-rw-r--r--web/script/playerconf-copy-url.js32
-rw-r--r--web/script/transition.js75
4 files changed, 233 insertions, 0 deletions
diff --git a/web/script/js-player.js b/web/script/js-player.js
new file mode 100644
index 0000000..7c3bb43
--- /dev/null
+++ b/web/script/js-player.js
@@ -0,0 +1,125 @@
+/*
+ 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 <metamuffin.org>
+*/
+
+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) + "<br/>" + display_time(e.currentTime - e.duration); // TODO can we have <br> 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" : "")
+}
diff --git a/web/script/main.ts b/web/script/main.ts
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/web/script/main.ts
@@ -0,0 +1 @@
+
diff --git a/web/script/playerconf-copy-url.js b/web/script/playerconf-copy-url.js
new file mode 100644
index 0000000..49f27fd
--- /dev/null
+++ b/web/script/playerconf-copy-url.js
@@ -0,0 +1,32 @@
+
+globalThis.addEventListener("load", () => {
+ for (const e of document.getElementsByClassName("playerconf"))
+ patch_playerconf(e)
+})
+
+function patch_playerconf(form) {
+ const submit = form.lastChild
+
+ const copyurl = document.createElement("button")
+ const d = document.createElement("div")
+ form.removeChild(submit)
+ d.appendChild(submit)
+ d.appendChild(copyurl)
+ form.append(d)
+
+ copyurl.textContent = "Copy Stream URL"
+ d.style.gridArea = "b"
+ d.style.width = "100%"
+ copyurl.style.width = "5em"
+
+ copyurl.addEventListener("click", ev => {
+ const session = document.cookie.split(";").map(e => e.trim().split("=")).find(e => e[0] == "session")[1]
+ ev.preventDefault()
+ const fd = new FormData(form)
+ const sp = ["v", "a", "s"].map(k => fd.get(k)).filter(k => k != "").flat()
+ const url = `${window.location.protocol}//${window.location.host}/n/${window.location.pathname.split("/")[2]}/stream?tracks=${sp}&session=${session}`
+ navigator.clipboard.writeText(url)
+ copyurl.textContent = "Copied"
+ setTimeout(() => copyurl.textContent = "Copy Stream URL", 1000)
+ })
+}
diff --git a/web/script/transition.js b/web/script/transition.js
new file mode 100644
index 0000000..7d39176
--- /dev/null
+++ b/web/script/transition.js
@@ -0,0 +1,75 @@
+/*
+ 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 <metamuffin.org>
+*/
+/// <reference lib="dom" />
+
+const duration = 0.2
+globalThis.addEventListener("load", () => {
+ patch_page()
+})
+
+globalThis.addEventListener("popstate", (_e) => {
+ transition_to(window.location.href, true)
+ // transition_to(_e.state.href, true)
+})
+
+function patch_page() {
+ document.querySelectorAll("a").forEach(el => {
+ el.addEventListener("click", async ev => {
+ ev.preventDefault()
+ await transition_to(el.href)
+ })
+ })
+}
+
+async function transition_to(href, back) {
+ const trigger_load = prepare_load(href, back)
+ await fade(false)
+ trigger_load()
+}
+
+function prepare_load(href, back) {
+ const r_promise = fetch(href)
+ return async () => {
+ let rt = ""
+ try {
+ const r = await r_promise
+ if (!r.ok) return document.body.innerHTML = "<h1>error</h1>"
+ rt = await r.text()
+ } catch (e) {
+ console.error(e)
+ return
+ }
+ const [head, body] = rt.split("<head>")[1].split("</head>")
+ document.head.innerHTML = head
+ document.body.outerHTML = body
+ fade(true)
+ // if (!back) window.history.pushState({href}, "", href)
+ if (!back) window.history.pushState({}, "", href)
+ patch_page()
+ }
+}
+
+function fade(dir) {
+ const overlay = document.createElement("div")
+ overlay.style.position = "absolute"
+ overlay.style.left = "0px"
+ overlay.style.top = "0px"
+ overlay.style.width = "100vw"
+ overlay.style.height = "100vh"
+ overlay.style.backgroundColor = dir ? "black" : "transparent"
+ overlay.style.transition = `background-color ${duration}s`
+ overlay.style.zIndex = 99999;
+ setTimeout(() => {
+ overlay.style.backgroundColor = dir ? "transparent" : "black"
+ }, 0)
+ document.body.appendChild(overlay)
+ return new Promise(res => {
+ setTimeout(() => {
+ if (dir) document.body.removeChild(overlay)
+ res()
+ }, duration * 1000)
+ })
+} \ No newline at end of file