Manual implementation of upstream PR #525
Added flushPartWordBuffer() function and call it before <br/> handling
to fix issue where preceding word was incorrectly wrapped to new line
- Add /api/hash endpoint to compute and cache MD5 hashes on demand
- Extend /api/files response with md5 field for EPUBs (null if not cached)
- Compute and cache MD5 automatically after EPUB uploads
- Add flush() before close() in WebSocket and HTTP upload handlers
- New Md5Utils module using ESP32's mbedtls for chunked hash computation
The MD5 hashes enable the companion app to detect file changes without
downloading content. Hashes are cached in each book's .crosspoint cache
directory and invalidated when file size changes.
Merges progress bar status bar feature from merge-438:
- Added FULL_WITH_PROGRESS_BAR and ONLY_PROGRESS_BAR status bar modes
- Added drawBookProgressBar() to ScreenComponents
Preserves features from current branch:
- Content offset tracking for position restoration (EPUB_PROGRESS_VERSION)
- drawBatteryLarge() function
- Sleep Screen Cover Mode "Actual" option
Adds full support for book lists managed by the Companion App:
- New /list API endpoints (GET/POST) for uploading, retrieving, and deleting lists
- BookListStore for binary serialization of lists to /.lists/ directory
- ListViewActivity for viewing list contents with book thumbnails
- Reading Lists tab in My Library with pin/unpin and delete actions
- Pinnable list shortcut on home screen (split button layout)
- Automatic cleanup of pinned status when lists are deleted
Integrates upstream PR #511 changes while preserving local delete/archive
functionality. Key changes:
- Add RecentBook struct with path, title, author fields
- Update RecentBooksStore to store and serialize metadata
- Implement version migration for existing recent.bin files
- Update MyLibraryActivity to display two-line items (title + author)
- Update EpubReaderActivity and XtcReaderActivity to pass metadata
Maintains backwards compatibility with delete/archive feature from
local commit d5a9873.
Add ZipFile::fillUncompressedSizes() for single-pass ZIP central directory
scan with hash-based target matching.
Also apply clang-format fixes for CI.
Shadow Slave results:
- buildBookBin: 506s → 35s
- Total indexing: 8.7min → 50s
Three optimizations for EPUBs with many chapters (e.g. 2768 chapters):
1. OPF idref→href lookup: Build sorted hash index during manifest parsing,
use binary search during spine resolution. Reduces ~4min to ~30-60s.
2. TOC href→spineIndex lookup: Build sorted hash index in beginTocPass(),
use binary search in createTocEntry(). Reduces ~4min to ~30-60s.
3. ZIP central-dir cursor: Resume scanning from last position instead of
restarting from beginning. Reduces ~8min to ~1-3min.
All optimizations only activate for large EPUBs (≥400 spine items).
Small books use unchanged code paths.
Memory impact: ~33KB + ~39KB temporary during indexing, freed after.
Expected total: ~17min → ~3-5min for Shadow Slave (2768 chapters).
Also adds phase timing logs for performance measurement.
The unordered_map with 2768 string keys (~100KB+) was causing OOM crashes
at beginTocPass() on ESP32-C3's limited ~380KB RAM.
Reverted createTocEntry() to use original O(n) spine file scan instead.
Kept the safe spineToTocIndex vector in buildBookBin() (only ~5.5KB).