// API response and request types matching the backend DTOs export type ContentType = "movie" | "episode" | "short"; export type FillStrategy = "best_fit" | "sequential" | "random"; export interface MediaFilter { content_type?: ContentType | null; genres: string[]; decade?: number | null; tags: string[]; min_duration_secs?: number | null; max_duration_secs?: number | null; collections: string[]; /** Filter to one or more TV series by name. OR-combined: any listed show is eligible. */ series_names?: string[]; /** Free-text search, used for library browsing only. */ search_term?: string | null; } // Library browsing export interface CollectionResponse { id: string; name: string; collection_type?: string | null; } export interface SeriesResponse { id: string; name: string; episode_count: number; genres: string[]; year?: number | null; } export interface LibraryItemResponse { id: string; title: string; content_type: ContentType; duration_secs: number; series_name?: string | null; season_number?: number | null; episode_number?: number | null; year?: number | null; genres: string[]; } export interface RecyclePolicy { cooldown_days?: number | null; cooldown_generations?: number | null; min_available_ratio: number; } export type BlockContent = | { type: "algorithmic"; filter: MediaFilter; strategy: FillStrategy } | { type: "manual"; items: string[] }; export interface ProgrammingBlock { id: string; name: string; /** "HH:MM:SS" */ start_time: string; duration_mins: number; content: BlockContent; /** Sequential only: loop back to episode 1 after the last episode. Default true on backend. */ loop_on_finish?: boolean; /** When true, skip the channel-level recycle policy for this block. Default false on backend. */ ignore_recycle_policy?: boolean; } export interface ScheduleConfig { blocks: ProgrammingBlock[]; } // Config export interface ConfigResponse { allow_registration: boolean; } // Auth export interface TokenResponse { access_token: string; token_type: string; expires_in: number; } export interface UserResponse { id: string; email: string; created_at: string; } // Channels export interface ChannelResponse { id: string; owner_id: string; name: string; description?: string | null; timezone: string; schedule_config: ScheduleConfig; recycle_policy: RecyclePolicy; created_at: string; updated_at: string; } export interface CreateChannelRequest { name: string; timezone: string; description?: string; } export interface UpdateChannelRequest { name?: string; description?: string; timezone?: string; schedule_config?: ScheduleConfig; recycle_policy?: RecyclePolicy; } // Media & Schedule export interface MediaItemResponse { id: string; title: string; content_type: ContentType; duration_secs: number; description?: string | null; genres: string[]; tags: string[]; year?: number | null; /** Episodes only: the parent TV show name. */ series_name?: string | null; /** Episodes only: season number (1-based). */ season_number?: number | null; /** Episodes only: episode number within the season (1-based). */ episode_number?: number | null; } export interface ScheduledSlotResponse { id: string; block_id: string; item: MediaItemResponse; /** RFC3339 */ start_at: string; /** RFC3339 */ end_at: string; } export interface ScheduleResponse { id: string; channel_id: string; generation: number; generated_at: string; valid_from: string; valid_until: string; slots: ScheduledSlotResponse[]; } export interface CurrentBroadcastResponse { slot: ScheduledSlotResponse; offset_secs: number; }