Skip to content

fix(prowlarr-import): build proxy URLs from the base Prowlarr answered on - #876

Open
m4bard wants to merge 1 commit into
Listenarrs:canaryfrom
m4bard:fix/bug1-prowlarr-urlbase
Open

fix(prowlarr-import): build proxy URLs from the base Prowlarr answered on#876
m4bard wants to merge 1 commit into
Listenarrs:canaryfrom
m4bard:fix/bug1-prowlarr-urlbase

Conversation

@m4bard

@m4bard m4bard commented Aug 22, 2026

Copy link
Copy Markdown

Fixes #875.

Importing indexers from a Prowlarr instance that runs under a URL base stored every proxy URL without that base:

stored by Listenarr: http://prowlarr.example:9696/4/api
Prowlarr serves at:  http://prowlarr.example:9696/prowlarr/4/api

The discovery request to /api/v1/indexer is redirected onto the base and Listenarr follows it, so the import reports success. Each indexer's URL was then composed from the address that was typed in rather than the one that answered.

OutboundRequestSecurity.SendWithValidatedRedirectsAsync already returns the final URI, and ProwlarrIndexerImportWorkflow.SendValidatedAsync was discarding it (var (response, _) = ...). This keeps it, strips the discovery path off the end, and uses the remainder as the base for BuildProxyUrl and for the tag lookup.

Change

  • ProwlarrImportUrlPlanner.ResolveBaseUrlFromDiscovery is new: given the requested base, the URI the discovery call finished on, and the discovery path, return the base Prowlarr actually answered on. It falls back to the requested base when there was no redirect or when the final path does not end in the discovery path.
  • ProwlarrIndexerImportWorkflow.SendValidatedAsync returns the final URI instead of dropping it, and FetchProwlarrIndexersAsync passes it back with the payload.
  • ImportAsync resolves the effective base once and uses it for both BuildProxyUrl and TryFetchProwlarrTagMapAsync, and logs at Information when the two differ.

46 added, 13 removed across two files. The address the user typed is still what gets saved to the Prowlarr import settings; the redirect only affects how proxy URLs are composed, so a re-import recomputes the same thing rather than quietly rewriting what the user entered.

Diagram

stateDiagram-v2
    direction TB
    [*] --> Requested: user supplies a Prowlarr address
    Requested --> Discovery: GET {base}/api/v1/indexer
    Discovery --> Answered: 2xx, possibly after a redirect
    Discovery --> Failed: unreachable or non-2xx
    Answered --> Resolved: strip /api/v1/indexer off the URI that answered
    Resolved --> Stored: BuildProxyUrl(resolved base, indexer id)
    Failed --> [*]
    Stored --> [*]
Loading

Before this change the Resolved step did not exist and Stored read straight from Requested. Those are the same value whenever Prowlarr sits at the root, which is presumably why it went unnoticed.

Tests

tests/Features/Api/Features/Prowlarr/ProwlarrImportUrlBaseTests.cs, two cases:

  • discovery redirected onto /prowlarr: the stored URL is http://prowlarr.example:9696/prowlarr/4/api, and the redirected discovery request is asserted to have happened.
  • no redirect: the stored URL is http://prowlarr.example:9696/4/api, unchanged from today.

Control: with both production files reverted, the first case fails with http://prowlarr.example:9696/4/api against an expected http://prowlarr.example:9696/prowlarr/4/api, and the second still passes. Full suite is green.

…d on

Importing indexers from a Prowlarr instance that runs under a URL base stored
every proxy URL without that base. The discovery request to /api/v1/indexer is
redirected onto the base and Listenarr follows it, so the import reports success,
but each indexer's URL was composed from the address that was typed in rather
than the one that answered.

SendWithValidatedRedirectsAsync already returns the final URI and the workflow
discarded it. Keep it, strip the discovery path off the end, and use what is
left as the base for BuildProxyUrl and for the tag lookup.
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.

Prowlarr import stores indexer URLs without Prowlarr's URL base, so every imported indexer points at a path Prowlarr does not serve

1 participant