"""E5 S6: HU-overlay language serving. When ?lang=hu, the unified library, facets, genre filter and detail endpoints serve the Hungarian `*_hu` columns (falling back to EN where a row has no HU twin); ?lang=en (the default) serves English. Also covers the imdb_rating IMDb-only / audience-score split. DB lane (`db` fixture) — skipped without Postgres. """ from datetime import datetime, timezone from fastapi.testclient import TestClient import app.state as state from app.auth import current_user from app.db import get_db from app.main import app from app.models import PlexItem, PlexLibrary, User def _seed(db): """One EN movie library with a single movie that has both EN and HU metadata, plus a second movie that is EN-only (no HU twin) to prove the coalesce fallback.""" lib = PlexLibrary(plex_key="1", title="Movies", kind="movie", enabled=True) db.add(lib) db.flush() m1 = PlexItem( rating_key="m1", library_id=lib.id, kind="movie", title="English Title", title_hu="Magyar Cím", summary="English summary.", summary_hu="Magyar összefoglaló.", genres=["Drama"], genres_hu=["Dráma"], rating=6.5, imdb_rating=None, year=2001, added_at=datetime(2024, 1, 1, tzinfo=timezone.utc), people_enriched_at=datetime(2024, 1, 1, tzinfo=timezone.utc), # serve from row, skip live enrich ) m2 = PlexItem( rating_key="m2", library_id=lib.id, kind="movie", title="EN Only", genres=["Comedy"], # no HU twin year=2002, added_at=datetime(2024, 1, 2, tzinfo=timezone.utc), people_enriched_at=datetime(2024, 1, 2, tzinfo=timezone.utc), ) db.add_all([m1, m2]) user = User(email="plexlang@example.com") db.add(user) db.commit() return user def _get(db, user, monkeypatch, path): monkeypatch.setattr(state, "_configured_cache", True) # the request gate 503s an unconfigured app app.dependency_overrides[get_db] = lambda: db app.dependency_overrides[current_user] = lambda: user try: client = TestClient(app) # no context manager: skip lifespan return client.get(path) finally: app.dependency_overrides.clear() def _titles(resp): return {i["title"] for i in resp.json()["items"]} def test_library_serves_active_language_titles(db, monkeypatch): user = _seed(db) hu = _get(db, user, monkeypatch, "/api/plex/library?scope=movie&lang=hu") en = _get(db, user, monkeypatch, "/api/plex/library?scope=movie&lang=en") # HU serves the twin's Hungarian title; the EN-only row falls back to its English title. assert _titles(hu) == {"Magyar Cím", "EN Only"} assert _titles(en) == {"English Title", "EN Only"} def test_facets_vocabulary_is_language_specific(db, monkeypatch): user = _seed(db) hu = _get(db, user, monkeypatch, "/api/plex/facets?scope=movie&lang=hu") en = _get(db, user, monkeypatch, "/api/plex/facets?scope=movie&lang=en") hu_genres = {g["value"] for g in hu.json()["genres"]} en_genres = {g["value"] for g in en.json()["genres"]} assert "Dráma" in hu_genres and "Drama" not in hu_genres assert "Drama" in en_genres and "Dráma" not in en_genres def test_genre_filter_matches_active_language_vocabulary(db, monkeypatch): user = _seed(db) # The HU genre chip filters the HU column; the same string against the EN column matches nothing. hit = _get(db, user, monkeypatch, "/api/plex/library?scope=movie&lang=hu&genres=Dráma") miss = _get(db, user, monkeypatch, "/api/plex/library?scope=movie&lang=en&genres=Dráma") assert _titles(hit) == {"Magyar Cím"} assert miss.json()["items"] == [] def test_item_detail_language_and_rating_split(db, monkeypatch): user = _seed(db) resp = _get(db, user, monkeypatch, "/api/plex/item/m1?lang=hu") body = resp.json() assert body["title"] == "Magyar Cím" assert body["summary"] == "Magyar összefoglaló." # imdb_rating is IMDb-only (None here); the audience score is served separately as `rating`. assert body["imdb_rating"] is None assert body["rating"] == 6.5 def test_hu_search_still_finds_en_only_titles(db, monkeypatch): user = _seed(db) # m2 ("EN Only") has no HU twin, so search_vector_hu carries no title tokens for it. HU-mode search # must still match it via the EN vector (vector_match's union) — findable by its English title. resp = _get(db, user, monkeypatch, "/api/plex/library?scope=movie&lang=hu&q=Only") assert "EN Only" in _titles(resp) def test_rating_filter_prefers_imdb_over_audience(db, monkeypatch): lib = PlexLibrary(plex_key="1", title="Movies", kind="movie", enabled=True) db.add(lib) db.flush() # imdb 8.0 but audience 4.0 → a rating_min of 7 must MATCH (filter the displayed best score, # IMDb preferred), where filtering the raw audience column (4.0) would wrongly exclude it. db.add(PlexItem( rating_key="r1", library_id=lib.id, kind="movie", title="High IMDb", imdb_rating=8.0, rating=4.0, year=2001, added_at=datetime(2024, 1, 1, tzinfo=timezone.utc), people_enriched_at=datetime(2024, 1, 1, tzinfo=timezone.utc), )) user = User(email="rating@example.com") db.add(user) db.commit() hit = _get(db, user, monkeypatch, "/api/plex/library?scope=movie&rating_min=7") assert "High IMDb" in _titles(hit) miss = _get(db, user, monkeypatch, "/api/plex/library?scope=movie&rating_min=9") assert "High IMDb" not in _titles(miss)