feat(plex): S5a HU-overlay backend — schema, guid, overlay sync
Adds the storage + sync for the Hungarian-metadata overlay (the browsable EN sections gain HU
twin fields written from a paired HU section, matched by guid; no browsable HU rows).
Schema (2 migrations, ADD-only; run before the first HU sync while *_hu is NULL so the generated
column build is trivial):
- 0063: plex_libraries.metadata_lang ('en' default) + self-FK overlay_of.
- 0064: plex_items/plex_shows.guid (indexed) + title_hu/summary_hu/genres_hu (+ GIN) + a STORED
generated search_vector_hu mirroring the EN vector (title_hu A / people_text B / summary_hu C) + GIN.
Sync:
- includeGuids=1 on section_items so the canonical guid rides the cheap listing.
- _canonical_guid(meta) (tmdb > imdb > tvdb) captured onto every EN row in _apply_item/_sync_shows.
- Two-pass sync(): pass 1 mirrors browsable (non-overlay) sections; pass 2 reads plex_overlay_map
('huKey:enKey', new sysconfig), designates each HU section (metadata_lang='hu' + overlay_of), and
_sync_overlay writes title_hu/summary_hu/genres_hu onto the guid-matched EN rows.
Browse: _content_libs now excludes overlay libraries (overlay_of is None); the unified_library and
facets inline library partitions fold into it, and list_libraries/collections exclude overlays too.
Tests: DB-lane coverage of the overlay write (matched vs unmatched rows, no browsable HU rows, the
generated search_vector_hu populates), the guid parse, and the browse exclusion. Full suite 272
passed; migrations verified reversible (upgrade→downgrade→upgrade). S5b (persist the live detail
fields + serve item/show detail from DB) is the follow-up.
This commit is contained in:
@@ -82,9 +82,12 @@ def _field_recheck(model, field: str, tsq):
|
||||
def list_libraries(
|
||||
user: User = Depends(current_user), db: Session = Depends(get_db)
|
||||
) -> dict:
|
||||
"""The mirrored libraries the user can browse (drives the Plex scope selector)."""
|
||||
"""The mirrored libraries the user can browse (drives the Plex scope selector). HU overlay
|
||||
libraries are excluded — they're not browsable, they only feed the EN twin's Hungarian metadata."""
|
||||
libs = db.execute(
|
||||
select(PlexLibrary).order_by(PlexLibrary.kind.desc(), PlexLibrary.title)
|
||||
select(PlexLibrary)
|
||||
.where(PlexLibrary.overlay_of.is_(None))
|
||||
.order_by(PlexLibrary.kind.desc(), PlexLibrary.title)
|
||||
).scalars().all()
|
||||
out = []
|
||||
for lib in libs:
|
||||
@@ -291,11 +294,7 @@ def unified_library(
|
||||
episodes come back in a separate `episodes` list (grouped result — the 'Episodes' section)."""
|
||||
offset = max(0, offset)
|
||||
p = f.as_dict()
|
||||
libs = db.execute(
|
||||
select(PlexLibrary).where(PlexLibrary.enabled.is_(True))
|
||||
).scalars().all()
|
||||
movie_lib_ids = [lb.id for lb in libs if lb.kind == "movie"]
|
||||
show_lib_ids = [lb.id for lb in libs if lb.kind == "show"]
|
||||
movie_lib_ids, show_lib_ids = _content_libs(db)
|
||||
want_movies = scope in ("movie", "both") and bool(movie_lib_ids)
|
||||
want_shows = scope in ("show", "both") and bool(show_lib_ids)
|
||||
|
||||
@@ -531,17 +530,9 @@ def facets(
|
||||
"duration_min": None,
|
||||
"duration_max": None,
|
||||
}
|
||||
libs = db.execute(
|
||||
select(PlexLibrary).where(PlexLibrary.enabled.is_(True))
|
||||
).scalars().all()
|
||||
movie_ids = (
|
||||
[lb.id for lb in libs if lb.kind == "movie"]
|
||||
if scope in ("movie", "both")
|
||||
else []
|
||||
)
|
||||
show_ids = (
|
||||
[lb.id for lb in libs if lb.kind == "show"] if scope in ("show", "both") else []
|
||||
)
|
||||
all_movie_ids, all_show_ids = _content_libs(db)
|
||||
movie_ids = all_movie_ids if scope in ("movie", "both") else []
|
||||
show_ids = all_show_ids if scope in ("show", "both") else []
|
||||
if not movie_ids and not show_ids:
|
||||
return empty
|
||||
p = f.as_dict()
|
||||
@@ -758,7 +749,9 @@ def collections(
|
||||
else:
|
||||
enabled_ids = list(
|
||||
db.execute(
|
||||
select(PlexLibrary.id).where(PlexLibrary.enabled.is_(True))
|
||||
select(PlexLibrary.id).where(
|
||||
PlexLibrary.enabled.is_(True), PlexLibrary.overlay_of.is_(None)
|
||||
)
|
||||
).scalars()
|
||||
)
|
||||
if not enabled_ids:
|
||||
@@ -1545,11 +1538,13 @@ def _rich_meta(meta: dict) -> dict:
|
||||
|
||||
|
||||
def _content_libs(db: Session) -> tuple[list[int], list[int]]:
|
||||
"""The enabled content libraries, partitioned into (movie_lib_ids, show_lib_ids) — the single
|
||||
source of the browsable-library scope shared by people_cards and the person filmography endpoint.
|
||||
(S5 will extend this to exclude HU overlay libraries and fold in the browse/facets partition sites.)"""
|
||||
"""The BROWSABLE content libraries, partitioned into (movie_lib_ids, show_lib_ids) — the single
|
||||
source of the browse scope. Excludes HU overlay libraries (`overlay_of` set): those are never
|
||||
browsed on their own, they only lend their Hungarian metadata to the EN twin's rows (E5 S5)."""
|
||||
libs = db.execute(
|
||||
select(PlexLibrary).where(PlexLibrary.enabled.is_(True))
|
||||
select(PlexLibrary).where(
|
||||
PlexLibrary.enabled.is_(True), PlexLibrary.overlay_of.is_(None)
|
||||
)
|
||||
).scalars().all()
|
||||
movie_lib_ids = [lb.id for lb in libs if lb.kind == "movie"]
|
||||
show_lib_ids = [lb.id for lb in libs if lb.kind == "show"]
|
||||
|
||||
Reference in New Issue
Block a user