// API response and request types matching the backend DTOs export interface ActivityEvent { id: string; timestamp: string; event_type: string; detail: string; channel_id?: string; } export interface LogLine { level: string; target: string; message: string; timestamp: string; } export type ContentType = "movie" | "episode" | "short"; export type AccessMode = "public" | "password_protected" | "account_required" | "owner_only"; export type LogoPosition = "top_left" | "top_right" | "bottom_left" | "bottom_right"; 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; provider_id?: string } | { type: "manual"; items: string[]; provider_id?: 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; access_mode?: AccessMode; /** Plain-text password sent to API; hashed server-side. Only set on write operations. */ access_password?: string; } export type Weekday = | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday' export const WEEKDAYS: Weekday[] = [ 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', ] export const WEEKDAY_LABELS: Record = { monday: 'Mon', tuesday: 'Tue', wednesday: 'Wed', thursday: 'Thu', friday: 'Fri', saturday: 'Sat', sunday: 'Sun', } export interface ScheduleConfig { day_blocks: Record } export interface ConfigSnapshot { id: string version_num: number label: string | null created_at: string } export interface ScheduleHistoryEntry { id: string generation: number valid_from: string valid_until: string } // Config export type StreamingProtocol = "hls" | "direct_file"; export interface ProviderCapabilities { collections: boolean; series: boolean; genres: boolean; tags: boolean; decade: boolean; search: boolean; streaming_protocol: StreamingProtocol; rescan: boolean; transcode: boolean; } export interface TranscodeSettings { cleanup_ttl_hours: number; } export interface TranscodeStats { cache_size_bytes: number; item_count: number; } export interface ProviderInfo { id: string; capabilities: ProviderCapabilities; } export interface ConfigResponse { allow_registration: boolean; /** All registered providers. Added in multi-provider update. */ providers: ProviderInfo[]; /** Primary provider capabilities — kept for backward compat. */ provider_capabilities: ProviderCapabilities; available_provider_types: string[]; } export interface ProviderConfig { provider_type: string; config_json: Record; enabled: boolean; } export interface ProviderTestResult { ok: boolean; message: string; } // Auth export interface TokenResponse { access_token: string; token_type: string; expires_in: number; refresh_token?: string; } export interface UserResponse { id: string; email: string; created_at: string; is_admin: boolean; } // Channels export interface ChannelResponse { id: string; owner_id: string; name: string; description?: string | null; timezone: string; schedule_config: ScheduleConfig; recycle_policy: RecyclePolicy; auto_schedule: boolean; access_mode: AccessMode; logo?: string | null; logo_position: LogoPosition; logo_opacity: number; webhook_url?: string | null; webhook_poll_interval_secs?: number; webhook_body_template?: string | null; webhook_headers?: string | null; created_at: string; updated_at: string; } export interface CreateChannelRequest { name: string; timezone: string; description?: string; access_mode?: AccessMode; access_password?: string; webhook_url?: string; webhook_poll_interval_secs?: number; webhook_body_template?: string; webhook_headers?: string; } export interface UpdateChannelRequest { name?: string; description?: string; timezone?: string; schedule_config?: ScheduleConfig; recycle_policy?: RecyclePolicy; auto_schedule?: boolean; access_mode?: AccessMode; /** Empty string clears the password. */ access_password?: string; /** null = clear logo */ logo?: string | null; logo_position?: LogoPosition; logo_opacity?: number; /** null = clear webhook */ webhook_url?: string | null; webhook_poll_interval_secs?: number; /** null = clear template */ webhook_body_template?: string | null; /** null = clear headers */ webhook_headers?: string | null; } // 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; block_access_mode: AccessMode; } 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; block_access_mode: AccessMode; }