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" | "private"; export type LogoPosition = "top_left" | "top_right" | "bottom_left" | "bottom_right"; export type FillStrategy = "best_fit" | "sequential" | "random" | "alternating" | "weighted" | "marathon"; 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[]; series_names?: string[]; 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; provider_id: string; external_id: string; title: string; content_type: string; duration_secs: number; series_name?: string | null; season_number?: number | null; episode_number?: number | null; year?: number | null; genres: string[]; tags: string[]; collection_id?: string | null; collection_name?: string | null; collection_type?: string | null; thumbnail_url?: string | null; synced_at?: string | null; } export interface RotationPolicy { cooldown_days?: number | null; cooldown_generations?: number | null; min_available_ratio: number; } export interface InterstitialRule { pool_filter: MediaFilter; strategy: FillStrategy; min_gap_secs: number; } export interface MidRollRule { prefer_chapters: boolean; fallback_interval_mins: number; break_duration_secs: number; pool_filter: MediaFilter; } 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; start_time: string; duration_mins: number; content: BlockContent; loop_on_finish?: boolean; ignore_rotation_policy?: boolean; interstitial_rule?: InterstitialRule | null; mid_roll_rule?: MidRollRule | null; access_mode?: AccessMode; 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; providers: ProviderInfo[]; provider_capabilities: ProviderCapabilities; available_provider_types: string[]; } export interface ProviderConfig { id: string; 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; rotation_policy: RotationPolicy; auto_schedule: boolean; access_mode: string; logo?: string | null; logo_position: string; logo_opacity: number; webhook_url?: string | null; webhook_poll_interval_secs: number; webhook_body_template?: string | null; webhook_headers?: string | null; gap_filler?: MediaFilter | 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; rotation_policy?: RotationPolicy; auto_schedule?: boolean; access_mode?: string; logo?: string | null; logo_position?: string; logo_opacity?: number; webhook_url?: string | null; webhook_poll_interval_secs?: number; webhook_body_template?: string | null; webhook_headers?: string | null; gap_filler?: MediaFilter | null; } // Media & Schedule export interface MediaItemResponse { id: string; title: string; content_type: string; duration_secs: number; description?: string | null; genres: string[]; tags: string[]; year?: number | null; series_name?: string | null; season_number?: number | null; episode_number?: number | null; } export interface ScheduledSlotResponse { id: string; start_at: string; end_at: string; item: MediaItemResponse; source_block_id: string; } export interface ScheduleResponse { id: string; channel_id: string; valid_from: string; valid_until: string; generation: number; slots: ScheduledSlotResponse[]; } export interface CurrentBroadcastResponse { slot: ScheduledSlotResponse; offset_secs: number; } export type LibraryItemFull = LibraryItemResponse; export interface ShowSummary { series_name: string; episode_count: number; season_count: number; thumbnail_url?: string | null; genres: string[]; } export interface SeasonSummary { season_number: number; episode_count: number; thumbnail_url?: string | null; } export interface PagedLibraryResponse { items: LibraryItemFull[]; total: number; } export interface LibrarySyncLogEntry { id: number; provider_id: string; started_at: string; finished_at?: string | null; items_found: number; status: 'running' | 'done' | 'error'; error_msg?: string | null; } export interface AdminSettings { library_sync_interval_hours: number; [key: string]: unknown; }