1f7b763a7b09f45647d7ec74d15b348f04e765f5
Build ErsatzTV Image / CI toolchain image resolves (push) Successful in 25s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 8m19s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (push) Skipped
Build ErsatzTV Image / Delimiter ban (release path) (push) Successful in 45s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Skipped
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Skipped
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 9m22s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 6m30s
Jellyfin's library-items projection builds every music video's MediaVersion with Streams = [] and no width/height; the server reports those only through per-item PlaybackInfo. MediaServerMusicVideoLibraryScanner.UpdateStatistics wrote that empty projection straight through (also removing any streams a stored row already had), so every Jellyfin music video was stored without streams and FFmpegStreamSelector.SelectVideoStream threw "Sequence contains no matching element" on play. Prod 2026-10-21: the Jellyfin "Music Videos" library (id 16), 1520/1520 versions with zero MediaStream rows. - UpdateStatistics mirrors the movie scanner: on deep scan, new item, changed etag or no stored streams it asks the abstract GetMediaServerStatistics, and writes nothing when the server cannot answer. - JellyfinMusicVideoLibraryScanner implements it via GetPlaybackInfo; chapters come from the incoming projection. - SelectVideoStream fails with the version id, file and remediation (deep scan, or remove a file that has no video stream) instead of a bare First() throw. - Other-video and TV scanners checked: no such gap. - Record scan.mediaserver-statistics-from-server. Existing rows heal only on a DEEP scan (a regular scan skips unchanged etags): POST /api/v1/libraries/16/scan?deep=true after deploy. fixes #924 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: 99d1dedb-f027-4e05-baab-2111f3a7d951 Co-authored-by: Timothy <timothy@noreply.gitea.tblindustries.be>
fix(754,757): declare graphicsElementIds + padToNearestMinute, and pin every MCP tool to its OpenAPI contract (#760)
fix(754,757): declare graphicsElementIds + padToNearestMinute, and pin every MCP tool to its OpenAPI contract (#760)
ErsatzTV
ErsatzTV lets you transform your media library into a personalized, live TV experience - complete with EPG, channel scheduling, and seamless streaming to all your devices. Rediscover your content, your way.
How It Works
- Install ErsatzTV: Download and set up the server on your system.
- Add Your Media: Connect your media libraries and collections.
- Create Channels: Design and schedule your own live channels.
- Stream Anywhere: Watch on any device with IPTV and EPG support.
Key Features
- Custom channels: Create and schedule your own live TV channels.
- IPTV & EPG: Stream with IPTV and Electronic Program Guide support.
- Hardware Transcoding: High-performance streaming with hardware acceleration (NVENC, QSV, VAAPI, AMF, VideoToolbox)
- Media Server Integration: Connect Plex, Jellyfin, Emby and more.
- Music & Subtitles: Mix music videos and enjoy subtitle support.
- Open Source: Free, open, and community-driven project.
Documentation
Documentation is available at ersatztv.org.
License
This project is inspired by pseudotv-plex and the dizquetv fork and is released under the zlib license.
