mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
feat(portal): show each season's own poster beside the season tabs (#1628)
Series detail pages now render the selected season's poster as a season
cover next to the season tabs and description, and the fullscreen episode
panel shows the same poster as a season strip above its tabs.
Resolution is TMDB-first, like the show artwork merge: the lazy season
enrichment stores `/tv/{id}/season/{n}` `poster_path` as a w342 URL in
`tmdb_season_posters` (Xtream) or `StalkerSeriesTmdbSeasonsService.posters()`
(Stalker), under the same write-only-if-changed convergence guard as the
season overview. Xtream falls back to the provider's `seasons[].cover_big`/
`cover` when it is an http(s) URL other than the show poster, because panels
repeat the show poster on every season. Stalker is TMDB-only.
The cover column is not rendered for one-season items, seasons without a
poster, or a failed image, so every fallback is today's markup. It is sized
by a new `--season-cover-width` token (96/120/144px per Settings.coverSize).
The hero poster never follows the season.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
43c1ceac16
commit
7790e68147
36 files changed
+1119
-102
No files matched your search
@@ -278,6 +278,23 @@ episode" chip appears when the playing episode is outside the opened
|
||||
season. Season descriptions come from `get_series_info` seasons (Xtream)
|
||||
or `TmdbEnrichmentService.getSeason` (Stalker).
|
||||
|
||||
The tabs and description sit in a **season card** with an optional cover
|
||||
column: the selected season's own poster (`seasonPosters` input, keyed like
|
||||
`seasonDescriptions`; TMDB season poster first, provider `seasons[].cover_big`
|
||||
next — see "Season/Episode Enrichment" in `tmdb-metadata-enrichment.md`).
|
||||
The column is sized by `--season-cover-width` (96 / 120 / 144px for
|
||||
`Settings.coverSize` small / medium / large, `apps/web/src/_cover-size.scss`;
|
||||
medium matches the About block's poster) and is not rendered at all — the
|
||||
card collapses to one column and the tabs render exactly as before — when
|
||||
the selected season has no poster, when the item has a single season (that
|
||||
poster is the show poster a few hundred pixels below the hero), or when the
|
||||
image request failed. The hero poster never follows the season: the show
|
||||
keeps its identity element, the season gets its own picture next to its own
|
||||
text. The fullscreen episode panel shows the same poster as a compact season
|
||||
strip (poster, season name, episode count) above its season tabs, under the
|
||||
same gates, from `PortalInlinePlayerComponent.seasonPosters` through
|
||||
`buildFullscreenEpisodePanelSeasons`.
|
||||
|
||||
### Manual watched toggle for movies
|
||||
|
||||
Movies carry the same manual "watched" affordance as episodes, in the
|
||||
|
||||
@@ -244,7 +244,10 @@ Movie and series covers render in three surfaces: the catalog grid
|
||||
recent card (`app-content-card`, same lib) and the dashboard rails. All of
|
||||
them size from the `--cover-grid-min-width` / `--cover-rail-width` /
|
||||
`--cover-gap` tokens that `Settings.coverSize` writes onto `<html>` as
|
||||
`data-cover-size` (`apps/web/src/_cover-size.scss`).
|
||||
`data-cover-size` (`apps/web/src/_cover-size.scss`). The same file carries
|
||||
`--season-cover-width` (96 / 120 / 144px) for the season cover beside the
|
||||
season tabs on series detail pages; medium equals the About block's 120px
|
||||
poster so browse and watch share one secondary-poster size.
|
||||
|
||||
### Posters-only wall
|
||||
|
||||
|
||||
@@ -248,6 +248,25 @@ routinely fill it with a bare cover-image URL —
|
||||
`sanitizeProviderOverview` (`@iptvnator/shared/interfaces`) treats a
|
||||
URL-only value as absent, and the stored TMDB overview fills the gap.
|
||||
|
||||
The same payload's `poster_path` — every TMDB season has its own poster,
|
||||
distinct from the show poster on most shows — is stored as a full `w342`
|
||||
URL (`tmdbSeasonPosterUrl`) in `tmdb_season_posters[seasonKey]` beside the
|
||||
overview, under the same write-only-if-changed convergence guard. Stalker
|
||||
keeps it in `StalkerSeriesTmdbSeasonsService.posters(tmdbId)` next to
|
||||
`descriptions(tmdbId)`, dropped together with the entry when a replacement
|
||||
fetch fails. Season posters resolve **TMDB-first**, like the show artwork
|
||||
merge (`prefer(tmdbPoster, provider)`): `buildSeasonPosters`
|
||||
(`libs/portal/xtream/feature/src/lib/serial-details/season-posters.util.ts`)
|
||||
takes the stored TMDB poster and falls back to the provider's
|
||||
`seasons[].cover_big`/`cover` from `get_series_info`, accepted only as a
|
||||
trimmed http(s) URL that differs from the show poster because panels repeat
|
||||
it on every season. Stalker has no provider season art, so it is TMDB-only.
|
||||
The detail views render the selected season's poster as the season cover
|
||||
beside the season tabs and in the fullscreen episode panel's season strip;
|
||||
both are withheld for one-season items (that poster is the show poster) and
|
||||
fold on a failed image request. Contract: "Two-State Detail Layout" in
|
||||
`embedded-inline-playback.md`.
|
||||
|
||||
The season number `{n}` is the provider's episode season number, with one
|
||||
correction (`resolveEnrichmentSeasonNumber` in
|
||||
`libs/shared/interfaces/src/lib/season-marker.util.ts`): providers often
|
||||
|
||||
Reference in new issue
Block a user