diff --git a/.skills/SKILL.md b/.skills/SKILL.md index 1e687b3e..3d34eaca 100644 --- a/.skills/SKILL.md +++ b/.skills/SKILL.md @@ -847,8 +847,8 @@ rm -rf /path/to/sd/.crosspoint/epub_/sections/ **Source**: `lib/Epub/Epub/Section.cpp`, `lib/Epub/Epub/BookMetadataCache.cpp` **Current Versions** (as of docs/file-formats.md): -- `book.bin`: **Version 5** (metadata structure) -- `section.bin`: **Version 20** (layout structure, includes paragraph LUT) +- `book.bin`: **Version 7** (header A includes cached `tocReliable` byte) +- `section.bin`: **Version 23** (layout structure, includes paragraph LUT) **Version Increment Rules**: 1. **ALWAYS increment version** BEFORE changing binary structure diff --git a/docs/epub-toc-navigation.md b/docs/epub-toc-navigation.md index 2e623c65..6f40af82 100644 --- a/docs/epub-toc-navigation.md +++ b/docs/epub-toc-navigation.md @@ -22,6 +22,14 @@ Spine items before the first TOC entry (cover pages) and after the last (appendi - `getTocItem(i)` returns the TOC entry (title, spineIndex, anchor) for TOC index `i` -- also a file seek per call, not cached in memory. Code that queries TOC metadata in a loop should cache the results locally first. - `getSpineIndexForTocIndex(i)` does the reverse lookup (TOC index to spine index). +### Cached TOC reliability flag + +`hasReliableToc()` answers whether the TOC has enough spine coverage (>=25% of spines referenced) to drive chapter UX, with short-circuits for `tocCount <= 0` and the "large book with one TOC entry" pathology. + +The result is computed once during `buildBookBin` (folded into the existing `spineIndex->tocIndex` scan, so no extra disk pass) and persisted as a single byte in book.bin's header A. `Epub::hasReliableToc()` reads `BookMetadataCache::isTocReliable()` and caches the bool in `tocReliabilityState`. + +This matters because the check used to recompute the answer on demand by calling `getTocEntry(i)` for every TOC entry, which does two SD-card seeks per call. On a 2858-entry web-novel TOC that was ~5700 seeks (~7 seconds) added to first-page latency. `BOOK_CACHE_VERSION` was bumped to 7 for this layout change; older caches are rebuilt on next open. + ## Section cache file format The section cache (`.bin`) stores pre-rendered page data for a spine item. The file layout: diff --git a/docs/file-formats.md b/docs/file-formats.md index 61c4c8bd..669ae078 100644 --- a/docs/file-formats.md +++ b/docs/file-formats.md @@ -2,7 +2,7 @@ ## `book.bin` -### Version 3 +### Version 7 ImHex Pattern: @@ -12,7 +12,7 @@ import std.string; import std.core; // === Configuration === -#define EXPECTED_VERSION 3 +#define EXPECTED_VERSION 7 #define MAX_STRING_LENGTH 65535 // === String Structure === @@ -34,8 +34,12 @@ fn format_string(String s) { struct Metadata { String title [[comment("Book title")]]; String author [[comment("Book author")]]; + String language [[comment("BCP47 language tag")]]; String coverItemHref [[comment("Path to cover image")]]; String textReferenceHref [[comment("Path to guided first text reference")]]; + String series [[comment("Series name")]]; + String seriesIndex [[comment("Series index/position")]]; + String description [[comment("Book description / blurb")]]; } [[comment("Book metadata information")]]; // === Spine Entry Structure === @@ -70,7 +74,8 @@ struct BookBin { u32 lutOffset [[comment("Offset to lookup tables"), color("6BCB77")]]; u16 spineCount [[comment("Number of spine entries"), color("4D96FF")]]; u16 tocCount [[comment("Number of TOC entries"), color("FF6B9D")]]; - + u8 tocReliable [[comment("1 if TOC has >=25% spine coverage, 0 otherwise"), color("F4A261")]]; + // Metadata section Metadata metadata [[comment("Book metadata")]];