Skip to content

Retry automatic search with title only when title and author returns nothing - #825

Closed
matheusfillipe wants to merge 3 commits into
Listenarrs:canaryfrom
matheusfillipe:801-search-query-fallback
Closed

matheusfillipe wants to merge 3 commits into
Listenarrs:canaryfrom
matheusfillipe:801-search-query-fallback

Conversation

@matheusfillipe

@matheusfillipe matheusfillipe commented Aug 19, 2026 •

Copy link
Copy Markdown

Automatic search builds one query from the title plus the author, and gives up if it comes back empty. Audible titles often carry a suffix like (Part 1 of 2) or (Dramatized Adaptation), and the author usually does not appear in release names, so that combined query matches nothing at the indexers.

Refs #801.

@m4bard

m4bard commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

I wanted to see what this retry sends to an indexer, so I ran it in throwaway containers: stock canary a630572e9, and a630572e9 with this branch merged (it merges cleanly). Each had a stub Torznab indexer that logs requests and returns nothing except for queries containing "Doyle". I searched with POST /api/v1/download/search-and-download.

Book Stock With #825
Ghosts, Henrik Ibsen Ghosts Henrik Ibsen that, then Ghosts
The Strange Case of Dr Jekyll and Mr Hyde, Robert Louis Stevenson title plus author that, then the title alone
The Adventures of Sherlock Holmes, Arthur Conan Doyle (stub answers) title plus author title plus author only
Beowulf, no author Beowulf Beowulf

With the indexer's Categories blank, no request carried cat=. With 3030 set, all of them did.

The risk I see is Ghosts reaching an indexer with no category. As far as I can tell, at 3ec84f74b SearchAndDownloadAsync only scores results through ScoreSearchResults, which never sees the book, so nothing checks that what comes back is the book (read, not reproduced as a wrong grab). #591 and #744 add a RelevanceFilter that asks for author corroboration on single-word titles like Ghosts, and #744 also sends cat=3030 on automatic searches.

Readarr sends a bare title as its last tier too (NewznabRequestGenerator.cs#L85-L90). Two things in the request path keep that safe: it builds no request for an indexer without categories (#L129-L131), and it won't save one (NewznabSettings.cs#L35-L37). Our fork has a version of the categories requirement, not yet exercised on a real install.

#714's title-only fallback is opt-out (AutomaticSearchTitleOnlyFallback); this one is not.

How would you like this sequenced against #591 and #744?

Disclosure: drafted with Claude Code at my direction; I read the cited code at the stated commit and reviewed this before posting.

@matheusfillipe

Copy link
Copy Markdown
Author

@m4bard thanks for testing it like that, the table made it really clear.

I pushed a small change: the retries now go out with cat=3030, so a bare title like Ghosts only hits the audiobook category and can't pull in music or video. I tried it against my own indexers and Red Rising (Part 1 of 2) went from no results to picking the unabridged Red Rising. The sequels like Golden Son still show up in that list though, so a relevance check like the one in #744 would still help.

I don't mind the order, happy to rebase on whichever lands first.

Yoldark34 added a commit to Yoldark34/Listenarr that referenced this pull request Oct 14, 2026
Listenarrs#825 is based on 1.3.0. On 1.3.10 it pushes DownloadService.cs past the
500-line limit and its test class misses BaseTests and the Name/Category
traits. Move the retry loop into SearchQueryFallbacks.SearchAsync, used by
both search paths, and cover it with the Marche ou crève case (author
credited as "Stephen King (alias Richard Bachman)").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Yoldark34

Yoldark34 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

I've been running this PR in my build on top of current canary, and it fixes a real case for me: Audible credits Marche ou crève to Stephen King (alias Richard Bachman), so the title + author query returns nothing on my French indexer, and the title-only retry finds it.

Merged as is onto v1.3.11-canary, three tests fail:

  1. DownloadServiceTests.SearchAndDownloadAsync_WhenSendToDownloadClientReturnsEmpty_ReturnsFailureAndDoesNotLogHistory (added in fix(wanted): scope search all to filtered audiobooks and add confirmation modal #1009): Expected invocation on the mock once, but was 0 times. The test's audiobook has no title or author, so the primary query is empty, and Expand() drops empty entries. No search runs at all, where the current code still runs the primary search.
  2. BackendArchitectureTests.ActiveProductionSourceFiles_RemainFocused: DownloadService.cs grows to 508 lines (limit 500).
  3. BackendArchitectureTests.TestClasses_FollowRepositoryConventions: SearchQueryFallbacksTests needs to derive from BaseTests and carry the Name/Category traits.

This is how I fixed them locally, on local/1.3.11 in my fork (Yoldark34/Listenarr@1e06c18 and Yoldark34/Listenarr@0e0d6e9):

  • the retry loop moved into a SearchQueryFallbacks.SearchAsync(searchService, primaryQuery, title) helper used by both DownloadService and AutomaticSearchService, which brings DownloadService.cs back under 500 lines;
  • the helper always runs the primary search, even when the query is empty (falls back to [primaryQuery] when Expand() returns nothing);
  • the test class follows the conventions, with tests for the helper (including the empty-query case).

Feel free to take any of it.

@matheusfillipe
matheusfillipe force-pushed the 801-search-query-fallback branch from 854a58c to 332ac3e Compare October 14, 2026 15:31
@matheusfillipe

Copy link
Copy Markdown
Author

Thanks @Yoldark34, your fixes looked right to me. I rebased onto 1.3.11 and took the shared helper and the test conventions. One thing I did differently is the empty query: the helper always runs the primary search and only filters the title retries, so it needs no special case.

@Yoldark34

Copy link
Copy Markdown
Contributor

Thanks @matheusfillipe, filtering only the title retries is cleaner than my special case.

I tested your update (332ac3e) on 1.3.11:

  • merged alone onto v1.3.11-canary, the three tests that failed now pass;
  • in my build I replaced my local commits with yours, and the full backend suite and dotnet format --verify-no-changes are green;
  • on my test instance (French indexer, real downloads), Marche ou crève, credited by Audible to Stephen King (alias Richard Bachman), finds nothing with title + author, and the title-only retry finds it and it gets imported. Same on 1.3.10 earlier today.

I haven't done a full code review, but it fixes the problems I had.

@matheusfillipe

Copy link
Copy Markdown
Author

Thanks for testing it @Yoldark34.

@therobbiedavis

therobbiedavis commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

@matheusfillipe Thank you for your contribution! This addresses a real discovery problem, but expanding title retries feels like a band-aid over the underlying selection issue: Listenarr currently ranks releases by quality without first establishing that they match the requested audiobook.

I am very much aware of this behavior as it predates this PR. It's been on the back burner for a while because there are manual workarounds.

To fix this properly it's going to require a lot more scope.

I think we should structure the flow like this:

  1. Build the search context. Listenarr already builds a query from audiobook metadata. Retain the requested book’s identifiers, title variants, authors, known aliases, and edition requirements throughout selection.
  2. Query the indexers. Preserve the existing automatic-search indexer selection.
  3. Parse the releases. Listenarr already converts provider responses into search results. Extend this with book-specific parsing where identity evidence appears in the release name.
  4. Match candidates to the requested audiobook. This is the missing step. Define the acceptance contract for candidate matching: identifier precedence, title normalization, author aliases, equivalent editions, conflicting evidence, and treatment of missing or ambiguous information. Both automatic download paths should implement that same contract.
  5. Apply quality requirements and rank eligible candidates. Preserve Listenarr’s existing quality-profile scoring and rejection, applying it to candidates that passed identity matching.
  6. Try the next query when none qualify. Each title retry should pass through the same matching and quality checks, continuing when there are no eligible candidates.
  7. Validate and submit. Preserve the existing duplicate-download checks, trusted download-source validation, and history recording after client acceptance.

I propose recording the following candidate-matching contract in an ADR:

  • Parse identity evidence: extract audiobook identifiers, title, author, and edition details from provider metadata and recognizable release-name patterns (unfortunately there is no standard release-name patterns like shows/movies, but we can make reasonable assumptions).
  • Match identifiers first: accept identifiers linked to the requested audiobook or explicitly approved equivalent editions. Reject identifiers known to identify another work; contradictory identity evidence requires manual review.
  • Otherwise require title and author: match the complete normalized title or an approved title variant, together with a credited author or known author alias. Normalize case, punctuation, and spacing while preserving meaningful words and part numbers.
  • Check edition compatibility: apply explicit rules for language, abridgement, adaptations, and complete books versus individual parts.
  • Return matched, mismatched, or uncertain: only matched candidates proceed to automatic quality scoring and selection. Missing or ambiguous evidence remains available for manual selection; fuzzy similarity alone cannot authorize a grab.

[Side note: The quality scoring algorithm needs more tuning as well...]

Apply this contract to every query tier, including the original query. Continue to the next tier when no candidates pass both identity and quality requirements.

@matheusfillipe

Copy link
Copy Markdown
Author

Thanks @therobbiedavis

I am currently happy with this workaround for my personal instance. I understand your vision but I think it is far fetched for me and obviously for this PR alone. Feel free to close if this band-aid is not wished.

Yoldark34 added a commit to Yoldark34/Listenarr that referenced this pull request Oct 15, 2026
Revert of af27f9d, 275ebef and 50d1d5b (Listenarrs#825, author's version of
2026-10-14). The maintainer considers the title-only retry a band-aid
over release selection, and its author won't take it further: the PR
will most likely be closed. Automatic and interactive searches go back to
upstream behaviour (title + first author only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Yoldark34

Yoldark34 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Thanks @matheusfillipe, and @therobbiedavis for the detailed plan.

I've just opened #1054 (draft), which reworks the book searches: the rules for finding a book on Audible now live in one place in the backend (BookSearchRules, behind the API), and Add New, Library Import and the new Repair feature all go through them. They cover what counts as an ASIN, cleaning a folder or file name into a book name, normalizing titles (case, accents, punctuation, whole words, volume numbers), and checking that a result really fits before it is matched automatically.

That PR is about identifying the book on Audible, not about picking releases from indexers, so it doesn't fix the case handled here. But step 4 of your plan (matching candidates to the requested audiobook) needs the same kind of rules on the release side. So if this is wanted, I think the proper fix is best done after #1054, so it can reuse that unified backend search instead of adding another set of rules.

For reference, the case here comes from the author string: Audible credits Marche ou crève to "Stephen King (alias Richard Bachman)", and title + that author finds nothing on my indexers, while title + "Stephen King" finds the same releases as the title-only retry. That's the "known aliases" part of step 1.

EDIT : In fact modifying rules will not impact backend search refactoring, we should pursue the dev of improving matching and changing matching rules.

@Yoldark34

Copy link
Copy Markdown
Contributor

@therobbiedavis

Copy link
Copy Markdown
Collaborator

Should we close this PR in favor of #1072 Retry automatic search without the author when the full query returns nothing ?

Yes, I think that one needs less work and the OP already stated they were not interested in continuing to pursue the root cause fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants