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> = 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); } }