fix(924): the no-video-stream error allows for a file that really has none, and the record names library 16
review-verdict/h10 Review-verdict: MERGEABLE @ 304040d (base: main)
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 11s
PR Gates / Docs update reminder (pull_request) Successful in 13s
PR Gates / decisions lifecycle (pull_request) Successful in 16s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 10s
Review verdict / Set review-verdict status (pull_request_target) Successful in 7s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 19m44s
Build ErsatzTV Image / CI toolchain image resolves (pull_request) Successful in 5s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m6s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 7m19s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 8s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 7s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 40s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 9m5s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
review-verdict/h10 Review-verdict: MERGEABLE @ 304040d (base: main)
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 11s
PR Gates / Docs update reminder (pull_request) Successful in 13s
PR Gates / decisions lifecycle (pull_request) Successful in 16s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 10s
Review verdict / Set review-verdict status (pull_request_target) Successful in 7s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 19m44s
Build ErsatzTV Image / CI toolchain image resolves (pull_request) Successful in 5s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m6s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 7m19s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 8s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 7s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 40s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 9m5s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
Review round 1 nits: - SelectVideoStream's message stated "its media statistics have not been read" as fact. A file that genuinely has no video stream (an audio-only local file, or a Jellyfin item whose playback info has no video, where ProjectToMediaVersion returns None) would send an operator round a deep-scan loop that can never succeed. The message now covers both cases. - scan.mediaserver-statistics-from-server said "library 8". Prod's Jellyfin "Music Videos" library is id 16; no Library row has Id 8 (measured by media-management, 2026-10-21). - The ersatztv skill's symptom note named "images before the #924 fix" instead of the release that carries it (v26.16.0). Refs #924 Decisions-Edit: yes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: 99d1dedb-f027-4e05-baab-2111f3a7d951
This commit is contained in:
@@ -472,11 +472,11 @@ docker start ersatztv
|
||||
### Common Mistakes (check every time)
|
||||
- **Playout not building**: Three things must all be correct: (1) `ProgramScheduleOneItem` row exists for the schedule item, (2) `PlaybackOrder=3` (Shuffle), (3) `ScheduleKind=1` on Playout. Missing any one results in 0 playout items — this is the most common issue.
|
||||
- **Collection queries fail**: `CollectionItem` has no `Id` column — use `rowid` for counting. Content lookup goes through `MediaVersion.MovieId` → `MediaFile.Path` (not a generic MediaItemId join).
|
||||
- **Channel won't start — "has no video stream on record"** (images before the ersatztv#924 fix log a bare
|
||||
- **Channel won't start — "has no video stream on record"** (images before v26.16.0, which carries the ersatztv#924 fix, log a bare
|
||||
`Sequence contains no matching element` at `FFmpegStreamSelector.SelectVideoStream`): the playing item's
|
||||
`MediaVersion` has no `MediaStream` rows. Deep-scan its library — `POST /api/v1/libraries/{id}/scan?deep=true`;
|
||||
a regular scan skips items whose server etag is unchanged and cannot heal them. Jellyfin music videos scanned
|
||||
before that fix were all stored without streams (`scan.mediaserver-statistics-from-server`).
|
||||
a regular scan skips items whose server etag is unchanged and cannot heal them. If the file itself has no video
|
||||
stream, no scan heals it. Jellyfin music videos scanned before that fix were all stored without streams (`scan.mediaserver-statistics-from-server`).
|
||||
- **Channel logos forgotten**: After creating a channel, add an Artwork row (ArtworkKind=2) + logo file, then run `fix_logos.py` to push to Jellyfin. Without this, the channel shows no logo in the EPG.
|
||||
- **Playout reset required**: After any schedule/collection change, run `POST /api/v1/channels/{id}/playout/reset`. Wait 5-10s for the playout to build before verifying item count.
|
||||
|
||||
|
||||
@@ -58,9 +58,10 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector
|
||||
return Task.FromException<MediaStream>(
|
||||
new InvalidOperationException(
|
||||
$"Media version {version.Id} ({path}) has no video stream on record, so it cannot be played. " +
|
||||
"Its media statistics have not been read: rescan the item's library to read them (for a " +
|
||||
"If its media statistics were never read, rescan the item's library to read them (for a " +
|
||||
"Jellyfin/Emby/Plex library, a deep scan, since a regular scan skips items the server reports " +
|
||||
"unchanged)."));
|
||||
"unchanged). If the file itself has no video stream, a rescan cannot help: remove it from " +
|
||||
"video channels."));
|
||||
}
|
||||
|
||||
public async Task<Option<MediaStream>> SelectAudioStream(
|
||||
|
||||
@@ -14,7 +14,7 @@ The Jellyfin and Emby library-items projections build every movie, episode and m
|
||||
`Streams = []` and no dimensions; only the per-item playback info carries them. The movie and TV scanners fetch
|
||||
statistics when the item is new, changed, deep-scanned or has no stored streams. The music-video scanner wrote
|
||||
the projection's version instead, so every Jellyfin music video was stored without streams and
|
||||
`FFmpegStreamSelector.SelectVideoStream` threw on play. Measured on prod 2026-10-21 (#924): library 8, 1520 of
|
||||
`FFmpegStreamSelector.SelectVideoStream` threw on play. Measured on prod 2026-10-21 (#924): the Jellyfin "Music Videos" library (id 16), 1520 of
|
||||
1520 music-video versions with zero `MediaStream` rows (movies 0, episodes 4).
|
||||
|
||||
- **Writing the projection is worse than writing nothing.** `IMetadataRepository.UpdateStatistics` reconciles
|
||||
|
||||
Reference in New Issue
Block a user