aboutsummaryrefslogtreecommitdiff
path: root/web/script/player/sync.ts
diff options
context:
space:
mode:
Diffstat (limited to 'web/script/player/sync.ts')
-rw-r--r--web/script/player/sync.ts92
1 files changed, 92 insertions, 0 deletions
diff --git a/web/script/player/sync.ts b/web/script/player/sync.ts
new file mode 100644
index 0000000..a2029ea
--- /dev/null
+++ b/web/script/player/sync.ts
@@ -0,0 +1,92 @@
+import { Logger } from "../jshelper/src/log.ts";
+import { Player } from "./player.ts"
+
+function get_username() {
+ return document.querySelector("nav .account .username")?.textContent ?? "Unknown User"
+}
+
+interface Packet {
+ time?: number,
+ playing?: boolean,
+ join?: string,
+ leave?: string,
+}
+
+export class Playersync {
+ private ws: WebSocket
+ private on_destroy: (() => void)[] = []
+
+ private cancel_pers: undefined | (() => void)
+ set_pers(s?: string) {
+ if (this.cancel_pers) this.cancel_pers(), this.cancel_pers = undefined
+ if (s) this.cancel_pers = this.logger?.log_persistent(s)
+ }
+
+ constructor(private player: Player, private logger: Logger<string>, private channel_name: string) {
+ this.set_pers("Playersync enabling...")
+
+ let [localpart, remotepart] = channel_name.split(":")
+ if (!remotepart?.length) remotepart = window.location.host
+
+ this.ws = new WebSocket(`${window.location.protocol.endsWith("s:") ? "wss" : "ws"}://${remotepart}/playersync/${encodeURIComponent(localpart)}`)
+ this.on_destroy.push(() => this.ws.close())
+
+ this.ws.onopen = () => {
+ this.set_pers()
+ this.logger.log(`Playersync connected.`)
+ this.send({ join: get_username() })
+ }
+ this.ws.onerror = () => {
+ this.set_pers(`Playersync websocket error.`)
+ }
+ this.ws.onclose = () => {
+ this.set_pers(`Playersync websocket closed.`)
+ }
+
+ let last_time = 0;
+ this.ws.onmessage = ev => {
+ const packet: Packet = JSON.parse(ev.data)
+ console.log("playersync recv", packet);
+ if (packet.time !== undefined) {
+ this.player.seek(packet.time)
+ last_time = packet.time
+ }
+ if (packet.playing === true) this.player.play()
+ if (packet.playing === false) this.player.pause()
+ if (packet.join) this.logger.log(`${packet.join} joined.`)
+ if (packet.leave) this.logger.log(`${packet.join} left.`)
+ }
+
+ let cb: () => void
+
+ player.video.addEventListener("play", cb = () => {
+ this.send({ playing: true })
+ })
+ this.on_destroy.push(() => player.video.removeEventListener("play", cb))
+
+ player.video.addEventListener("pause", cb = () => {
+ this.send({ playing: false })
+ })
+ this.on_destroy.push(() => player.video.removeEventListener("pause", cb))
+
+ player.video.addEventListener("seeking", cb = () => {
+ const time = this.player.video.currentTime
+ if (Math.abs(last_time - time) < 0.01) return
+ this.send({ time: this.player.video.currentTime })
+ })
+ this.on_destroy.push(() => player.video.removeEventListener("seeking", cb))
+ }
+
+ destroy() {
+ this.set_pers()
+ this.logger.log("Playersync disabled.")
+ this.on_destroy.forEach(f => f())
+ this.send({ leave: get_username() })
+ }
+
+ send(p: Packet) {
+ console.log("playersync send", p);
+ this.ws.send(JSON.stringify(p))
+ }
+}
+