feat(plex): lazy-enrich the full cast on info-page view (S1a)

The cheap section listing that drives the main sync only stores the top ~3 cast,
so any cast member below that was unfilterable (clicking them AND-emptied the
grid). Now the movie/show info fetch (/item, /show) — which already pulls the full
rich cast — persists it onto cast_names + people_text (so every displayed cast
member becomes filterable) and caches each headshot in the new plex_people table
(migration 0056). Idempotent (only grows a thinner stored set); best-effort (never
500s a read). Verified: 10 Cloverfield Lane 3->8 cast after viewing; plex_people
populated with photos. (Plex cast-explore S1a)
This commit is contained in:
2026-07-19 03:31:34 +02:00
parent d462834ed7
commit 0030f32a5d
3 changed files with 106 additions and 0 deletions
+17
View File
@@ -1129,6 +1129,23 @@ class PlexItem(Base, TimestampMixin, UpdatedAtMixin):
)
class PlexPerson(Base, TimestampMixin, UpdatedAtMixin):
"""A small cast/crew headshot cache, keyed by name, so person filter-chips (the cards for the
actors currently in the filter) can show a photo + count without a live per-card metadata fetch.
Populated opportunistically when an item's RICH metadata is fetched — the info-page view and the
periodic rich re-sync — since the cheap section listing that drives the main sync only carries the
top few cast. Rows whose name no longer appears in ANY item's cast_names/directors (a library
removal orphaned them) are pruned by the maintenance sweep, mirroring how Plex drops orphaned
metadata. The filterable cast lives in plex_items/plex_shows.cast_names (self-cleaning with the
row); this table is ONLY the headshot cache."""
__tablename__ = "plex_people"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(255), unique=True, index=True)
photo_thumb: Mapped[str | None] = mapped_column(Text) # proxied /person-image URL, or None
class PlexCollection(Base, TimestampMixin, UpdatedAtMixin):
"""A mirrored Plex collection (a grouping of movies or shows — franchises like Avatar, curated
sets like MCU, or auto/community lists like IMDb Top 250). Mirrored in full by the background