98 lines
2.1 KiB
TypeScript
98 lines
2.1 KiB
TypeScript
import type { ServerWebSocket } from "bun";
|
|
|
|
export interface Track {
|
|
filename: string;
|
|
title: string;
|
|
duration: number;
|
|
}
|
|
|
|
export interface StreamConfig {
|
|
id: string;
|
|
name: string;
|
|
tracks: Track[];
|
|
}
|
|
|
|
export class Stream {
|
|
id: string;
|
|
name: string;
|
|
playlist: Track[];
|
|
currentIndex: number = 0;
|
|
startedAt: number = Date.now();
|
|
clients: Set<ServerWebSocket<{ streamId: string }>> = new Set();
|
|
paused: boolean = false;
|
|
pausedAt: number = 0;
|
|
|
|
constructor(config: StreamConfig) {
|
|
this.id = config.id;
|
|
this.name = config.name;
|
|
this.playlist = config.tracks;
|
|
}
|
|
|
|
get currentTrack(): Track | null {
|
|
if (this.playlist.length === 0) return null;
|
|
return this.playlist[this.currentIndex];
|
|
}
|
|
|
|
get currentTimestamp(): number {
|
|
if (this.paused) return this.pausedAt;
|
|
return (Date.now() - this.startedAt) / 1000;
|
|
}
|
|
|
|
tick(): boolean {
|
|
if (this.paused) return false;
|
|
const track = this.currentTrack;
|
|
if (!track) return false;
|
|
if (this.currentTimestamp >= track.duration) {
|
|
this.advance();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
advance() {
|
|
if (this.playlist.length === 0) return;
|
|
this.currentIndex = (this.currentIndex + 1) % this.playlist.length;
|
|
this.startedAt = Date.now();
|
|
this.broadcast();
|
|
}
|
|
|
|
getState() {
|
|
return {
|
|
track: this.currentTrack,
|
|
currentTimestamp: this.currentTimestamp,
|
|
streamName: this.name,
|
|
paused: this.paused,
|
|
};
|
|
}
|
|
|
|
pause() {
|
|
if (this.paused) return;
|
|
this.pausedAt = this.currentTimestamp;
|
|
this.paused = true;
|
|
this.broadcast();
|
|
}
|
|
|
|
unpause() {
|
|
if (!this.paused) return;
|
|
this.paused = false;
|
|
this.startedAt = Date.now() - this.pausedAt * 1000;
|
|
this.broadcast();
|
|
}
|
|
|
|
broadcast() {
|
|
const msg = JSON.stringify(this.getState());
|
|
for (const ws of this.clients) {
|
|
ws.send(msg);
|
|
}
|
|
}
|
|
|
|
addClient(ws: ServerWebSocket<{ streamId: string }>) {
|
|
this.clients.add(ws);
|
|
ws.send(JSON.stringify(this.getState()));
|
|
}
|
|
|
|
removeClient(ws: ServerWebSocket<{ streamId: string }>) {
|
|
this.clients.delete(ws);
|
|
}
|
|
}
|