import type { Channel, Nullable } from "../types/index.js"; import type { Request, Response } from "express"; /** * Result of channel validation. On success, contains the resolved channel and provider key. On failure, contains the HTTP error details. The body field carries * either a plain string (for text error responses) or an object (for JSON error responses), so callers can use typeof to pick res.send() vs res.json(). */ export type ValidateChannelResult = { channel: Channel; resolvedKey: string; valid: true; } | { body: Record | string; statusCode: number; valid: false; }; /** * Validates a channel name for streaming. Performs all fast, synchronous checks: disabled status, provider resolution, channel lookup, and login mode. Returns a * discriminated union so callers can handle success and failure without coupling to Express response objects. * * This is extracted from ensureChannelStream() so it can be called by both HLS and MPEG-TS code paths without duplicating the validation logic. * * @param channelName - The channel key to validate. * @returns Validation result with channel data on success, or error details on failure. */ export declare function validateChannel(channelName: string): ValidateChannelResult; /** * Sends a validation error response to the client. Handles both plain text bodies (via res.send) and object bodies (via res.json). * @param validation - The failed validation result. * @param res - Express response object. */ export declare function sendValidationError(validation: { body: Record | string; statusCode: number; }, res: Response): void; /** * Ensures a stream is running for a channel. If no stream exists, starts one. If a stream startup is in progress (-1 sentinel), waits for it to complete. Returns * the stream ID if successful, or null if an error occurred (with the error response already sent to the client). * * The existing-stream check runs first so that ad-hoc streams (registered under synthetic keys like "play-a1b2c3d4") can be served without failing the * "Channel not found" check. * * For channels with multiple providers (e.g., ESPN via ESPN.com or Disney+), the user's provider selection is resolved before looking up the channel definition. * The stream is registered under the canonical key (channelName) for deduplication, but uses the resolved provider's URL and settings. * * @param channelName - The channel key (or synthetic ad-hoc key) to stream. * @param req - Express request object (for profile override and client IP). * @param res - Express response object (for error responses). * @returns The stream ID if a stream is running, or null if an error occurred. */ export declare function ensureChannelStream(channelName: string, req: Request, res: Response): Promise>; /** * Handles HLS playlist requests. Ensures a stream is running for the channel (blocking until ready if a new stream must start), then returns the playlist. * * Route: GET /hls/:name/stream.m3u8 * * @param req - Express request object. * @param res - Express response object. */ export declare function handleHLSPlaylist(req: Request, res: Response): Promise; /** * Handles HLS segment requests. Returns the requested segment from memory. Supports both the fMP4 initialization segment (init.mp4) and media segments (.m4s). * * Route: GET /hls/:name/:segment * * @param req - Express request object. * @param res - Express response object. */ export declare function handleHLSSegment(req: Request, res: Response): void; /** * Handles ad-hoc stream requests for arbitrary URLs. Generates a deterministic synthetic key from the URL and profile, starts a stream if none exists, and redirects * to the standard HLS playlist path. This enables streaming URLs that are not predefined as channels. * * The synthetic key includes the profile so that the same URL with different profiles produces separate streams. The "play-" prefix prevents collisions with * predefined channel names. * * Route: GET /play?url=&profile= * * @param req - Express request object. * @param res - Express response object. */ export declare function handlePlayStream(req: Request, res: Response): Promise; /** * Waits for a stream startup to complete without sending any HTTP responses. Used by MPEG-TS when headers have already been flushed and error responses cannot be * sent. * * @param channelName - The channel name (or synthetic ad-hoc key) to poll. * @returns The resolved stream ID on success, or null if startup failed or timed out. */ export declare function awaitStreamReadySilent(channelName: string): Promise>; /** * Options for initializing a stream. */ interface InitializeStreamOptions { channel?: Channel; channelSelector?: string; channelName: string; clientAddress: Nullable; clickSelector?: string; clickToPlay?: boolean; profileOverride?: string; url: string; } /** * Initializes a new HLS stream. This is the shared stream startup logic used by both channel-based and ad-hoc streams. It handles browser capture setup, segmenter * creation, stream registration, and event emission. * * A -1 sentinel is set in channelToStreamId during setup to prevent duplicate stream starts. On success, the sentinel is replaced with the real stream ID. On * failure, the sentinel is removed and the error is re-thrown for the caller to handle HTTP error responses appropriately (channel-based streams need HDHomeRun * headers, ad-hoc streams do not). * * @param options - Stream initialization options. * @returns The stream ID on success, or null if the stream was terminated during the narrow setup window (orphaned setup race condition). * @throws StreamSetupError if setup fails, or Error for unexpected failures. */ export declare function initializeStream(options: InitializeStreamOptions): Promise>; /** * Checks for idle streams and terminates them. Called periodically by the idle detection interval. */ export declare function cleanupIdleStreams(): void; export {};