fix(plex): show-library collections get montage art too (A3)
The collection browse-tile montage queried only movie members, so show-library collections (IMDb Popular, TMDb Trending, … in the TV library) rendered as bare colour tiles. Union the art from PlexShow members as well (a collection lives in one library, so exactly one side has art); fall back to the collection's own poster, then the colour hash. Runtime stays movie-only (shows have no single duration). Verified live: every collection now shows a montage (0 art-less tiles, was ~all the show collections). Gate: backend ruff clean, 5 collections tests (+ a show-collection art assertion).
This commit is contained in:
@@ -11,6 +11,7 @@ from app.models import (
|
||||
PlexCollection,
|
||||
PlexItem,
|
||||
PlexLibrary,
|
||||
PlexShow,
|
||||
User,
|
||||
)
|
||||
from app.plex import sync as plex_sync
|
||||
@@ -95,17 +96,25 @@ def collections(
|
||||
func.lower(PlexCollection.title),
|
||||
)
|
||||
).scalars().all()
|
||||
# A montage of the top films per tile + the collection's total runtime (color hash + no-runtime is
|
||||
# the client fallback for show-only / empty collections). Two grouped queries over the movie libs.
|
||||
movie_ids, _show_ids = _content_libs(db)
|
||||
# A montage of the top titles per tile + the collection's total runtime. Art unions MOVIE and SHOW
|
||||
# members (a collection lives in one library, so exactly one side has art) — a show collection would
|
||||
# otherwise render blank; the collection's own poster is the next fallback, then the colour hash.
|
||||
# Runtime is movie-only (shows have no single duration).
|
||||
movie_ids, show_ids = _content_libs(db)
|
||||
keys = [c.rating_key for c in rows]
|
||||
art = top_art_keys(db, PlexItem, movie_ids, PlexItem.collection_keys, keys, per=2)
|
||||
art_m = top_art_keys(db, PlexItem, movie_ids, PlexItem.collection_keys, keys, per=2)
|
||||
art_s = top_art_keys(db, PlexShow, show_ids, PlexShow.collection_keys, keys, per=2)
|
||||
runtime = runtime_by_key(db, PlexItem, movie_ids, PlexItem.collection_keys, keys)
|
||||
|
||||
def _art(c: PlexCollection) -> list[str]:
|
||||
member = art_m.get(c.rating_key) or art_s.get(c.rating_key)
|
||||
return member or ([c.rating_key] if c.thumb_key else [])
|
||||
|
||||
return {
|
||||
"collections": [
|
||||
{
|
||||
**_collection_card(c),
|
||||
"art": art.get(c.rating_key, []),
|
||||
"art": _art(c),
|
||||
"total_runtime_s": runtime.get(c.rating_key, 0),
|
||||
}
|
||||
for c in rows
|
||||
|
||||
@@ -10,7 +10,7 @@ import app.state as state
|
||||
from app.auth import current_user
|
||||
from app.db import get_db
|
||||
from app.main import app
|
||||
from app.models import PlexCollection, PlexItem, PlexLibrary, User
|
||||
from app.models import PlexCollection, PlexItem, PlexLibrary, PlexShow, User
|
||||
|
||||
|
||||
def _seed(db):
|
||||
@@ -92,3 +92,25 @@ def test_collection_cards_carry_montage_art_and_total_runtime(db, monkeypatch):
|
||||
if c["id"] == "A")
|
||||
assert card["art"] == ["m2", "m1"] # best-rated first (m2 9.0 > m1 8.0)
|
||||
assert card["total_runtime_s"] == 5400 # 3600 + 1800
|
||||
|
||||
|
||||
def test_show_collection_gets_montage_art_from_shows(db, monkeypatch):
|
||||
# A show-library collection must get its montage from PlexShow members (else it renders blank) — the
|
||||
# A3 fix that unions movie + show art. Runtime stays 0 (shows have no single duration).
|
||||
lib = PlexLibrary(plex_key="2", title="Shows", kind="show", enabled=True)
|
||||
db.add(lib)
|
||||
db.flush()
|
||||
db.add(PlexCollection(rating_key="S", library_id=lib.id, title="Show Coll", child_count=2))
|
||||
db.add_all([
|
||||
PlexShow(rating_key="s1", library_id=lib.id, title="S1", collection_keys=["S"], rating=7.0,
|
||||
added_at=datetime(2024, 1, 1, tzinfo=timezone.utc)),
|
||||
PlexShow(rating_key="s2", library_id=lib.id, title="S2", collection_keys=["S"], rating=9.0,
|
||||
added_at=datetime(2024, 1, 2, tzinfo=timezone.utc)),
|
||||
])
|
||||
user = User(email="showcoll@example.com")
|
||||
db.add(user)
|
||||
db.commit()
|
||||
card = next(c for c in _get(db, user, monkeypatch, "/api/plex/collections").json()["collections"]
|
||||
if c["id"] == "S")
|
||||
assert card["art"] == ["s2", "s1"] # show members, best-rated first
|
||||
assert card["total_runtime_s"] == 0
|
||||
|
||||
Reference in New Issue
Block a user