Add keyword browsing/filtering and expose alternate titles
CI / lint (push) Canceled after 0s
CI / typecheck (push) Canceled after 0s
CI / unit-tests (push) Canceled after 0s
CI / integration-tests (push) Canceled after 0s
CI / container-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s

Keywords were ingested and shown read-only on detail pages, but had no
directory (GET /keywords) or filter param -- the same gap genres had
before today. Mirrors the genre browse pattern exactly: repository,
service, route, plus a `keyword` filter on GET /movies and GET /series.

Alternate/translated titles ("Also Known As") were normalized down to
bare title strings and never written to MovieAlternateTitle/
SeriesAlternateTitle at all. Normalizer now captures country_code + type
per TMDb's actual shape; ingestion writes them; movie/series detail now
expose an alternate_titles list.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
NixReaper
2026-09-06 04:40:32 -05:00
co-authored by Claude Sonnet 5
parent e1a36ce227
commit 567b4ef068
23 changed files with 548 additions and 17 deletions
+21 -2
View File
@@ -156,7 +156,9 @@ def test_normalize_movie_maps_genres_and_keywords():
movie = normalize_movie(FAKE_MOVIE)
assert movie.genres == ["Action", "Science Fiction"]
assert movie.keywords == ["dystopia"]
assert movie.alternate_titles == ["Matrix"]
assert len(movie.alternate_titles) == 1
assert movie.alternate_titles[0].title == "Matrix"
assert movie.alternate_titles[0].country_code == "US"
def test_normalize_movie_maps_cast_and_crew():
@@ -225,6 +227,21 @@ def test_normalize_movie_maps_collection_and_recommendations():
assert movie.recommendation_external_ids == ["604"]
def test_normalize_movie_alternate_titles_capture_type_and_skip_titleless_entries():
with_type = {
**FAKE_MOVIE,
"alternative_titles": {
"titles": [
{"title": "Matrix", "iso_3166_1": "US", "type": "working title"},
{"iso_3166_1": "FR"}, # no "title" key at all -- must be skipped
]
},
}
movie = normalize_movie(with_type)
assert len(movie.alternate_titles) == 1
assert movie.alternate_titles[0].type == "working title"
def test_normalize_movie_maps_release_dates_and_certification():
movie = normalize_movie(FAKE_MOVIE)
assert len(movie.release_dates) == 4
@@ -431,7 +448,9 @@ def test_normalize_series_keywords_and_alt_titles_use_tv_shaped_keys():
# for /movie — a normalizer bug here would silently return empty lists.
series = normalize_series(FAKE_SERIES)
assert series.keywords == ["drug dealer"]
assert series.alternate_titles == ["Breaking Bad"]
assert len(series.alternate_titles) == 1
assert series.alternate_titles[0].title == "Breaking Bad"
assert series.alternate_titles[0].country_code == "US"
def test_normalize_series_keeps_season_zero_specials():