yt-dlp reports scheduled premieres as live_status 'is_upcoming' (not
'upcoming'), and exposes release_timestamp with the stream's scheduled
start time. For an upcoming stream with a known start, reschedule the
job at start+2min without touching the wait counter, no matter how far
away the start is — the bounded 10-minute wait clock (maxLiveWaits,
~4h) now only applies while a stream is actually running. Upcoming
streams with an unknown start time keep the 10-minute wait behavior.
While a YouTube video is still a live stream (or upcoming), the static
formats bestaudio requests may not be available, so yt-dlp fails with
'Requested format is not available'. Once the stream ends, YouTube
converts it to a regular VOD that downloads normally.
Before downloading, probe the video's live_status via yt-dlp. If it is
still live, reschedule the job in 10-minute increments (live_wait_count)
without counting against the normal retry budget. After 24 consecutive
waits (~4h) the job falls back to a regular retry attempt with the
exponential backoff, so a video that never converts still fails
permanently instead of retrying forever. Live waits are reset on
success or any ordinary retry.
- ytdlp: thin wrapper around yt-dlp CLI for channel/playlist discovery
(--flat-playlist) and per-video metadata (--print-json); defaults to
player_client=web_embedded to avoid SABR-only format restrictions.
- downloader: YouTube path extracts audio via yt-dlp -x, probes duration
with ffprobe and rejects clips far shorter than the expected length.
- main: YouTube channel/playlist feeds, incremental discovery with
pre-start-date boundary for newest-first channels, two-phase
record-then-enqueue so discovered jobs survive crashes.
- poller: propagate enclosure MIME type; computeDestPath appends the
matching file extension.
- state: jobs carry expected duration; AddJobWithStatus for skipped items.
- cmd/probe: dry-run discovery/date-resolution diagnostics.