aboutsummaryrefslogtreecommitdiff
path: root/web/script/player/player.ts
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-10-02 20:07:09 +0200
committermetamuffin <metamuffin@disroot.org>2023-10-02 20:07:09 +0200
commitf783143b4adf22be662db1af2ca00b34a868cf72 (patch)
tree180ea44b0f7e7052231643da6e929b1be5f8def1 /web/script/player/player.ts
parente25beb3e0c2531b09d8efd70e858396dcc631dd2 (diff)
downloadjellything-f783143b4adf22be662db1af2ca00b34a868cf72.tar
jellything-f783143b4adf22be662db1af2ca00b34a868cf72.tar.bz2
jellything-f783143b4adf22be662db1af2ca00b34a868cf72.tar.zst
player: split files
Diffstat (limited to 'web/script/player/player.ts')
-rw-r--r--web/script/player/player.ts98
1 files changed, 98 insertions, 0 deletions
diff --git a/web/script/player/player.ts b/web/script/player/player.ts
new file mode 100644
index 0000000..5c38dc8
--- /dev/null
+++ b/web/script/player/player.ts
@@ -0,0 +1,98 @@
+import { OVar, e } from "../jshelper/mod.ts";
+import { JhlsMetadata, TimeRange } from "./jhls.d.ts";
+import { PlayerTrack } from "./track.ts";
+
+export interface BufferRange extends TimeRange { status: "buffered" | "loading" | "queued" }
+export class Player {
+ public video = e("video")
+ private media_source = new MediaSource();
+ public tracks = new OVar<PlayerTrack[]>([]);
+
+ public position = new OVar(0)
+ public duration = new OVar(1)
+ public playing = new OVar(false)
+ public canplay = new OVar(false)
+ public buffering_status = new OVar<string | undefined>(undefined)
+ public error = new OVar<string | undefined>(undefined)
+
+ constructor(private node_id: string) {
+ this.video.onloadedmetadata = () => { }
+ this.video.ondurationchange = () => { }
+ this.video.ontimeupdate = () => {
+ this.position.value = this.video.currentTime
+ this.update() // TODO maybe not here
+ }
+ this.video.onplay = () => {
+ console.log("play");
+ this.buffering_status.value = "Resuming playback...";
+ }
+ this.video.onwaiting = () => {
+ console.log("waiting");
+ this.buffering_status.value = "Buffering...";
+ this.canplay.value = false;
+ }
+ this.video.onplaying = () => {
+ console.log("playing");
+ this.playing.value = true;
+ this.buffering_status.value = undefined;
+ }
+ this.video.onpause = () => {
+ console.log("pause");
+ this.playing.value = false
+ }
+ this.video.oncanplay = () => {
+ console.log("canplay");
+ this.buffering_status.value = undefined
+ this.canplay.value = true
+ }
+ this.video.onseeking = () => {
+ console.log("seeking");
+ this.buffering_status.value = "Seeking..."
+ }
+ this.video.onseeked = () => {
+ console.log("seeked");
+ this.buffering_status.value = undefined
+ }
+ this.fetch_meta()
+ }
+
+ async fetch_meta() {
+ this.buffering_status.value = "Loading JHLS metadata..."
+ const res = await fetch(`/n/${encodeURIComponent(this.node_id)}/stream?format=jhls`)
+ if (!res.ok) return this.error.value = "Cannot download JHLS metadata"
+ const metadata = await res.json() as JhlsMetadata
+ this.buffering_status.value = undefined
+
+ this.duration.value = metadata.duration
+ this.video.src = URL.createObjectURL(this.media_source)
+ this.media_source.addEventListener("sourceopen", async () => {
+ this.tracks.value.push(new PlayerTrack(this.media_source, this.node_id, 0, metadata.tracks[0]))
+ this.tracks.value.push(new PlayerTrack(this.media_source, this.node_id, 1, metadata.tracks[1]))
+ this.tracks.change()
+ this.buffering_status.value = "Fetching initial segments..."
+ this.update()
+ await this.canplay.wait_for(true)
+ this.buffering_status.value = undefined
+ })
+ }
+ async update(newt?: number) {
+ await Promise.all(this.tracks.value.map(t => t.update(newt ?? this.video.currentTime)))
+ }
+
+ play() {
+ this.video.play()
+ }
+ pause() {
+ this.video.pause()
+ }
+ frame_forward() {
+ //@ts-ignore trust me bro
+ this.video["seekToNextFrame"]()
+ }
+ async seek(p: number) {
+ this.buffering_status.value = "Buffering at target..."
+ await this.update(p)
+ this.video.currentTime = p
+ }
+}
+