Chapter images are never extracted, so a chapter list renders without pictures #98
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A scan already writes the
Chaptersrows —crates/jellyfin-db/src/scan.rs:1668deletes and re-inserts them from what ffprobe reported — andImagePathon every one of them is null. Nothing extracts a frame.Upstream's
ChapterImagesTask(Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs, keyRefreshChapterImages, daily) walks every video, seeks to each chapter's start, writes a jpg under the metadata directory, and stores the path on the row. A client draws the chapter menu from those paths; with none, the menu is a list of times.Two things to settle from upstream rather than guess at: which items are eligible (it has a configuration switch per library and skips items with too many chapters), and where the file goes — the path convention is the same kind of rule M6 settled for local artwork, and getting it wrong writes files upstream cannot read.
Depends on the scheduler issue for the when; the extraction itself is standalone and can be driven by hand first.
Where to start
The rows already exist:
crates/jellyfin-db/src/scan.rs:1668deletes andre-inserts
Chaptersfrom what the prober reported, andImagePathis writtennull.
crates/jellyfin-db/src/items.rs:340is the read.Upstream is
Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs(key
RefreshChapterImages, daily). Two things to take from it rather thandecide: which items are eligible (there is a per-library switch and a ceiling on
chapter count), and where the file goes — the on-disk convention is the same
kind of rule M6 settled for local artwork, and a file in the wrong place is one
upstream cannot read.
The extraction itself is a seek and a still, through
crates/jellyfin-ffmpeg.How to know it is done
diff-dbover a library both servers scanned reports no difference onChapters,ImagePathincluded once the paths are substituted — that column isthe whole point and it is diffed today, so this is a check that already exists
and currently passes vacuously because both sides are null.
Compare a written jpg against upstream's on bytes, not on dimensions. M10
learned that twice: a check on a projection is not a check.
House rules
CLAUDE.mdis the short version and these are the parts that bite: tests rununder
cargo nextest; upstream's source is the checkout inupstream/at thepin (
v12.0-rc5,6d501ba4) and not the clone beside the repository;generated files are regenerated rather than edited; a comment says what the code
does, not how it got there; and
Dnreferences stay out of code and comments.ARCHITECTURE.mddecides which crate a thing goes in and which dependency edgesare illegal,
DECISIONS.mdsays why a rule exists.The reference pair is
cargo xtask reference up(andreference provision,which is idempotent); a run is
cargo run -p jellyfin-harness -- replay --upstream URL --ours URL --scenario FILE --out DIR,with
diff-dbfor the two databases.crates/jellyfin-harness/README.mdsayswhat a diff means and what an ignore entry has to carry — every entry needs a
reason and an expiry milestone, and an adds-only history is the smell the risk
table names.
Done, on
main—dda1d09.The
Chaptersrows already existed withImagePathnull. Three chapter rows now agree column for column and the three jpegs are identical byte for byte — 9973, 9578 and 9510 bytes. The path convention, the 15-second offset for the opening chapter, the average-gap floor and the failure list under the cache directory are all upstream's.This uncovered a bug outside the batch, in a path nothing could have caught.
jellyfin-encoding::input::video_sync_optionhanded the number to the option that takes a name: upstream maps-1 → autofor ffmpeg 5.1 and later, and ours emitted-fps_mode -1, which ffmpeg refuses outright — so everything reaching it failed. It is also in the attachment burn-in path (attach.rs:123setsinput_video_sync = "-1"). Fixed here; the corpus gap that hid it is filed separately, because neither generated corpus file contains-fps_modeat all.One
db-ignore-list.jsonentry added:Chapters.ImageDateModified, value-scoped, on the same wall-clock argument asBaseItems.DateLastRefreshed— which chapters carry a picture is still diffed, and so isImagePathbeside it. It cannot fire on the current fixture, because nothing there has chapters, which is the honest cost of adding it before the fixture grows one.The fixture wants a chaptered file. This was measured on one built by hand —
Night Signalremuxed with three chapters — and registered as a library on both servers. Until the committed fixture carries one, nothing in a replay holds this.