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
@@ -25,7 +25,7 @@ from app.models.credit import Credit
|
||||
from app.models.enums import MatchConfidence, MovieStatus, VideoType
|
||||
from app.models.genre import MovieGenre
|
||||
from app.models.keyword import MovieKeyword
|
||||
from app.models.movie import Movie, MovieRecommendation
|
||||
from app.models.movie import Movie, MovieAlternateTitle, MovieRecommendation
|
||||
from app.models.video import Video
|
||||
from app.providers.base import MetadataProvider
|
||||
from app.repositories import polymorphic
|
||||
@@ -51,6 +51,24 @@ async def _replace_movie_keywords(session: AsyncSession, movie_id: uuid.UUID, na
|
||||
session.add(MovieKeyword(movie_id=movie_id, keyword_id=keyword.id))
|
||||
|
||||
|
||||
async def _replace_movie_alternate_titles(
|
||||
session: AsyncSession, movie_id: uuid.UUID, alt_titles
|
||||
) -> None:
|
||||
await session.execute(
|
||||
delete(MovieAlternateTitle).where(MovieAlternateTitle.movie_id == movie_id)
|
||||
)
|
||||
for alt in alt_titles:
|
||||
country_code = None
|
||||
if alt.country_code:
|
||||
country = await refs.get_or_create_country(session, alt.country_code, alt.country_code)
|
||||
country_code = country.code
|
||||
session.add(
|
||||
MovieAlternateTitle(
|
||||
movie_id=movie_id, title=alt.title, country_code=country_code, type=alt.type
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def _replace_movie_companies(
|
||||
session: AsyncSession, movie_id: uuid.UUID, provider_id: uuid.UUID, companies
|
||||
) -> None:
|
||||
@@ -239,6 +257,7 @@ async def ingest_movie(
|
||||
|
||||
await _replace_movie_genres(session, movie.id, normalized.genres)
|
||||
await _replace_movie_keywords(session, movie.id, normalized.keywords)
|
||||
await _replace_movie_alternate_titles(session, movie.id, normalized.alternate_titles)
|
||||
await _replace_movie_companies(session, movie.id, tmdb_provider.id, normalized.companies)
|
||||
await _replace_movie_credits(session, movie.id, tmdb_provider.id, normalized.cast, normalized.crew)
|
||||
await polymorphic.sync_artwork(
|
||||
|
||||
@@ -25,7 +25,7 @@ from app.models.credit import Credit
|
||||
from app.models.enums import CompanyType, MatchConfidence, SeriesStatus, VideoType
|
||||
from app.models.genre import SeriesGenre
|
||||
from app.models.keyword import SeriesKeyword
|
||||
from app.models.tv import Series
|
||||
from app.models.tv import Series, SeriesAlternateTitle
|
||||
from app.models.video import Video
|
||||
from app.providers.base import MetadataProvider, ProviderNotFoundError
|
||||
from app.repositories import polymorphic, tv_repository
|
||||
@@ -70,6 +70,24 @@ async def _replace_series_keywords(
|
||||
session.add(SeriesKeyword(series_id=series_id, keyword_id=keyword.id))
|
||||
|
||||
|
||||
async def _replace_series_alternate_titles(
|
||||
session: AsyncSession, series_id: uuid.UUID, alt_titles
|
||||
) -> None:
|
||||
await session.execute(
|
||||
delete(SeriesAlternateTitle).where(SeriesAlternateTitle.series_id == series_id)
|
||||
)
|
||||
for alt in alt_titles:
|
||||
country_code = None
|
||||
if alt.country_code:
|
||||
country = await refs.get_or_create_country(session, alt.country_code, alt.country_code)
|
||||
country_code = country.code
|
||||
session.add(
|
||||
SeriesAlternateTitle(
|
||||
series_id=series_id, title=alt.title, country_code=country_code, type=alt.type
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def _replace_series_companies(
|
||||
session: AsyncSession,
|
||||
series_id: uuid.UUID,
|
||||
@@ -230,6 +248,7 @@ async def ingest_series(
|
||||
|
||||
await _replace_series_genres(session, series.id, normalized.genres)
|
||||
await _replace_series_keywords(session, series.id, normalized.keywords)
|
||||
await _replace_series_alternate_titles(session, series.id, normalized.alternate_titles)
|
||||
await _replace_series_companies(
|
||||
session, series.id, tmdb_provider.id, normalized.networks, normalized.companies
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user