diff --git a/backend/app/plex/cards.py b/backend/app/plex/cards.py
index 7e13a595..da24097e 100644
--- a/backend/app/plex/cards.py
+++ b/backend/app/plex/cards.py
@@ -14,12 +14,21 @@ def _art_url(rating_key: str, art_key: str | None) -> str | None:
return f"/api/plex/image/{rating_key}?variant=art" if art_key else None
+# Card hover-overview: a short synopsis for the reveal panel, trimmed so a strip/related row of cards
+# stays a few hundred bytes each rather than carrying full synopses. (These non-grid card paths serve
+# the EN summary/rating; the main grid coalesces the HU twin in browse.unified_library.)
+def _card_summary(summary: str | None) -> str | None:
+ return (summary or "")[:300] or None
+
+
def movie_card(it: PlexItem, st: PlexState | None) -> dict:
return {
"id": it.rating_key,
"type": "movie",
"title": it.title,
"year": it.year,
+ "rating": it.rating,
+ "summary": _card_summary(it.summary),
"duration_seconds": it.duration_s,
"thumb": f"/api/plex/image/{it.rating_key}",
"art": _art_url(it.rating_key, it.art_key),
@@ -35,6 +44,8 @@ def show_card(sh: PlexShow, status: str = "new") -> dict:
"type": "show",
"title": sh.title,
"year": sh.year,
+ "rating": sh.rating,
+ "summary": _card_summary(sh.summary),
"thumb": f"/api/plex/image/{sh.rating_key}",
"art": _art_url(sh.rating_key, sh.art_key),
"season_count": sh.child_count,
diff --git a/backend/app/plex/query.py b/backend/app/plex/query.py
index ca3b31ce..56d0efe6 100644
--- a/backend/app/plex/query.py
+++ b/backend/app/plex/query.py
@@ -29,6 +29,11 @@ def title_col(model, lang: str):
return func.coalesce(model.title_hu, model.title) if lang == "hu" else model.title
+def summary_col(model, lang: str):
+ """DISPLAY summary, HU-coalesced (EN fallback) — the card hover-overview + info page read this."""
+ return func.coalesce(model.summary_hu, model.summary) if lang == "hu" else model.summary
+
+
def genres_col(model, lang: str):
# type_coerce so the JSONB comparator (`.contains` / `@>`, GIN-backed) survives the coalesce.
if lang == "hu":
diff --git a/backend/app/routes/plex/browse.py b/backend/app/routes/plex/browse.py
index f333ffb9..5fa702c2 100644
--- a/backend/app/routes/plex/browse.py
+++ b/backend/app/routes/plex/browse.py
@@ -38,6 +38,7 @@ from app.plex.query import (
movie_status_case,
show_status_case,
split_csv,
+ summary_col,
title_col,
vector_col,
vector_match,
@@ -130,6 +131,8 @@ def unified_library(
title_col(PlexItem, lang).label("title"),
PlexItem.year.label("year"),
PlexItem.rating.label("rating"),
+ # Truncated so the card hover-overview costs a few hundred bytes, not the full synopsis.
+ func.left(summary_col(PlexItem, lang), 300).label("summary"),
PlexItem.added_at.label("added_at"),
PlexItem.originally_available_at.label("rel"),
PlexItem.duration_s.label("duration_s"),
@@ -170,6 +173,7 @@ def unified_library(
title_col(PlexShow, lang).label("title"),
PlexShow.year.label("year"),
PlexShow.rating.label("rating"),
+ func.left(summary_col(PlexShow, lang), 300).label("summary"),
PlexShow.added_at.label("added_at"),
PlexShow.originally_available_at.label("rel"),
cast(null(), Integer).label("duration_s"),
@@ -227,6 +231,8 @@ def unified_library(
"type": "movie",
"title": r.title,
"year": r.year,
+ "rating": r.rating,
+ "summary": r.summary,
"duration_seconds": r.duration_s,
"thumb": f"/api/plex/image/{r.rk}",
"playable": r.playable,
@@ -241,6 +247,8 @@ def unified_library(
"type": "show",
"title": r.title,
"year": r.year,
+ "rating": r.rating,
+ "summary": r.summary,
"thumb": f"/api/plex/image/{r.rk}",
"season_count": r.season_count,
"status": r.status,
diff --git a/frontend/src/components/plexCards.dom.test.tsx b/frontend/src/components/plexCards.dom.test.tsx
index 20261d36..f631aba8 100644
--- a/frontend/src/components/plexCards.dom.test.tsx
+++ b/frontend/src/components/plexCards.dom.test.tsx
@@ -61,6 +61,26 @@ describe("PlexPosterCard a11y", () => {
);
expect(screen.getByRole("button", { name: "plex.markUnwatched" })).toBeTruthy();
});
+
+ it("reveals the synopsis + rating on the hover scrim when the card carries them", () => {
+ render(
+
+ {card.summary} +
+ )} +