feat(plex): episodes, taglines and genres in Hungarian from the HU overlay (E30 S1a)

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.
This commit is contained in:
2026-09-29 01:52:02 +02:00
parent 0f9ed7cdbf
commit 13d95ef70e
9 changed files with 301 additions and 28 deletions
+16 -1
View File
@@ -30,7 +30,9 @@ def _seed(db):
summary="English summary.",
summary_hu="Magyar összefoglaló.",
genres=["Drama"],
genres_hu=["Dráma"],
genres_hu=["Dráma", "Akció"],
tagline="English tagline.",
tagline_hu="Magyar mottó.",
rating=6.5,
imdb_rating=None,
year=2001,
@@ -102,12 +104,25 @@ def test_genre_filter_matches_active_language_vocabulary(db, monkeypatch, overri
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
+99 -1
View File
@@ -10,7 +10,8 @@ from sqlalchemy import func, select
import app.plex.sync as syncmod
from app import sysconfig
from app.models import PlexItem, PlexLibrary
from app.models import PlexItem, PlexLibrary, PlexShow
from app.plex.genres import hu_genre, hu_genres
from app.plex.sync import _apply_item, _canonical_guid, _sync_overlay
from app.plex.query import content_libs
@@ -244,3 +245,100 @@ def test_content_libs_excludes_overlay_libraries(db):
assert en_lib.id in movie_ids
assert overlay.id not in movie_ids # the HU overlay is never browsable
assert show_ids == [en_shows.id]
class _KindStub:
"""An overlay section listing per Plex type (2 = show, 4 = episode), like a HU TV section."""
def __init__(self, by_type: dict[int, list[dict]]):
self._by = by_type
def section_items(self, key, item_type, start, size):
items = self._by.get(item_type, [])
return items[start : start + size], len(items)
def test_a_show_overlay_writes_hungarian_episode_titles_and_summaries(db):
"""E30: the HU TV section lists every episode in Hungarian; they were never read, so a Hungarian
reader saw every episode title and summary in English."""
en_lib = PlexLibrary(plex_key="1", title="TV Shows", kind="show")
hu_lib = PlexLibrary(plex_key="9", title="Sorozatok", kind="show", metadata_lang="hu")
db.add_all([en_lib, hu_lib])
db.flush()
show = PlexShow(rating_key="s1", library_id=en_lib.id, title="3 Body Problem", guid="tmdb:10")
db.add(show)
db.flush()
ep = PlexItem(
rating_key="e1",
library_id=en_lib.id,
kind="episode",
show_id=show.id,
title="Countdown",
summary="EN.",
guid="tmdb:501",
)
db.add(ep)
db.commit()
stub = _KindStub(
{
syncmod._TYPE_SHOW: [_hu_movie("hs", "A 3-test-probléma", "HU.", [], "tmdb://10")],
syncmod._TYPE_EPISODE: [
_hu_movie("he", "Visszaszámlálás", "Magyar epizód.", [], "tmdb://501")
],
}
)
_sync_overlay(db, stub, hu_lib, en_lib.id, {})
db.commit()
db.refresh(ep)
db.refresh(show)
assert (ep.title_hu, ep.summary_hu) == ("Visszaszámlálás", "Magyar epizód.")
assert show.title_hu == "A 3-test-probléma"
def test_the_overlay_gives_every_row_one_hungarian_word_per_genre(db):
"""E30: Plex's HU agent mixes "Action" with "Dráma", and a title with no HU twin kept only its
English list — so the HU genre list offered "Drama" beside "Dráma"."""
en_lib = PlexLibrary(plex_key="4", title="Movies", kind="movie")
hu_lib = PlexLibrary(plex_key="9", title="Filmek", kind="movie", metadata_lang="hu")
db.add_all([en_lib, hu_lib])
db.flush()
twin = PlexItem(
rating_key="m1",
library_id=en_lib.id,
kind="movie",
title="Heat",
guid="tmdb:1",
genres=["Action", "Crime"],
)
lone = PlexItem(
rating_key="m2",
library_id=en_lib.id,
kind="movie",
title="Solo",
guid="tmdb:2",
genres=["Drama", "Science Fiction"],
)
db.add_all([twin, lone])
db.commit()
meta = _hu_movie(
"h1", "Szemtől szemben", "HU.", ["Action", "Bűnügyi", "Drama", "Dráma"], "tmdb://1"
)
meta["tagline"] = "Magyar mottó."
_sync_overlay(db, _StubPlex([meta]), hu_lib, en_lib.id, {})
db.commit()
db.refresh(twin)
db.refresh(lone)
assert twin.genres_hu == ["Akció", "Bűnügyi", "Dráma"]
assert twin.tagline_hu == "Magyar mottó."
assert lone.genres_hu == ["Dráma", "Sci-Fi"] # no twin: its own English list, in Hungarian
assert lone.tagline_hu is None
def test_the_genre_map_is_idempotent_and_keeps_an_unknown_word():
assert hu_genre("science fiction") == "Sci-Fi" # case-insensitive
assert hu_genre("Dráma") == "Dráma"
assert hu_genre("Space Opera") == "Space Opera" # unknown: shown as Plex gave it, never dropped
once = hu_genres(["Drama", "Action", "Dráma"])
assert once == ["Dráma", "Akció"]
assert hu_genres(once) == once
assert hu_genres(None) is None and hu_genres([]) is None