New Features
Match Report Widget
- Full per-book match report UI rendered after every run -- expandable cards in a 2-per-row grid showing local vs. matched metadata side by side
- Each card shows: cover images (local + provider), title, author, narrator, series, sequence, genre, year, ASIN, duration comparison, the query used to find the match, and a score percentage badge
- Searchable by title, author, series, or path; filterable by status (Matched, Goodreads, Manually Applied, Smart-skipped, Would write, Written, Skipped, Not Matched, Error)
- Manually applied books show a dedicated badge and load their stored marker data so the report reflects what was actually written, not a re-matched result
- Local cover loading now extracts the embedded cover from loose audio files directly via ffmpeg, so books without a folder-level cover.jpg get their own correct cover instead of sharing the parent folder's
Goodreads / Kindle Fallback (abs-tract)
- Unmatched books automatically fall back to Goodreads via abs-tract for title, author, series, and sequence metadata
- Kindle cover-only fallback for books that match on metadata but lack an Audible cover
- Explicit opt-in flag in the UI (Goodreads fallback checkbox); manual provider selector also exposes Goodreads and Kindle for single-book review
- Circuit breaker with cooldown protects against upstream Goodreads/Amazon rate-limit blocks; transient failures retry instead of failing silently
- Goodreads matches are provider-aware: smart-skip only checks the fields Goodreads can actually supply (title, author, series, sequence) -- narrator, ASIN, year, and genre are never blanked by a Goodreads re-match
Settings Page
- Dedicated /settings page consolidating preferences, Accounts, and cleanup controls into a left-nav sectioned layout
- Publisher learning author/narrator guard: known author and narrator names are no longer incorrectly learned as publishers
Multi-file Grouping Improvements
- Per-chapter .ogg books grouped as a single multi-file book
- Leading-ordinal chapter splits (e.g. "01 - BookTitle Part 1.mp3") grouped correctly as one book
- Sidecar cleanup endpoint: remove libraforge state files for a target folder
Fixes
Matching Quality
- Cross-series matches blocked when series names share only a prefix word (e.g. Arena vs Arena Road)
- Hard block on matches with a clearly different author
- Four matching failures fixed: chapter-numbered titles, audio-author-prefixed filenames, format labels misread as immersion labels, Goodreads series queries
- "Title - Series, N" filenames with a bare book number now parsed correctly
- Grouped "Series N - Author" folder names no longer blocked from matching
Genre
- Removed all "Audiobook" hardcodes from the fixer script -- genre now defaults to empty string instead of the format label
- Genre field filtered through all candidate providers and surfaced in the match report card and manual review UI
- _pick_genre() helper blocks format labels ("audiobook", "audiobooks") so they never appear as a real genre
Metadata Correctness
- fill_missing no longer preserves stale fraction sequences (e.g. "1/1" from embedded MP4 track tags) when a fresh valid sequence is available
- Relative target paths normalized correctly before being passed to the fixer
- Target path validated before run starts with a clear 400 error instead of a silent failure
UI / UX
- Score badge shows percentage (e.g. 87%) instead of a rounded 0 or 1
- "Audiobook" genre no longer appears in manual review metadata fields
- Path validation error surfaced clearly in the run UI