mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
docs(stalker): codify is_series cross-surface contract
This commit is contained in:
1 parent
de445a013f
commit
1c3cc6c9fa
5 files changed
+126
-24
No files matched your search
@@ -0,0 +1,64 @@
|
||||
---
|
||||
name: stalker-portal
|
||||
description: Repository guidance for Stalker/Ministra portal catalogs, VOD/series shapes, playback metadata, collections, EPG, and remote control.
|
||||
---
|
||||
|
||||
# Stalker Portal
|
||||
|
||||
Use this skill when changing Stalker/Ministra routes, stores, catalog/detail
|
||||
views, playback, favorites/recent activity, EPG, or remote control.
|
||||
|
||||
## Read First
|
||||
|
||||
- `docs/architecture/stalker-portal.md`
|
||||
- `docs/architecture/stalker-epg.md` for ITV EPG work
|
||||
- `docs/architecture/remote-control.md` for live remote-control work
|
||||
|
||||
## Ownership
|
||||
|
||||
- Feature UI: `libs/portal/stalker/feature/src/lib/`
|
||||
- Store/API data access: `libs/portal/stalker/data-access/src/lib/`
|
||||
- Electron requests: `apps/electron-backend/src/app/events/stalker.events.ts`
|
||||
- Shared Stalker item normalization:
|
||||
`libs/shared/interfaces/src/lib/stalker-item.normalizer.ts`
|
||||
- Dashboard aggregation: `libs/workspace/dashboard/data-access/src/lib/`
|
||||
|
||||
Keep provider-specific API and normalization behavior in Stalker data access.
|
||||
Keep shared portal layouts/utilities provider-neutral. Preserve full-portal
|
||||
session auth and simple IPC request paths.
|
||||
|
||||
## `is_series` Cross-Surface Checklist
|
||||
|
||||
Treat VOD items with `is_series` as series across every downstream surface.
|
||||
Do not stop after making the detail view render.
|
||||
|
||||
1. Accept portal flags `true`, `1`, and `'1'` through the existing normalizers.
|
||||
Preserve all three modes: regular `/series`, embedded VOD `series[]`, and
|
||||
lazy Ministra VOD `is_series`.
|
||||
2. Build quick-start state through the shared series utility. Preserve
|
||||
`labelKey`, `labelParams`, and `episodeLabel` when adapting it for Stalker;
|
||||
translation parameters must reach the template.
|
||||
3. Preserve `is_series` and the VOD origin in favorites/recent activity.
|
||||
`extractStalkerItemType()` must normalize that activity to dashboard type
|
||||
`series`.
|
||||
4. Before either inline or external episode playback, persist the parent
|
||||
`seriesXtreamId` plus resolved `seasonNumber` and `episodeNumber`. Keep
|
||||
generated episode tracking IDs stable for lazy `is_series` episodes.
|
||||
5. The dashboard reads saved playback positions; it must not infer episode
|
||||
numbers from provider payloads. Legacy rows without season/episode metadata
|
||||
remain badge-less until that episode is played again.
|
||||
|
||||
## Regression Coverage
|
||||
|
||||
- Series view/UI and playback handoff:
|
||||
`pnpm nx test portal-stalker-feature`
|
||||
- Stalker shape/store behavior:
|
||||
`pnpm nx test portal-stalker-data-access`
|
||||
- Dashboard classification and position lookup:
|
||||
`pnpm nx test workspace-dashboard-data-access`
|
||||
- Dashboard badge rendering when changed:
|
||||
`pnpm nx test workspace-dashboard-feature`
|
||||
|
||||
For user-visible workflow changes, run the closest available E2E target. If no
|
||||
fixture covers the affected portal shape, record that gap and perform the
|
||||
strongest targeted unit/build validation available.
|
||||
@@ -383,6 +383,11 @@ Key files:
|
||||
Use when moving heavy database work off the main thread, adding worker-backed SQLite operations, or wiring loading/progress UI for Xtream and playlist DB flows.
|
||||
File: `.codex/skills/iptvnator-sqlite-db-worker/SKILL.md`
|
||||
|
||||
- `stalker-portal`
|
||||
Repository-specific guidance for Stalker/Ministra catalogs, all three VOD/series modes, cross-surface `is_series` behavior, playback metadata, collections, EPG, and remote control.
|
||||
Use when changing Stalker routes, stores, detail views, playback, favorites/recent activity, EPG, or remote control.
|
||||
File: `.codex/skills/stalker-portal/SKILL.md`
|
||||
|
||||
- `xtream-electron`
|
||||
Repository-specific guidance for IPTVnator's Electron-first Xtream implementation, including feature/data-access boundaries, worker-backed DB flows, and Xtream loading/progress UX expectations.
|
||||
Use when working on Xtream routes, store/data-source logic, or Electron-backed Xtream import/search/delete behavior.
|
||||
|
||||
@@ -780,6 +780,7 @@ engine` (restart required) or
|
||||
- Xtream and Stalker detail pages use the shared `PortalDetailShellComponent` (`libs/ui/components/src/lib/portal-detail-shell/`) with two states: **Browse** (hero with poster/metadata/actions, episodes below) and **Watch** (hero collapses with a ~300ms morph, the inline player takes the full content width, metadata moves to an About block below the episodes)
|
||||
- Watch state derives from `inlinePlayback() !== null` only; external MPV/VLC playback keeps the browse layout. Esc and "Close player" exit to browse without navigation; the now-playing back arrow is route-level back (straight to the list via the host's `goBack()`)
|
||||
- A successful external MPV/VLC episode launch immediately persists the selected episode as the latest playback-position entry and retargets the series CTA to `Play episode N`; real player telemetry overwrites that marker when available, so episode identity is reliable while exact external timestamps remain best-effort.
|
||||
- Stalker preserves this contract for regular `/series`, embedded VOD `series[]`, and lazy Ministra VOD `is_series` items: quick-start translation parameters must reach the CTA, and inline/external episode handoffs must include the parent series id plus resolved season and episode numbers. This metadata lets the dashboard render the tracked S/E badge for VOD-backed series. Existing playback rows without it remain badge-less until the episode is played again.
|
||||
- Hosts pass hero chips/meta/actions as `*appDetailTags`/`*appDetailMeta`/`*appDetailActions` templates; the shell stamps them into both the hero and the About block
|
||||
- Seasons are tabs (`SeasonTabsComponent`, dropdown beyond 6 seasons) with auto-selection (playing episode's season → resume season → first) that fires the same `seasonSelected` lazy-load/enrichment hooks as manual clicks; grid/list episode view toggle persists to localStorage; season descriptions come from `get_series_info` (Xtream) or TMDB (Stalker)
|
||||
- Dashboard hero/Continue Watching clicks for an Xtream series carry a one-shot resume target through the global-recent inline-detail handoff; after series metadata and playback positions load, the exact saved episode starts at its stored position. A failed positions load leaves the target unconsumed and the handoff detail-only, so a transient storage error never starts the episode from the beginning. Ordinary global-recent grid clicks remain detail-only.
|
||||
|
||||
@@ -29,7 +29,8 @@ Stalker support covers:
|
||||
|
||||
## Routing Structure
|
||||
|
||||
Primary route tree lives in `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/stalker-feature.routes.ts`.
|
||||
Primary route tree lives in
|
||||
`libs/portal/stalker/feature/src/lib/stalker-feature.routes.ts`.
|
||||
|
||||
- `/stalker/:id/vod`
|
||||
- `/stalker/:id/series`
|
||||
@@ -45,30 +46,31 @@ Primary route tree lives in `/Users/4gray/Code/iptvnator/libs/portal/stalker/fea
|
||||
1. Angular Stalker screens call methods/resources in `StalkerStore`.
|
||||
2. `StalkerStore` builds request params based on selected content type and current view state.
|
||||
3. Requests go through `DataService.sendIpcEvent(STALKER_REQUEST, ...)` or `StalkerSessionService` (full portal auth).
|
||||
4. Electron main process handles `STALKER_REQUEST` in `/Users/4gray/Code/iptvnator/apps/electron-backend/src/app/events/stalker.events.ts`.
|
||||
4. Electron main process handles `STALKER_REQUEST` in
|
||||
`apps/electron-backend/src/app/events/stalker.events.ts`.
|
||||
5. Axios calls Stalker `load.php` API with required headers/cookies and returns normalized payloads to renderer.
|
||||
|
||||
## Main UI Components
|
||||
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/stalker-main-container.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-main-container.component.ts`
|
||||
- Category + content layout for `vod` and `series`
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/stalker-live-stream-layout/stalker-live-stream-layout.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-live-stream-layout/stalker-live-stream-layout.component.ts`
|
||||
- ITV live playback, radio playback, channel/station navigation, EPG panel integration
|
||||
- `/Users/4gray/Code/iptvnator/libs/ui/playback/src/lib/audio-player/audio-player.component.ts`
|
||||
- `libs/ui/playback/src/lib/audio-player/audio-player.component.ts`
|
||||
- Shared inline audio player used by M3U radio channels and Stalker radio stations
|
||||
- `/Users/4gray/Code/iptvnator/libs/ui/components/src/lib/stalker-series-view/stalker-series-view.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-series-view/stalker-series-view.component.ts`
|
||||
- Season/episode UI for all Stalker series modes
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/stalker-favorites/stalker-favorites.component.ts`
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/recently-viewed/recently-viewed.component.ts`
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/stalker-search/stalker-search.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-favorites/stalker-favorites.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/recently-viewed/recently-viewed.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-search/stalker-search.component.ts`
|
||||
|
||||
## Store and Data Flow
|
||||
|
||||
Stalker store is now feature-composed:
|
||||
|
||||
- Facade: `/Users/4gray/Code/iptvnator/libs/portal/stalker/data-access/src/lib/stalker.store.ts`
|
||||
- Feature slices: `/Users/4gray/Code/iptvnator/libs/portal/stalker/data-access/src/lib/stores/features/*`
|
||||
- Shared helpers: `/Users/4gray/Code/iptvnator/libs/portal/stalker/data-access/src/lib/*`
|
||||
- Facade: `libs/portal/stalker/data-access/src/lib/stalker.store.ts`
|
||||
- Feature slices: `libs/portal/stalker/data-access/src/lib/stores/features/*`
|
||||
- Shared helpers: `libs/portal/stalker/data-access/src/lib/*`
|
||||
|
||||
Important store responsibilities:
|
||||
|
||||
@@ -185,6 +187,9 @@ Stalker has multiple real-world data shapes. The current implementation supports
|
||||
- For unloaded VOD-series seasons, the CTA target label is derived from season
|
||||
metadata and rendered as `SxxE01` until episode details are loaded.
|
||||
- Uses unique generated tracking IDs for episode playback position compatibility.
|
||||
- Quick-start actions preserve both their translation key and interpolation
|
||||
parameters when adapted for the Stalker CTA. Dropping `labelParams` exposes
|
||||
the raw `{{episode}}` placeholder.
|
||||
|
||||
Series inline playback behavior is shared across all three modes:
|
||||
|
||||
@@ -194,11 +199,27 @@ Series inline playback behavior is shared across all three modes:
|
||||
- Inline series autoplay is enabled by default. On player EOF (`ended`), Stalker starts the next episode only when it already exists in the current season's mapped episode list.
|
||||
- Autoplay and Next stop at the last episode of the current season. They do not jump to the next season and do not lazy-load an unloaded `is_series=1` season. Quick start remains the only flow that may load another VOD-series season before playback.
|
||||
- Previous is disabled on the first episode of the current season and otherwise switches directly to the previous episode.
|
||||
- Before either inline or external playback starts, the resolved content info
|
||||
includes the parent `seriesXtreamId` and the mapped `seasonNumber` /
|
||||
`episodeNumber`. Future playback-position rows therefore carry enough
|
||||
metadata for workspace surfaces to render an episode badge. Existing rows
|
||||
without those fields are intentionally not migrated and remain badge-less
|
||||
until the episode is played again.
|
||||
|
||||
The VOD-series contract is cross-surface:
|
||||
|
||||
- Favorites and recently viewed records preserve the raw `is_series` flag and
|
||||
VOD origin so reopening still uses the lazy Ministra resources.
|
||||
- `extractStalkerItemType()` normalizes those activity records to dashboard
|
||||
type `series`.
|
||||
- The dashboard resolves episode progress by the parent `seriesXtreamId` and
|
||||
renders the saved season/episode metadata. It does not infer episode numbers
|
||||
from provider payloads.
|
||||
|
||||
Core decision logic and normalization are centralized in:
|
||||
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/data-access/src/lib/stalker-vod.utils.ts`
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/data-access/src/lib/models/*.ts`
|
||||
- `libs/portal/stalker/data-access/src/lib/stalker-vod.utils.ts`
|
||||
- `libs/portal/stalker/data-access/src/lib/models/*.ts`
|
||||
|
||||
## Favorites and Recently Viewed
|
||||
|
||||
@@ -213,10 +234,10 @@ Current implementation is shared via Stalker-specific helpers:
|
||||
|
||||
Where this is used:
|
||||
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/stalker-favorites/stalker-favorites.component.ts`
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/recently-viewed/recently-viewed.component.ts`
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/stalker-search/stalker-search.component.ts`
|
||||
- `/Users/4gray/Code/iptvnator/libs/ui/components/src/lib/stalker-favorites-button/stalker-favorites-button.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-favorites/stalker-favorites.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/recently-viewed/recently-viewed.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-search/stalker-search.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-favorites-button/stalker-favorites-button.component.ts`
|
||||
|
||||
Navigation rule to preserve:
|
||||
|
||||
@@ -264,7 +285,7 @@ Import rule:
|
||||
|
||||
Stalker live remote control is implemented in:
|
||||
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/feature/src/lib/stalker-live-stream-layout/stalker-live-stream-layout.component.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-live-stream-layout/stalker-live-stream-layout.component.ts`
|
||||
|
||||
Supported today:
|
||||
|
||||
@@ -299,9 +320,12 @@ This reduces duplicate UI logic across portal types and keeps compatibility beha
|
||||
|
||||
## Regression Coverage
|
||||
|
||||
Focused regression tests for Stalker VOD mode branching live in:
|
||||
Focused regression tests for Stalker VOD mode branching and the cross-surface
|
||||
series contract live in:
|
||||
|
||||
- `/Users/4gray/Code/iptvnator/libs/portal/stalker/data-access/src/lib/stalker-vod.utils.spec.ts`
|
||||
- `libs/portal/stalker/data-access/src/lib/stalker-vod.utils.spec.ts`
|
||||
- `libs/portal/stalker/feature/src/lib/stalker-series-view/stalker-series-view.component.spec.ts`
|
||||
- `libs/workspace/dashboard/data-access/src/lib/dashboard-data.service.spec.ts`
|
||||
|
||||
Covered scenarios include:
|
||||
|
||||
@@ -310,3 +334,7 @@ Covered scenarios include:
|
||||
- VOD-backed series favorites keep VOD-series loading semantics when opened from
|
||||
favorites/global favorites
|
||||
- Favorite toggle helper path invokes the expected add/remove flow
|
||||
- Quick-start episode labels interpolate their episode number
|
||||
- Inline and external episode handoffs carry resolved season/episode metadata
|
||||
- Dashboard activity classifies `is_series` VOD as series and resolves its
|
||||
saved episode position
|
||||
@@ -93,10 +93,14 @@ Render rules:
|
||||
2. It derives the dashboard surface via `computed()`:
|
||||
1. `hero` — first item of `globalRecentItems()`.
|
||||
2. `continueWatchingCards` — maps `globalRecentVodItems()` to movie/series
|
||||
cover cards. Xtream playback positions are bulk-loaded per playlist so
|
||||
cover cards. Portal playback positions are bulk-loaded per playlist so
|
||||
hero and cards can show progress, remaining time, and series season/
|
||||
episode badges. Series lookup uses keyed maps for both direct episode ids
|
||||
and series ids; card renders must not scan the full playback-position map.
|
||||
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` /
|
||||
`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
|
||||
|
||||
Reference in new issue
Block a user