Skip to content

feat: move to TheIntroDB API v4 and ask by TVDb id first - #9

Merged
Pasithea0 merged 2 commits into
mainfrom
v4
Oct 26, 2026
Merged

Pasithea0 merged 2 commits into
mainfrom
v4

Conversation

@Pasithea0

@Pasithea0 Pasithea0 commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Move to TheIntroDB API v4, and ask by TVDb id first

Fixes #8

Why

Two things were wrong with the v3 default, and the issue names both.

The base URL. /v2 and /v3 are frozen at GET /media only. /user/stats is read from the same base, so the key check and the stats view hit /v3/user/stats — a 404 today, which lands in the default: branch and surfaces as theintrodb: user stats returned HTTP 404: Cannot GET /v3/user/stats instead of a key verdict. Measured on the shipped default, with a key configured:

before  (v3):  theintrodb: user stats returned HTTP 404: Cannot GET /v3/user/stats
after   (v4):  TheIntroDB rejected the API key (HTTP 401): {"error":"Invalid or expired token"}

The second is what ValidateKey is for. The first blamed the URL on the key.

The identity. buildQuery preferred tmdb_id, and that is not just a preference: the season and episode travel with the id, and the API reads them in the numbering of the id that was sent. Plex numbers episodes the TVDb way by default, so a request carrying TMDb numbers asks about a different episode — or about one that does not exist. Measured just now against v4:

request answer
tmdb_id=615&season=12&episode=1 404 media not found for provided season/episode
tvdb_id=73871&season=12&episode=1 404 no submissions for this media

The second resolved the episode and has no timings for it yet; the first could not find the episode at all. That is the failure the issue describes as silent: a run caches the first as a miss and never asks again. A movie still resolves by its own id (tvdb_id=247 → 200).

What changed

  • internal/config/config.go — default BaseURL https://api.theintrodb.org/v3 → /v4.
  • internal/model/model.go — ExternalIDs.IDs() lists the ids in the API's own precedence (tvdb, tmdb, imdb) with the query parameter each is sent under; LookupKey takes its provider from that one list.
  • internal/tidb/lookup.go — buildQuery takes the first id from IDs() instead of switching on the fields. One list feeds the request and the cache key, so they cannot drift apart.
  • README.md, docs/architecture.md, docs/troubleshooting.md, internal/cli/commands.go, internal/tui/model.go — the text said TMDb metadata was recommended and to set the agent to TMDb. It now says a TVDb id is what lookups are made with, and why.

Tests

  • internal/model/model_test.go — TestLookupKeyUsesTVDbFirst, TestIDsInRequestOrder: the key and the request order, the movie key, the no-id case, and an empty IMDb string.
  • internal/tidb/client_test.go — TestLookupAsksByTVDbFirst: an item carrying both ids asks by tvdb_id and carries no tmdb_id.
  • The existing fallback test still passes — no TVDb id still asks by tmdb_id, then imdb_id — which is what keeps libraries whose shows have no TVDb id working.
  • RED: reordering IDs() back to the old preference fails 3 of them:
--- FAIL: TestLookupKeyUsesTVDbFirst ... LookupKey = "tmdb:615:7:1", want "tvdb:73871:7:1"
--- FAIL: TestIDsInRequestOrder ... IDs()[0] = {tmdb tmdb_id 615}, want {tvdb tvdb_id 73871}
--- FAIL: TestLookupAsksByTVDbFirst ... Key = "tmdb:615:7:1"; tvdb_id = "", want 73871
  • go build ./..., go vet ./... and go test -count=1 ./... all pass. The first commit on this branch keeps its own RED/GREEN for the base URL (TestDefaultBaseURLIsNotAFrozenSurface, TestUserStatsOnAFrozenSurfaceIsNotAKeyVerdict).

Cache note

LookupKey's provider is part of the ledger key, so an item carrying more than one id gets a new key and is asked again after the upgrade. That is the point — its old entries were answered under a different identity. An item with a single id is unaffected.

Not in this PR

  • mapping= (DVD / alternate / absolute display orders). v4 honours it only on a tvdb_id lookup, so this change is its prerequisite. What it still needs is Plex's per-show Episode ordering value; this tool reads the library database, and that setting is not in the tables it reads. Guessing it would remap shows that are already correct, so it is left out rather than approximated. With IDs() in place, sending a known mapping is a small follow-up.
  • /v4/data. Nothing here reads media details.
  • Version bump. Left to you, as before.

/v2 and /v3 are frozen at GET /media and answer nothing else, so the v3
default made part of this client talk to a surface that cannot answer:
/user/stats -- the key check and the stats view -- returned 404, which
surfaced as "theintrodb: user stats returned HTTP 404: Cannot GET
/v3/user/stats" instead of a verdict about the key.

Measured live through the shipped default (TestLiveLookup builds its
config from config.Default()): with the v3 default, ValidateKey fails
with that 404; with v4, it fails with the real verdict -- 401 "Invalid
or expired token". A media lookup through the same default answers 200,
and the remaining-quota header is read exactly as before.

Two tests pin it: the default must not name a frozen surface, and a 404
from /user/stats must stay a non-terminal KindStatus that is never
worded as a rejected key.

save_test.go keeps its v3 fixture on purpose: now that v3 is no longer
the default, it proves a non-default base URL round-trips.

Not here: buildQuery's tmdb_id preference. ExternalIDs.LookupKey
derives the ledger cache key from the same provider order by design, so
flipping it moves every key and invalidates the existing ledger -- its
own decision, and it goes together with mapping=, which v4 honours only
for tvdb_id lookups.
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f4c59d49-1bee-453e-8479-bb48a94a8455
Commits

Reviewing files that changed from the base of the PR and between bed7636 and e10fe63.

Files selected for processing: 3
  • internal/config/config.go
  • internal/config/config_test.go
  • internal/tidb/client_test.go

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The default TheIntroDB base URL changes from v3 to v4. Tests check the default URL and verify that a 404 response from /user/stats is classified as a nonterminal status error, not an API-key rejection.

Changes: TheIntroDB API version

Layer / File(s) Summary
Set and validate the v4 API default
internal/config/config.go, internal/config/config_test.go, internal/tidb/client_test.go
The default base URL changes to v4. Tests check the default URL and verify that a /user/stats 404 is a nonterminal status error, not an API-key rejection.

Priority: Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: Minimal · up to e10fe

The v4 fallback is wired through existing request paths without disrupting configured overrides, so no merge-blocking risk is established.

Pre-merge checks: Passed 2 · Failed 3

Failed Failed checks: 3 warnings

Check name Status Explanation Resolution
Linked Issues check Warning Issue #8 requires the API v4 update. The PR changes config.Default().TheIntroDB.BaseURL to https://api.theintrodb.org/v4 and adds regression tests for the default and /user/stats 404 behavior. I… Update buildQuery to prefer tvdb_id. Keep the ledger cache-key derivation consistent with the query preference, and add or update automated tests for the query and cache-key behavior.
Docstring Coverage Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check Warning The title correctly identifies the API v4 change, but it also claims that lookups ask by TVDb ID first. The pull request does not change ID preference. Remove the unsupported clause. Use a title such as "feat: move to TheIntroDB API v4".
Passed Passed checks: 2 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Out of Scope Changes check Passed The changed files support Issue #8. The default URL change implements the API v4 objective. The config and client tests protect the default URL and the non-terminal /user/stats status behavior. No u…
Full details: Out of Scope Changes check

Explanation

The changed files support Issue #8. The default URL change implements the API v4 objective. The config and client tests protect the default URL and the non-terminal /user/stats status behavior. No unrelated change is demonstrated.

Full details: Linked Issues check

Explanation

Issue #8 requires the API v4 update. The PR changes config.Default().TheIntroDB.BaseURL to https://api.theintrodb.org/v4 and adds regression tests for the default and /user/stats 404 behavior. Issue #8 also lists the buildQuery ID preference as part of the v4 work. The PR leaves buildQuery preferring tmdb_id, so that coding requirement remains unmet. mapping= is optional in the issue and does not affect this result.

Resolution

Update buildQuery to prefer tvdb_id. Keep the ledger cache-key derivation consistent with the query preference, and add or update automated tests for the query and cache-key behavior.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The API reads an episode's season and episode in the numbering of the id the
request carries. Plex numbers episodes the TVDb way by default, so asking with
tmdb_id hands the API numbers from a different list: for a show whose TMDb list
differs (Futurama, tmdb 615), v4 answers "media not found for provided
season/episode" where the same episode resolves by tvdb_id.

ExternalIDs.IDs() now lists the ids in the API's own precedence, tvdb then tmdb
then imdb, and buildQuery takes the first one; LookupKey takes its provider from
the same list so the cache key still describes the request that was made. Items
with no TVDb id keep asking with tmdb_id as before.

Also updates the README, architecture and troubleshooting text, and the CLI and
TUI hints, which told users TMDb metadata was preferred -- the opposite of what
the code now does and what the API needs.
@Pasithea0 Pasithea0 changed the title fix(config): point the default base URL at TheIntroDB API v4 feat: move to TheIntroDB API v4 and ask by TVDb id first Oct 26, 2026
@Pasithea0
Pasithea0 merged commit f501708 into main Oct 26, 2026
5 checks passed
@Pasithea0
Pasithea0 deleted the v4 branch October 26, 2026 15:08
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.

Update to API v4

1 participant