A comic's fallback cover is the first entry by bytes, not by upstream's culture ordering #223

Closed
opened 2026-09-15 23:30:08 +02:00 by Claude · 1 comment
Collaborator

When a comic archive has no entry named as a cover, we fall back to its first page. Our first page can be a different entry from upstream's.

Both sides

upstream/MediaBrowser.Providers/Books/ComicImageProvider.cs:133 orders the entries with OrderBy(x => x.Key). That is .NET's default culture-sensitive string comparison, which ignores case at the first level and weights punctuation differently.

Ours (crates/ephyra-app/src/scan/books/mod.rs, the cover fallback) sorts the entry names by their bytes.

What differs

  • B01.jpg and a01.jpg: bytes put B01 first, while the culture comparison puts a01 first.
  • _credits.jpg and 001.jpg: underscore and digit order differ between the two comparisons.

The cover a library shows for such a comic differs between the servers. The library-kinds key covers neither case.

Verifying

Add a .cbz with mixed-case and punctuation-led entry names, and no named cover, to the library-kinds tree. Regenerate and compare the picked cover. Upstream runs under the invariant culture in its container, which is the ordering to match.

Found reviewing #210.

When a comic archive has no entry named as a cover, we fall back to its first page. Our first page can be a different entry from upstream's. ## Both sides `upstream/MediaBrowser.Providers/Books/ComicImageProvider.cs:133` orders the entries with `OrderBy(x => x.Key)`. That is .NET's default culture-sensitive string comparison, which ignores case at the first level and weights punctuation differently. Ours (`crates/ephyra-app/src/scan/books/mod.rs`, the cover fallback) sorts the entry names by their bytes. ## What differs - `B01.jpg` and `a01.jpg`: bytes put `B01` first, while the culture comparison puts `a01` first. - `_credits.jpg` and `001.jpg`: underscore and digit order differ between the two comparisons. The cover a library shows for such a comic differs between the servers. The library-kinds key covers neither case. ## Verifying Add a `.cbz` with mixed-case and punctuation-led entry names, and no named cover, to the library-kinds tree. Regenerate and compare the picked cover. Upstream runs under the invariant culture in its container, which is the ordering to match. Found reviewing #210.
Author
Collaborator

Fixed, and landed on main at 76f368b8.

A new archive, /kinds/books/Crossing #4 (1994).cbz, names no cover and holds a01.jpg, B01.jpg and _credits.jpg, each a different picture of a different size. The answer key now records the cover upstream extracted — which meant turning the comic cover extractor on in the generator, so five covers are compared. Upstream cut _credits.jpg: neither the first by bytes nor the first in the archive.

The order was then measured a pair at a time with four two-page archives, giving _ - ! ( @ #. ordered() in crates/ephyra-app/src/scan/books/mod.rs ranks those marks as measured, puts punctuation before digits and letters, folds case with case as the tiebreak, and leaves anything outside the measured marks in code-point order after them.

D49 records what the key settles and what it does not: marks outside the six, where digits fall between the classes, and non-ASCII names are all approximation rather than .NET's collation, and they are named as what would justify revisiting it.

Fixed, and landed on `main` at `76f368b8`. A new archive, `/kinds/books/Crossing #4 (1994).cbz`, names no cover and holds `a01.jpg`, `B01.jpg` and `_credits.jpg`, each a different picture of a different size. The answer key now records the cover upstream extracted — which meant turning the comic cover extractor on in the generator, so five covers are compared. Upstream cut `_credits.jpg`: neither the first by bytes nor the first in the archive. The order was then measured a pair at a time with four two-page archives, giving `_ - ! ( @ #`. `ordered()` in `crates/ephyra-app/src/scan/books/mod.rs` ranks those marks as measured, puts punctuation before digits and letters, folds case with case as the tiebreak, and leaves anything outside the measured marks in code-point order after them. D49 records what the key settles and what it does not: marks outside the six, where digits fall between the classes, and non-ASCII names are all approximation rather than .NET's collation, and they are named as what would justify revisiting it.
Sign in to join this conversation.
No description provided.