mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-12 20:16:15 -08:00
feat(dashboard): say where you left off instead of which provider it came from (#1646)
Every dashboard title carried a "Xtream · Series" / "Stalker · Movie" subtitle. Provider kind and content kind are the app's own taxonomy, not a property of the title, and they are identical on every card in a rail — so the one line that could tell two cards apart said nothing. The hero now shows the source name alone, through `playlistDisplayLabel` (a stored playlist name is routinely the pasted URL with credentials, or a MAC). Continue Watching cards show what actually varies: the "S1·E5" chip plus "12 min left". Favorites keep the title alone, Recently Added keeps the source name, and a meta row with nothing in it is no longer rendered. Stalker shows filed under Movies had no badge, no progress and no resume. An embedded-VOD row announces its episodes through a `series[]` array and carries no `is_series` flag, so `extractStalkerItemType` reports `movie` on purpose — the item must keep routing to the VOD catalog — while its progress is a set of episode positions keyed by the parent id, which the dashboard was looking up as a single `vod` row and never finding. Split the two questions: `PortalActivityItem.watch_kind` records the progress model when it differs from the routing type, and every reader that has to choose goes through `resolvePortalActivityWatchKind` instead of `type`. That makes the resume handoff reachable for Stalker, so wire it through `STALKER_SERIES_RESUME_TARGET`: consumed once after the series positions are read, hydrating a lazy Ministra season first with a bounded two-attempt retry, and playing nothing at all when the position read failed rather than restarting the episode from zero. Also fixes the global-recent route template, which bound `[seriesResume]` only on its Xtream branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
954c8ad65e
commit
4e575a810e
26 files changed
+1514
-160
No files matched your search
@@ -74,13 +74,27 @@ with a return handler keep Back available.
|
||||
Stalker movies/series into the matching global collection route with detail
|
||||
pre-opened.
|
||||
- The dashboard hero CTA and the Continue Watching cards' explicit "Resume
|
||||
episode" ⋮ action for Xtream series carry a one-shot season/episode resume
|
||||
target. The collection-owned Xtream detail consumes it after its episode
|
||||
positions load and starts that exact episode; the cards' default click is
|
||||
detail-only (movie-like), as is opening the series from the collection grid
|
||||
itself. If the positions load fails, the target stays unconsumed and the
|
||||
handoff degrades to detail-only rather than starting the episode at offset
|
||||
zero. Continue Watching cards also expose "Mark as Watched" (maxes out the
|
||||
episode" ⋮ action for Xtream and Stalker series carry a one-shot
|
||||
season/episode resume target. The collection-owned detail consumes it after
|
||||
its episode positions load and starts that exact episode; the cards' default
|
||||
click is detail-only (movie-like), as is opening the series from the
|
||||
collection grid itself. If the positions load fails, the target stays
|
||||
unconsumed and the handoff degrades to detail-only rather than starting the
|
||||
episode at offset zero. Xtream reads it from `XTREAM_SERIES_RESUME_TARGET`;
|
||||
Stalker from `STALKER_SERIES_RESUME_TARGET`, provided by
|
||||
`StalkerCollectionDetailComponent` and consumed by
|
||||
`StalkerSeriesViewComponent` (`stalker-series-resume.ts`), which first
|
||||
hydrates the lazy Ministra season the target lives in. The two Stalker
|
||||
shapes differ in the handoff state: a lazy `is_series` row carries
|
||||
`contentType: 'series'` (the flag is read by `extractStalkerItemType`) and
|
||||
`resolveStalkerCollectionDetailMode` sends it through the VOD detail flow
|
||||
without changing that type, while an embedded-VOD row — a `series[]`
|
||||
episode array and no flag — carries `contentType: 'movie'`, because the
|
||||
type resolver is deliberately blind to that array so the item keeps
|
||||
routing to the VOD catalog. Only the detail, reading the stored row, can
|
||||
tell the second shape from a real movie, so
|
||||
`getOpenCollectionDetailItemState` keeps a resume target for any non-live
|
||||
Stalker item, not only `contentType: 'series'`. Continue Watching cards also expose "Mark as Watched" (maxes out the
|
||||
tracked position row) and "Remove from history" in the same ⋮ menu.
|
||||
- Ready Download Manager cards open one of the three focused
|
||||
`downloads/:downloadId` routes. These local details hide the workspace
|
||||
@@ -227,9 +241,10 @@ Dashboard behavior to preserve:
|
||||
Xtream movie/series items into `/workspace/global-favorites` or
|
||||
`/workspace/global-recent` with collection detail pre-opened from navigation
|
||||
state.
|
||||
- When an Xtream series recent has a saved episode position, the dashboard hero
|
||||
and Continue Watching card should include that exact series/episode target in
|
||||
the navigation state. It is a one-shot playback request and must not leak into
|
||||
- When a series recent (Xtream, or a Stalker row that
|
||||
`resolvePortalActivityWatchKind` answers `series` for) has a saved episode
|
||||
position, the dashboard hero and Continue Watching card should include that
|
||||
exact series/episode target in the navigation state. It is a one-shot playback request and must not leak into
|
||||
normal favorites, search, category, or collection-grid navigation. Only
|
||||
position rows that name their parent `seriesXtreamId` produce a target:
|
||||
episode-keyed recents make `item.xtream_id` an episode id, so legacy rows
|
||||
|
||||
@@ -113,17 +113,29 @@ Render rules:
|
||||
2. `continueWatchingCards` — maps `globalRecentVodItems()` to movie/series
|
||||
cover cards. Portal playback positions are bulk-loaded per playlist so
|
||||
hero and cards can show progress, remaining time, and series season/
|
||||
episode badges. This includes Stalker VOD activity normalized to series
|
||||
through `is_series`. Series lookup uses keyed maps for both direct
|
||||
episode ids and parent series ids; card renders must not scan the full
|
||||
playback-position map. The badge uses saved `seasonNumber` /
|
||||
episode badges. Whether an item is looked up as a movie (one `vod`
|
||||
row) or a series (episode rows under the parent id) is its WATCH
|
||||
kind, `resolvePortalActivityWatchKind`, not its routing `type`. The
|
||||
shape that needs the distinction is a Stalker embedded-VOD row: its
|
||||
stored entry carries a `series[]` episode array but no `is_series`
|
||||
flag, so `extractStalkerItemType` reports `movie` (deliberately — the
|
||||
item belongs in the VOD catalog) while its progress lives in episode
|
||||
rows. The mappers give both it and a lazy Ministra `is_series` row
|
||||
(already typed `series`) `watch_kind: 'series'`. Series lookup uses
|
||||
keyed maps for both direct episode ids and parent series ids; card
|
||||
renders must not scan the full playback-position map. The badge uses saved `seasonNumber` /
|
||||
`episodeNumber` metadata and does not infer it from provider payloads;
|
||||
legacy rows without that metadata remain badge-less until replay.
|
||||
Dashboard-originated Xtream series clicks also carry that exact episode
|
||||
target through the global-recent inline-detail handoff. Once the series
|
||||
metadata and playback positions load, the detail player consumes the
|
||||
target once and resumes the saved episode. Opening the same item normally
|
||||
from the global recent grid remains a detail-only action.
|
||||
Dashboard-originated Xtream and Stalker series clicks also carry that
|
||||
exact episode target through the global-recent inline-detail handoff.
|
||||
Once the series metadata and playback positions load, the detail player
|
||||
consumes the target once and resumes the saved episode. Opening the same
|
||||
item normally from the global recent grid remains a detail-only action.
|
||||
Continue Watching cards carry no provider/content-kind subtitle: their
|
||||
meta row is the S·E chip plus a "N min left" label (`remainingLabel`,
|
||||
from `formatRemainingLabel`), and the row is not rendered when both are
|
||||
absent. The hero subtitle is the source name alone, through
|
||||
`playlistDisplayLabel`.
|
||||
3. `liveFavoriteCardsEnriched` and `recentLiveCardsEnriched` — two
|
||||
independent rails (`dashboard-live-favorites-rail` and
|
||||
`dashboard-recent-live-rail`); there is no fallback from one to the
|
||||
@@ -136,8 +148,9 @@ Render rules:
|
||||
which calls `getGlobalRecentlyAdded('all', limit, 'xtream')` with the
|
||||
DB-level `playlists.type = 'xtream'` filter. The rail is Electron-only
|
||||
(PWA returns `[]`) and auto-hides when empty, so users without Xtream
|
||||
playlists never see it. Cards carry a `playlist_name · type` subtitle
|
||||
so users can tell which provider each item came from. Driven by an
|
||||
playlists never see it. Cards carry the source name as their subtitle
|
||||
(`playlistDisplayLabel`) so users can tell where each item was added;
|
||||
the content kind is not repeated on every card. Driven by an
|
||||
effect that re-runs whenever the Xtream playlist count changes, but the
|
||||
first run waits for `globalFavoritesLoaded()` so the slower
|
||||
recently-added DB query does not block the live favorites rail on
|
||||
@@ -217,9 +230,10 @@ The welcome state is rendered via the existing
|
||||
rails have data.
|
||||
5. Navigation from a rail card must deep-link into the appropriate workspace
|
||||
route without switching the active playlist in the header switcher.
|
||||
6. Xtream series hero/Continue Watching clicks with a saved episode position
|
||||
must resume that exact episode while preserving the collection-owned detail
|
||||
and Back behavior. Do not apply autoplay to ordinary collection-grid clicks.
|
||||
6. Xtream and Stalker series hero/Continue Watching clicks with a saved episode
|
||||
position must resume that exact episode while preserving the
|
||||
collection-owned detail and Back behavior. Do not apply autoplay to
|
||||
ordinary collection-grid clicks.
|
||||
7. `Recently Used Sources` reflects recent source usage across all provider
|
||||
types, not just recent imports.
|
||||
8. The live rail title key must match the rendered source: favorites use
|
||||
|
||||
Reference in new issue
Block a user