fix(plex): address S4 review — cap filmography, dedupe toggle, scroll guard, tests
- Efficiency: cap each person section at _PERSON_SECTION_MAX (200) so a prolific person can't return an unbounded list the client mounts a card per row for. - Reuse: extract the optimistic watch-toggle (flip → persist → resync) into a shared toggleWatchState helper; the grid and the person page each supply their own cache updater. - Correctness (scroll): onOpenPerson now stashes infoScrollRef ONLY when leaving an info page (not from a show/grid context), and a jumped-to info page resets it — so a stale offset can't wrongly restore a fresh info page. - Test-coverage: add PlexPersonView.dom.test.tsx (export CastStrip + PlexPersonView) covering the cast-row rewiring (open-person vs filter fallback) and the person page's sections + filter + empty state. The name-as-identity finding is inherent to Plex cast carrying no per-person id (PlexPerson is name-keyed too); documented in the endpoint docstring, not structurally fixable in S4.
This commit is contained in:
@@ -1607,6 +1607,12 @@ def people_cards(
|
||||
return {"people": out}
|
||||
|
||||
|
||||
# Cap each filmography section — a prolific person shouldn't return an unbounded list the client then
|
||||
# mounts a card per row for (the grid paginates at PAGE; this page renders all at once). Ample for a
|
||||
# personal library; the most-recent titles win via the year-desc order.
|
||||
_PERSON_SECTION_MAX = 200
|
||||
|
||||
|
||||
@router.get("/person/{name}")
|
||||
def person_detail(
|
||||
name: str,
|
||||
@@ -1615,8 +1621,9 @@ def person_detail(
|
||||
) -> dict:
|
||||
"""One cast/crew member's filmography: their cached headshot + the movies and shows (in the enabled
|
||||
libraries) whose cast OR directors include this name — the inverse of the cast-name → library-filter
|
||||
link. The name string is the identity key (Plex cast carries no stable per-person id). An unknown
|
||||
name simply returns empty sections."""
|
||||
link. The name string is the identity key (Plex cast carries no stable per-person id), so distinct
|
||||
people who share a name share a page. Each section is capped at _PERSON_SECTION_MAX. An unknown name
|
||||
simply returns empty sections."""
|
||||
photo = db.scalar(select(PlexPerson.photo_thumb).where(PlexPerson.name == name))
|
||||
movie_lib_ids, show_lib_ids = _content_libs(db)
|
||||
|
||||
@@ -1633,6 +1640,7 @@ def person_detail(
|
||||
),
|
||||
)
|
||||
.order_by(PlexItem.year.desc().nullslast(), func.lower(PlexItem.title))
|
||||
.limit(_PERSON_SECTION_MAX)
|
||||
).scalars().all()
|
||||
item_ids = [it.id for it in items]
|
||||
states = {
|
||||
@@ -1658,6 +1666,7 @@ def person_detail(
|
||||
),
|
||||
)
|
||||
.order_by(PlexShow.year.desc().nullslast(), func.lower(PlexShow.title))
|
||||
.limit(_PERSON_SECTION_MAX)
|
||||
).scalars().all()
|
||||
statuses = rollup.state_map(db, user.id, [s.id for s in show_rows])
|
||||
shows = [_show_card(sh, statuses.get(sh.id, "new")) for sh in show_rows]
|
||||
|
||||
Reference in New Issue
Block a user