export interface Subtitle { src: string lang: string } export interface MediaOption { src: string resolution: string } export interface MediaElement { title?: string sub: Subtitle[] src: MediaOption[] } export interface Playlist { items: MediaElement[] currentIndex: number } export interface TargetState { playlist: Playlist playing: MediaElement paused: boolean progress: number playbackRate: number loop: boolean lastSync: number } export interface PlayerState extends TargetState { currentSrc: MediaOption currentSub: Subtitle volume: number muted: boolean fullscreen: boolean error: any duration: number } export interface UserState { socketIds: string[] uid: string name: string avatar: string player: PlayerState } export enum Command { play = "play", pause = "pause", seek = "seek", playbackRate = "playbackRate", playSrc = "playSrc", } export interface CommandLog { command: Command userId: string target?: MediaElement | Playlist | string | number time: number } /** * Chat message structure for in-room chat */ export interface ChatMessage { id: string // unique id per message userId: string // sender socket/user id name: string // sender display name text: string // message text ts: number // timestamp (ms since epoch) } export interface RoomState { serverTime: number id: string ownerId: string users: UserState[] targetState: TargetState commandHistory: CommandLog[] chatLog?: ChatMessage[] // optional to keep backward compatibility }