Skip to content

feat(indexing): emit and accept TVDB ids so Sonarr can match by id - #69

Merged
ChrisonSimtian merged 1 commit into
mainfrom
feat/arr-tvdb-matching
Jul 28, 2026
Merged

feat(indexing): emit and accept TVDB ids so Sonarr can match by id#69
ChrisonSimtian merged 1 commit into
mainfrom
feat/arr-tvdb-matching

Conversation

@ChrisonSimtian

Copy link
Copy Markdown
Contributor

PR 1 of the matching work. Sonarr previously had to identify every release by parsing our title string against Mediathek naming — the exact problem MediathekArr and RundfunkArr pour most of their effort into. A tvdbid attribute short-circuits it: Sonarr trusts the id over the string.

What changed

  • Release carries TvdbId, projected from Show.TvdbId by the Mapperly mapper.
  • NewznabXml emits <newznab:attr name="tvdbid"> when the show is mapped, and nothing when it isn't — a wrong id is far worse than none, since Sonarr trusts the id over the title and would silently attach releases to the wrong series.
  • caps advertises supportedParams="q,tvdbid,season,ep". This is the part that's easy to miss: Sonarr reads caps and only sends what we advertise, so without listing tvdbid it would keep doing title-only searches no matter what the endpoint accepts.
  • The endpoint binds tvdbid; a search by id answers from IEpisodeRepository.GetByTvdbIdAsync instead of re-parsing titles.

Fallback behaviour is deliberate

An id we haven't mapped is our gap, not proof the show is absent. So an unknown id falls through to the title search when Sonarr also sent one; with no title it returns empty rather than inventing a match.

Two corrections to my own earlier claims

season and episode were already being emitted. I'd said "no tvdbid, no season, no episode" when I first read the code — wrong on two of three. Only tvdbid was missing.

Show.TvdbId is still populated by nothing, so today every release goes out without an id and observable behaviour is unchanged. This is the plumbing that makes PR 3 (show mapping) worth having. I verified both directions so the unmapped case is known-good rather than assumed.

Verified against a running host

Seeded a mapped show (extra 3, tvdb 255986 — a real id from the research) and an unmapped one (Panorama):

Request Result
t=caps supportedParams="q,tvdbid,season,ep"
q=extra 3 (mapped) item carries tvdbid = 255986
q=Panorama (unmapped) item carries no tvdbid attr at all
tvdbid=255986 1 item, answered by id
tvdbid=999999 (unmapped, no title) 0 items
tvdbid=999999&q=Panorama 1 item — and the right show
q= / no params title search and RSS feed unchanged

Tests: App 117 / Arch 11 / Infra 102 green, 0 warnings.

Research recorded in the plan

The plan now carries the matching research, since it changes how PR 3 should be built:

  • Why the names differ: TVDB's primary title is often English, but it stores German translations and aliases and its search indexes them. So don't compare primary titles — query TVDB's search with the German title.
  • The keyless trick: Wikidata P4835 maps German title (label or alias) → TVDB id, with broadcaster for disambiguation. Measured live: 16.3% coverage (ZDF 14.6%, Das Erste 15.3%, KiKA 48.5%). Good first pass, not a complete answer.
  • Two gotchas the data surfaced: Die Biene Maja has two TVDB ids (1975 TV Asahi vs 2013 ZDF) so disambiguation is mandatory; and ARD is a federation, so extra 3's network is NDR, not "Das Erste" — filtering on Das Erste would silently miss it.
  • Conclusion: we don't have to mimic MediathekArr/RundfunkArr wholesale, but a manual tail is unavoidable. The layering shrinks it rather than removing it.

PR 3 will use TvdbClient (Chrison-dev/TvdbApi) rather than a hand-rolled client.

Plan: docs/plans/2026-07-28 - sonarr-radarr-integration.md

🤖 Generated with Claude Code

…follow-up)

PR 1 of the Sonarr/Radarr matching work. Sonarr previously had to identify every
release by parsing our title string against Mediathek naming — the exact problem
MediathekArr and RundfunkArr spend most of their effort on. A tvdbid attribute
short-circuits it: Sonarr trusts the id over the string.

- Release carries TvdbId, projected from Show.TvdbId by the Mapperly mapper.
- NewznabXml emits <newznab:attr name="tvdbid"> when the show is mapped, and nothing
  when it is not — a wrong id would be far worse than none, since Sonarr trusts the id
  over the title and would silently attach releases to the wrong series.
- caps advertises supportedParams="q,tvdbid,season,ep". This matters: Sonarr reads caps
  and only sends what we advertise, so without listing tvdbid it would keep falling back
  to title-only searches no matter what we accept.
- The endpoint binds tvdbid; SearchReleasesQuery carries it; a search by id answers from
  IEpisodeRepository.GetByTvdbIdAsync rather than re-parsing titles.

Fallback behaviour is deliberate. An id we have not mapped is *our* gap, not proof the
show is absent, so an unknown id falls through to the title search when Sonarr also sent
one. With no title it returns empty rather than inventing a match.

Correcting my own earlier claim: season and episode attributes were already being
emitted. Only tvdbid was missing.

Note Show.TvdbId is still populated by nothing, so today every release is emitted without
an id and behaviour is unchanged — this is the plumbing that makes PR 3 (show mapping)
worth having. Verified both directions so the unmapped case is known-good, not assumed.

Verified against a running host with a mapped show (extra 3, tvdb 255986 — a real id
found during the research) and an unmapped one (Panorama):

  caps                                  -> supportedParams="q,tvdbid,season,ep"
  q=extra 3        (mapped)             -> item carries tvdbid = 255986
  q=Panorama       (unmapped)           -> item carries no tvdbid attr at all
  tvdbid=255986                         -> 1 item, answered by id
  tvdbid=999999    (unmapped, no title) -> 0 items
  tvdbid=999999&q=Panorama              -> 1 item, and the *right* show
  q= / no params                        -> title search and RSS feed unchanged

Tests: App 117 / Arch 11 / Infra 102 green, 0 warnings.

Plan: docs/plans/2026-07-28 - sonarr-radarr-integration.md — which also records the
matching research: TVDB stores German titles as translations/aliases (its search indexes
them), and Wikidata's P4835 offers a keyless title->tvdbid bridge that covers only 16.3%
of German public-TV series, so a manual tail is unavoidable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ChrisonSimtian
ChrisonSimtian merged commit e83076f into main Jul 28, 2026
1 check passed
@ChrisonSimtian
ChrisonSimtian deleted the feat/arr-tvdb-matching branch July 28, 2026 09:21
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.

1 participant