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
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:
co-authored by
Claude Sonnet 5
parent
e1a36ce227
commit
567b4ef068
@@ -24,6 +24,7 @@ from app.services.common import (
|
||||
pick_certification,
|
||||
primary_artwork_path,
|
||||
split_credits,
|
||||
to_alternate_title_out,
|
||||
to_images_out,
|
||||
to_release_date_out,
|
||||
to_video_out,
|
||||
@@ -53,6 +54,7 @@ async def get_movie_detail(session: AsyncSession, movie_aurora_id: str) -> Movie
|
||||
|
||||
genres = await movie_repository.get_movie_genres(session, movie_id)
|
||||
keywords = await movie_repository.get_movie_keywords(session, movie_id)
|
||||
alternate_titles = await movie_repository.get_movie_alternate_titles(session, movie_id)
|
||||
companies = await movie_repository.get_movie_companies(session, movie_id)
|
||||
credits_ = await polymorphic.get_credits(session, "movie", movie_id)
|
||||
artwork = await polymorphic.get_artwork(session, "movie", movie_id)
|
||||
@@ -104,6 +106,7 @@ async def get_movie_detail(session: AsyncSession, movie_aurora_id: str) -> Movie
|
||||
certification=pick_certification(release_dates),
|
||||
genres=[GenreOut(id=aurora_id("genre", str(g.id)), name=g.name) for g in genres],
|
||||
keywords=[KeywordOut(id=aurora_id("keyword", str(k.id)), name=k.name) for k in keywords],
|
||||
alternate_titles=[to_alternate_title_out(t) for t in alternate_titles],
|
||||
cast=cast,
|
||||
crew=crew,
|
||||
companies=company_out,
|
||||
@@ -193,6 +196,7 @@ async def list_movies(
|
||||
session: AsyncSession,
|
||||
*,
|
||||
genre_aurora_id: str | None,
|
||||
keyword_aurora_id: str | None,
|
||||
year: int | None,
|
||||
status: str | None,
|
||||
sort_by: str,
|
||||
@@ -207,6 +211,13 @@ async def list_movies(
|
||||
except ValueError as exc:
|
||||
raise InvalidMovieFilterError(f"invalid genre id: {genre_aurora_id!r}") from exc
|
||||
|
||||
keyword_id: uuid.UUID | None = None
|
||||
if keyword_aurora_id is not None:
|
||||
try:
|
||||
keyword_id = uuid.UUID(parse_aurora_id(keyword_aurora_id, expected_type="keyword"))
|
||||
except ValueError as exc:
|
||||
raise InvalidMovieFilterError(f"invalid keyword id: {keyword_aurora_id!r}") from exc
|
||||
|
||||
status_enum: MovieStatus | None = None
|
||||
if status is not None:
|
||||
try:
|
||||
@@ -217,6 +228,7 @@ async def list_movies(
|
||||
movies, total = await movie_repository.list_movies(
|
||||
session,
|
||||
genre_id=genre_id,
|
||||
keyword_id=keyword_id,
|
||||
year=year,
|
||||
status=status_enum,
|
||||
sort_by=sort_by,
|
||||
|
||||
Reference in New Issue
Block a user