feat(i18n): the server's closed English vocabularies named in the reader's language (E30 S2)

- lib/vocab + the `vocab` locale area: TMDB crew jobs and departments, auto-tags (D1 A: the data
  stays English, the catalog is named at its one source, useTags), built-in download profiles,
  YouTube topics; held key-for-key to the backend's own lists by backendIds.contract.
- Countries by ISO code: TMDB parse stores {code, name}; rows stored before are coded from TMDB's
  own country list in one request (run_enrich); Intl names them, historic codes (YU, SU, XI…)
  from the catalog.
- Player tracks named from the language tag, forced/SDH flags and codec tail, not Plex's
  server-language displayTitle; no invented "Audio N" on the server.
- Download lifecycle notices (shared / expiring / expired / evicted) named from data; the share
  notice carries the title.
- Scheduler: the job result rides along as data and is named per key (dashboard + run notice).
- Invite status named; a render crash's notice no longer shows the engine's English message.
- Fix: YouTube links …/wiki/Humour, the tagger looked for "Humor" — Comedy never came from a topic.
This commit is contained in:
2026-09-29 21:21:19 +02:00
parent f6298d29af
commit f3a85916ec
50 changed files with 1475 additions and 94 deletions
+49
View File
@@ -352,3 +352,52 @@ def test_show_detail_lazy_fills_when_unenriched(db, monkeypatch, override_dep):
assert show.imdb_id == "tt0068646" # persisted for next time
assert show.people_enriched_at is not None
assert [c["name"] for c in show.full_cast] == ["Marlon Brando", "Al Pacino"]
def test_item_detail_names_tracks_from_their_language_not_plexs_title(
db, monkeypatch, override_dep
):
"""E30: Plex titles a track in the Plex SERVER's language ("English (AC3 5.1)", "magyar Forced",
"中文 (EAC3 Stereo)"), so a Hungarian reader got a mix. The route sends what the client names it
from instead — the language tag, the forced / SDH flags, the codec tail — keeping Plex's title
only as the fallback, and no invented English "Audio 2" for a track with neither."""
lib = PlexLibrary(plex_key="1", title="Movies", kind="movie", enabled=True)
db.add(lib)
db.flush()
db.add(PlexItem(rating_key="m1", library_id=lib.id, kind="movie", title="T"))
db.commit()
user = _user(db, "tracks@example.com")
db.commit()
streams = [
{"streamType": 2, "displayTitle": "English (AC3 5.1)", "languageTag": "en-US"},
{"streamType": 2, "displayTitle": "中文 (EAC3 Stereo)", "languageTag": "zh"},
{"streamType": 2},
{
"streamType": 3,
"displayTitle": "magyar Forced",
"languageTag": "hu",
"forced": True,
"codec": "srt",
},
{
"streamType": 3,
"displayTitle": "English SDH",
"languageTag": "en",
"hearingImpaired": True,
"codec": "srt",
},
]
meta = {**RICH_META, "Media": [{"Part": [{"Stream": streams}]}]}
monkeypatch.setattr(detail_routes, "PlexClient", lambda db: _StubClient(meta))
body = _get(db, user, monkeypatch, override_dep, "/api/plex/item/m1").json()
naming = ("label", "lang_tag", "forced", "hearing_impaired", "detail")
assert [tuple(a[k] for k in naming) for a in body["audio_streams"]] == [
("English (AC3 5.1)", "en-US", False, False, "AC3 5.1"),
("中文 (EAC3 Stereo)", "zh", False, False, "EAC3 Stereo"),
(None, None, False, False, None),
]
assert [tuple(s[k] for k in naming) for s in body["subtitle_streams"]] == [
("magyar Forced", "hu", True, False, None),
("English SDH", "en", False, True, None),
]