Fixes #1068
Problem
Automatic search for a book could return 0 results even when the book is available, because the auto-built query is Title Author (Series) and many release names don't carry the author.
I verified this read-only against NZBgeek's API: …Full Cast Edition returned 5 results, but appending J.K. Rowling dropped it to 0 (release names omit the author); and over-specific multi-word queries AND-matched to nothing. (De-hyphenating made no difference — that's a separate normalization, see #1070.)
Fix
AutomaticSearchService now retries once with an author-free query (title + series) when the full query returns no results.
Safety: the automatic path scores results by quality only — relevance comes entirely from the query — so broadening the query could otherwise let a same-title/different-book release pass scoring and be grabbed. The fallback therefore constrains its results to titles that still match the book (ConstrainFallbackResultsToTitle, built on TitleUtils.IsMatchingTitle) before they reach scoring. Distinctive multi-word/long titles recover their releases; short or generic titles (where same-title collisions are likely) fail the match and are safely dropped, so nothing unrelated is grabbed.
Testing
AutomaticSearchResultClassifierTests:
- the author-free query drops the author but keeps title + series;
- the title constraint keeps a matching release (
Andy Weir - Artemis - 2017 - M4Bfor Artemis) and drops an unrelated one (… The Martian …); - empty input returns empty.
The retry orchestration itself lives in the hosted-service loop (ProcessAudiobookAsync), which resolves ~7 services + a SignalR hub from a scope; happy to add a scope-driven integration test if you'd like it, but I kept the safety-critical pieces (query shape + title constraint) in the testable classifier.
🤖 Generated with Claude Code
Automated Canary build