The HU TV section lists every episode with its Hungarian title and summary, but the overlay read only movies and shows, so every episode stayed English. It now overlays the episodes too, and the HU tagline (new tagline_hu column, served on ?lang=hu). Plex's HU agent returns a mixed genre vocabulary (Action beside Dráma), and a title with no HU twin kept its English list, so the HU genre list showed Drama and Dráma. plex/genres.py maps every genre word to one Hungarian word; the overlay writes it into genres_hu for every row, and a HU genre filter is read through the same map, so a saved filter still holding Action keeps matching.
165 lines
6.5 KiB
Python
165 lines
6.5 KiB
Python
"""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", "Akció"],
|
|
tagline="English tagline.",
|
|
tagline_hu="Magyar mottó.",
|
|
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, override_dep, path):
|
|
monkeypatch.setattr(
|
|
state, "_configured_cache", True
|
|
) # the request gate 503s an unconfigured app
|
|
override_dep(get_db, db.info["request"])
|
|
override_dep(current_user, lambda: user)
|
|
client = TestClient(app) # no context manager: skip lifespan
|
|
return client.get(path)
|
|
|
|
|
|
def _titles(resp):
|
|
return {i["title"] for i in resp.json()["items"]}
|
|
|
|
|
|
def test_library_serves_active_language_titles(db, monkeypatch, override_dep):
|
|
user = _seed(db)
|
|
hu = _get(db, user, monkeypatch, override_dep, "/api/plex/library?scope=movie&lang=hu")
|
|
en = _get(db, user, monkeypatch, override_dep, "/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, override_dep):
|
|
user = _seed(db)
|
|
hu = _get(db, user, monkeypatch, override_dep, "/api/plex/facets?scope=movie&lang=hu")
|
|
en = _get(db, user, monkeypatch, override_dep, "/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, override_dep):
|
|
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, override_dep, "/api/plex/library?scope=movie&lang=hu&genres=Dráma"
|
|
)
|
|
miss = _get(
|
|
db, user, monkeypatch, override_dep, "/api/plex/library?scope=movie&lang=en&genres=Dráma"
|
|
)
|
|
assert _titles(hit) == {"Magyar Cím"}
|
|
assert miss.json()["items"] == []
|
|
|
|
|
|
def test_a_genre_filter_saved_in_english_still_matches_in_hungarian(db, monkeypatch, override_dep):
|
|
"""E30: the HU column holds one Hungarian word per genre. A filter saved while the HU list still
|
|
offered "Action" is read through the same map, so it finds the "Akció" title instead of nothing."""
|
|
user = _seed(db)
|
|
resp = _get(
|
|
db, user, monkeypatch, override_dep, "/api/plex/library?scope=movie&lang=hu&genres=Action"
|
|
)
|
|
assert _titles(resp) == {"Magyar Cím"}
|
|
|
|
|
|
def test_item_detail_language_and_rating_split(db, monkeypatch, override_dep):
|
|
user = _seed(db)
|
|
resp = _get(db, user, monkeypatch, override_dep, "/api/plex/item/m1?lang=hu")
|
|
body = resp.json()
|
|
assert body["title"] == "Magyar Cím"
|
|
assert body["summary"] == "Magyar összefoglaló."
|
|
assert body["tagline"] == "Magyar mottó." # E30: the HU overlay's tagline
|
|
en = _get(db, user, monkeypatch, override_dep, "/api/plex/item/m1").json()
|
|
assert en["tagline"] == "English tagline."
|
|
# 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, override_dep):
|
|
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, override_dep, "/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, override_dep):
|
|
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, override_dep, "/api/plex/library?scope=movie&rating_min=7")
|
|
assert "High IMDb" in _titles(hit)
|
|
miss = _get(db, user, monkeypatch, override_dep, "/api/plex/library?scope=movie&rating_min=9")
|
|
assert "High IMDb" not in _titles(miss)
|