Streaming: Drop token-in-URL auth entirely. Session-ID (UUID, 128-bit
entropy) IS the auth — same approach as Audiobookshelf. Eliminates the
entire class of token-related failures and matches how every other
streaming server handles this. Logs every stream request with Range
header and User-Agent for diagnostics.
Player: Visible error banner in UI when audio fails (with HTML5 media
error code translated to German). Stream URL is shown in the banner so
the user can see exactly what failed.
Scanner: Cover extraction from two new sources (in addition to API
matching):
1. Folder-level images (cover.jpg, folder.jpg, front.jpg, etc.)
2. Embedded artwork (ID3 APIC, MP4 covr, FLAC/Vorbis pictures)
Runs on every scan — also fills in covers for items that were already
scanned but never got one from matching.
New endpoint POST /api/items/{id}/extract-cover triggers this manually
for a single item.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>