Build and publish / Test and build (darwin) (push) Successful in 2m3s
Build and publish / Test and build (linux) (push) Successful in 2m45s
Build and publish / Test and build (windows) (push) Successful in 3m13s
Build and publish / Build and publish Docker image (push) Successful in 2m30s
Ombi's v2 Search/tv/{tvdbId} route is a TMDB-keyed alias despite its parameter name, so read_media details and write_request_create season expansion resolved the wrong series for TVDB ids (Gitea issue #1). Repoint tvdb to the legacy v1 Search/tv/info route, label theMovieDbId by origin route (tvdb on TVMaze-backed v1 results, tmdb on the v2 engine) and emit the new tvmaze identifier namespace from seriesId.
7.0 KiB
7.0 KiB
Phase 01 — TV Identifier Namespaces
Objective
Fix Gitea issue #1 end-to-end in code and tests: read_media details must resolve the correct series for a TVDB id, TVDB season expansion must read the same show, and every TV identifier must be labelled by the namespace it actually carries rather than by the upstream field name.
Prerequisites
- Phase 00 complete (this file and the index exist).
- Source files to mutate:
internal/tools/media.go,internal/tools/project.go,internal/tools/search.go,internal/tools/discover.go,internal/tools/library.go,internal/tools/requestswrite.go,internal/tools/families.go,internal/integration_test/mockombi_test.go,internal/integration_test/contract_test.go,internal/integration_test/live_test.go. - Root cause (verified against Ombi-app/Ombi
develop+ live 4.53.10):GET /api/v2/Search/tv/{tvdbId}andGET /api/v2/Search/tv/moviedb/{moviedbid}are aliases: both callTvSearchEngineV2.GetShowInformation→_movieApi.GetTVInfo(TMDB). ThetvdbIdparameter name is vestigial — both routes are TMDB-keyed. TMDB 75150 is Passfire: The Series, exactly the wrong-show result observed in the issue.- v1 TV search (
/api/v1/Search/tv/{term}, used byread_search) is TVMaze-backed:TvProfilemapsId ← show.externals.thetvdbandSeriesId ← show.id(TVMaze), andProcessResultsetsTheMovieDbId = Id. SotheMovieDbIdin v1 TV results is the TVDB id (Button Moon: TVDB 75150 per api.tvmaze.com), mislabeledtmdbin our projection. - The only real TVDB details route is legacy
GET /api/v1/Search/tv/info/{tvdbId}→TvSearchEngine.GetShowInformation→TvMazeApi.ShowLookupByTheTvDbId, returningSearchTvShowViewModelwithseasonRequests/episodes— sufficient forprojectFullTVandexpandSeasonNumbers. - The same bug existed in
write_request_createTVseasonmode:expandSeasonNumbersread the TMDB-alias v2 route forprovider:tvdb, expanding the wrong show's episodes. - v2-sourced TV data (discover browse,
by_request, multi-search) IS TMDB-keyed — keep thetmdblabel there. The same view-model field name carries different namespaces per origin; relabeling must be per call site.
Specification
Mutations
internal/tools/media.go—mediaDetailstv case:tvdb→GET /api/v1/Search/tv/info/{id}(was/api/v2/Search/tv/{id}), projection hinttvdb.tmdb→ keep/api/v2/Search/tv/moviedb/{id}, projection hinttmdb.mediaByRequesttv keeps the v2tv/requestroute with hinttmdb.
internal/tools/project.go— identifier origin fix:projectSearchMedia(m, media, tvIDNS)gains the per-call-site namespace hint fortheMovieDbIdon TV.- TV branch:
theMovieDbIdunder the hinted namespace;theTvDbId→tvdbandimdbId→imdbunchanged;seriesId→tvmazewhen present. projectFullTV(m, tvIDNS)forwards the hint and only overwritesGenres/Creditswhen the richergenres/castobject arrays are present — the v1 model carriesgenrestrings already handled byprojectSearchMedia.
- Call-site hints:
search.gosearchTexttv →tvdb(v1 TVMaze);media.godetailstvdb→tvdb,tmdb/by_request→tmdb;discover.gobrowse tv (v2, TMDB) →tmdb;library.gorecent tv →tmdbretained pending verification; multi-search tvidstaystmdb(v2 engine, Verify). internal/tools/requestswrite.go—expandSeasonNumbers:provider==tvdbreadsGET /api/v1/Search/tv/info/{id};tmdbkeeps the moviedb route. TheseasonRequests[].episodes[].episodeNumbershape matches the existing decode.internal/tools/families.go—Identifier.Namespacedoc comment gainstvmaze.
Test mutations
mockombi_test.go— registerGET /api/v1/Search/tv/info/{id}(TVMaze-shape fixture:id/theMovieDbId=tvdb 81189,seriesId=tvmaze 169,genrestring list,seasonRequests) andGET /api/v1/Search/tv/{term}(search-hit fixture withseriesId). The v2Search/tv/{id}handler stays registered so the suite can assert it is never called.contract_test.go— new assertions:read_media details provider:tvdbhits/api/v1/Search/tv/info/81189exactly once and/api/v2/Search/tv/zero times; emitstvdb/tvmaze/imdb, notmdb; preservesgenrestrings and season structure.write_request_createtvseasonmode withprovider:tvdbreads the v1 info route once, never the v2 alias, and posts expandedseasons[].episodesto/api/v1/Request/tv.read_searchtv emitstvdb+tvmaze+imdband notmdblabel.
live_test.go—TestLiveSearchThenDetailsbecomes the issue-#1 regression: search "Button Moon", take the emittedtvdbid,details provider:tvdbmust return the same title (skips withoutOMBI_URL).TestLiveSeasonExpansionswitches toprovider:tvdbsince search no longer emitstmdbfor TV.
Target artefacts
internal/tools/media.go— tvdb details repoint to the v1 info route; per-provider projection hints.internal/tools/project.go—tvIDNShint,seriesId→tvmaze,projectFullTVgenre/credit guard.internal/tools/search.go—searchTexttv hinttvdb; remaining call sites passtmdb.internal/tools/discover.go— all v2 call sites passtmdb.internal/tools/library.go— recent tv keepstmdbwith an unverified-namespace comment.internal/tools/requestswrite.go— tvdb season expansion via v1 info route.internal/tools/families.go— namespace doc comment.internal/integration_test/{mockombi_test,contract_test,live_test}.go— fixtures and assertions above.
Verification gates
read_media details {media:tv, provider:tvdb, id:81189}records exactly oneGET /api/v1/Search/tv/info/81189and zeroGET /api/v2/Search/tv/calls.- TV
seasonexpansion withprovider:tvdbrecords one v1 info GET, zero v2 tv GETs, and posts explicitseasons[].episodesto/api/v1/Request/tv. read_searchtv emitstvdb/tvmaze/imdb, notmdbidentifier.- v1-details projection keeps
genre-sourced genres andseasonRequestsseasons. CGO_ENABLED=0 go build ./...,go test ./...,go test -tags integration ./internal/integration_test/,go vet ./...,gofmt -l .clean.- Live
read_media details {media:tv, provider:tvdb, id:75150}returns Button Moon.
Evidence labels
- Documented — the route aliasing and field mappings are verified against upstream controller/engine/profile source and a live 4.53.10 instance (TMDB 75150 = Passfire: The Series; TVDB 75150 = Button Moon per api.tvmaze.com).
- Design — emitting
theMovieDbIdunder a call-site-supplied namespace and the newtvmazenamespace are intentional MCP contract decisions; the same upstream field name is never trusted. - Verify —
read_library recenttvtheMovieDbIdnamespace (kepttmdb), multi-search tvidnamespace (kepttmdb),by_requestexternalProviderIdnamespace, and pre-TVMaze Ombi version drift. Consolidated indocs/schema/06-verification.md.