Diagnosis from connectivity check: 4/5 APIs reachable (only Google Books
rate-limited). So the network is fine — the search title was the problem.
'Folge 114 Die Villa der Toten' isn't indexed under that name anywhere.
The MP3 itself has the real metadata in ID3 tags (album, artist, year).
Scanner now reads ID3/Vorbis/MP4 tags from the first audio file:
- album → item.title
- albumartist / composer / artist → item.author
- date → publish_year
- organization / publisher → publisher
- language → language
- genre → genres
- artist (heuristic) → series, if it doesn't appear in album title
Parent folder name → series hint (skipped if it's a library root).
Only fills empty fields, never overwrites manually edited or matched data.
Runs on new items AND on re-scan for items without an active match.
Search title normalization improved: 'Folge 123 - X' / 'Band 7: Y' etc.
prefixes and infixes get stripped so APIs see the actual episode title.
New endpoint POST /api/items/{id}/extract-tags + 'Tags lesen' button in
BookDetail — triggers tag extraction on demand for existing items.
Returns before/after diff so user can see what was filled in.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
- 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>