2.3 KiB
2.3 KiB
Changelog
All notable changes to this project are documented in this file.
[0.1.0] - Unreleased
Added
- Initial implementation: yt-dlp based resolver (merging separate video/audio renditions when YouTube serves a live stream split that way), ffmpeg restreaming, per-channel supervisor worker with proactive URL-expiry refresh and reactive restart-with-backoff, broadcast fan-out to multiple HTTP clients, aiohttp server exposing an M3U playlist and per-channel MPEG-TS streams for Jellyfin Live TV.
- Docker Compose deployment (
Dockerfile,docker-compose.yml) and configuration templates (channels.example.yaml,.env.example). - Gitea Actions CI (
.gitea/workflows/ci.yml): ruff, mypy and pytest, then nativeamd64andarm64image builds on separate runners (no emulation), merged into one multi-arch tag (:develfromdevel,:latestfromrelease, plus a commit-SHA tag). Per-architecture tags carry an-amd64/-arm64suffix. - Unit test suite covering config parsing, URL expiry parsing, ffmpeg argument building, playlist generation, and broadcast fan-out.
Fixed
- Stopping ffmpeg (on every proactive URL refresh) no longer stalls. The worker stops reading ffmpeg's stdout when it
breaks out to refresh, and asyncio's
Process.wait()does not return until every pipe reaches EOF, sostop()always ran into the terminate timeout ("did not exit in time, killing it") and could leave a channel worker stuck for good, silently ending that channel's stream.stop()now drains the leftover stdout while waiting for ffmpeg to exit. /stream/{channel_id}now forces the connection closed after each response (Connection: close) instead of allowing keep-alive. Jellyfin's M3U tuner client (SharedHttpStream) was reusing a pooled keep-alive connection still mid-stream from an earlier request and reading raw MPEG-TS bytes as if they were a fresh HTTP response, failing with "Received an invalid status line".- The yt-dlp resolver now correctly classifies which of the two
requested_formatsentries is audio when a live stream is split into separate video-only and audio-only renditions; it previously relied onacodecbeing set, which yt-dlp does not consistently do for audio-only formats, causing every resolve to fail.