Streaming: Custom range-aware HTTP endpoint. Returns 206 Partial Content
for Range requests (with Content-Range, Content-Length, Accept-Ranges).
This was the root cause of broken seeking — Starlette's default
FileResponse behavior wasn't reliable across all clients. Now seeking
works natively via standard HTML5 audio.
Player: Full rewrite. Cleaner separation between absolute book time and
per-track time. Track switching uses pendingSeek + canplay/loadedmetadata
handlers. Console logs for debugging. Removed crossOrigin to avoid CORS
issues. Removed hls.js entirely.
Matcher: Critical bug fix — get_work_details (OpenLibrary) was returning
a sparse MatchResult that REPLACED the rich search result, losing cover,
author, year. New _enrich_match merges details into best without
overwriting existing values (except description/chapters which are
preferred from details fetch).
Scoring: Lenient min/max-weighted similarity (better for German episodic
titles like "Die drei ??? - Folge 215"). Thresholds lowered:
UNCERTAIN 0.50→0.40, AUTO_ACCEPT 0.75→0.65.
Search: search_for_item now returns ALL fields (narrator, publisher,
series, genres, description, language) so manual apply has full data.
Apply: apply_match now always constructs from body first, then enriches
with details. Previously OL applies would lose cover/author. Added
detailed logging across matcher and apply paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MatchResult was missing subtitle field, causing AttributeError in
_apply_match that silently killed every background match task
- Wrap _apply_match in try/except with exc_info logging so failures
are visible in docker compose logs backend
- New POST /api/libraries/:id/match-all endpoint to trigger matching
for all unlocked items (useful for items scanned before the fix)
- Admin UI: Match button per library next to the Scan button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- auth: username lookup is now case-insensitive via func.lower()
- scanner: trigger match_audiobook for each newly found item after scan
- matcher: read match_sources from library settings; refactored to loop
over configured sources in priority order instead of hardcoded sequence
- schemas/routers: expose matchSources in LibraryOut API response
- Admin UI: pill-toggle for MusicBrainz/Open Library/Google Books per library
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>