The HTTP files browse, detail, people, collections and _shared do no database work of their own now. New plex/queries.py (the rows a page shows, a user's watch state through userscope), plex/service.py (the info pages' enrichment, a collection's editable flag, the row kept after a failed follow-up read, the person bio's background fetch; none commits), plex/library.py (the unified browse feed, its search and facets) and plex/collections.py (a collection's source, editability, card, certificate and member order). Every watch-state join in the moved code names its owner through owned_by. Pins 354 -> 178 in 4 files; basedpyright baseline 132 -> 118.
82 lines
3.5 KiB
Python
82 lines
3.5 KiB
Python
"""Plex's writes for the HTTP layer, one function per use case. None of them commits: the handler
|
|
does, so a page that fails to save an enrichment still renders, and a Plex write and its local
|
|
mirror land together.
|
|
|
|
The rest of the mirror's writes stay with the sync (`plex.sync`): a collection's targeted re-sync
|
|
after a write-back, its local cleanup after a delete.
|
|
"""
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app import logs
|
|
from app.db import SessionLocal
|
|
from app.plex import detail as plex_detail
|
|
from app.plex import people as plex_people
|
|
from app.plex import tmdb as plex_tmdb
|
|
from app.plex.lookups import by_rating_key
|
|
from app.plex.models import PlexCollection, PlexItem, PlexLibrary, PlexPerson, PlexShow
|
|
|
|
log = logs.get_logger(__name__)
|
|
|
|
|
|
def enrich_show(db: Session, sh: PlexShow, meta: dict) -> None:
|
|
"""Fill a not-yet-enriched show from its live metadata: the full cast (filterable), IMDb and
|
|
tagline, stamped so later views serve from the row."""
|
|
plex_people.enrich_row_people(db, sh, plex_people.cast_from_meta(meta))
|
|
plex_detail.apply_rich_detail(sh, meta)
|
|
sh.people_enriched_at = datetime.now(timezone.utc)
|
|
|
|
|
|
def enrich_movie(db: Session, it: PlexItem, meta: dict) -> None:
|
|
"""The same for a movie. The listing sync stored only its top ~3 cast; the live metadata
|
|
carries all of them."""
|
|
cast = plex_people.cast_from_meta(meta)
|
|
if cast:
|
|
plex_people.enrich_row_people(db, it, cast)
|
|
plex_detail.apply_rich_detail(it, meta)
|
|
it.people_enriched_at = datetime.now(timezone.utc)
|
|
|
|
|
|
def set_collection_editable(col: PlexCollection, editable: bool) -> None:
|
|
col.editable = editable
|
|
|
|
|
|
def keep_created_collection(
|
|
db: Session, lib: PlexLibrary, rating_key: str, title: str, seed: str
|
|
) -> None:
|
|
"""A collection Plex made, whose follow-up read failed: its row is kept, editable. The full sync
|
|
preserves `editable` but creates a missing row read-only, so the collection would drop out of
|
|
every "add to" list; and the duplicate-name check reads these rows, so a retry of the same name
|
|
would make a second one on Plex. Plex made it with exactly the seed in it, so the seed's row says
|
|
so too — otherwise the title showed unticked in the collection it was just added to, and the
|
|
collection empty, until that sync."""
|
|
db.add(
|
|
PlexCollection(
|
|
rating_key=rating_key, library_id=lib.id, title=title, editable=True, child_count=1
|
|
)
|
|
)
|
|
Model = PlexItem if lib.kind == "movie" else PlexShow
|
|
if row := by_rating_key(db, Model, seed):
|
|
row.collection_keys = list(dict.fromkeys([*(row.collection_keys or []), rating_key]))
|
|
db.flush()
|
|
|
|
|
|
def enrich_person_bg(person_id: int) -> None:
|
|
"""Fetch + persist one person's TMDB bio OFF the request path — a FastAPI background task that runs
|
|
AFTER the response is sent, so the outbound TMDB call never sits on the serve latency (the module's
|
|
"no live TMDB call at serve time" invariant). The request's session is already closed by then, so
|
|
open a fresh one. Best-effort: a TMDB failure just leaves `tmdb_enriched_at` NULL to retry on the
|
|
next open, and the bio lands from the row by then."""
|
|
db = SessionLocal()
|
|
try:
|
|
person = db.get(PlexPerson, person_id)
|
|
if person is not None:
|
|
plex_tmdb.enrich_person(db, person)
|
|
except Exception: # noqa: BLE001 — background best-effort; never surfaces to a user
|
|
db.rollback()
|
|
log.warning("background person bio enrich failed for id=%s", person_id, exc_info=True)
|
|
finally:
|
|
db.close()
|