mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 09:01:03 -08:00
* fix(stalker): fall back to short EPG when bulk EPG misses the current programme Some portals' bulk get_epg_info returns only future programmes — the one airing now is absent. The ITV channel-list previews read exclusively from that bulk map, so every row showed 'No program information available', and the EPG panel preferred any non-empty bulk list over the short-EPG fallback, so it showed upcoming shows with no 'on now' entry. Recently Viewed uses get_short_epg per channel, which is why the same channel worked there. Panel: merge the short-EPG fallback into the bulk list instead of either/or, and trigger the fallback whenever the bulk list has no currently airing programme (not only when it is empty). Rows: new throttled StalkerEpgPreviewQueue (mirroring Xtream's EpgQueueService — bounded concurrency, inter-request spacing, 5-minute cache including empty results, reset on playlist switch) fetches get_short_epg for rendered channels the settled bulk guide cannot answer. Docs: stalker-epg.md fallback contract updated accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(stalker): bound the preview-queue burst and keep mapped channels portal-free Review follow-up (Codex P1/P2 on #1386): P1 — request volume: each queue sync is now capped at 30 channels (top of the list first, where a freshly opened category is scrolled to), and the sidebar scroll handler re-syncs (throttled, 300 ms) to fill the next gaps. Request count now tracks how far the user scrolls instead of how many rows are rendered; caching (including empty results) and 200 ms pacing remain. P2 — manual mappings: a channel whose bulk record comes from a manual XMLTV mapping never falls back to the portal short EPG. The panel path resolves the channel's mapping before falling back and bails when an override owns the channel; the row path excludes overridden channels from both the queue and its cache. New store query hasItvEpgMappingOverride() exposes override ownership; merging portal data into a mapped schedule could otherwise surface the portal's programme — the exact thing the mapping replaces. Docs updated (stalker-epg.md); regression tests for the cap, the mapped- channel suppression, and the override query. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(stalker): scope the panel EPG fallback by channel and revalidate queued previews Review follow-up (Codex round 2 on #1386): The panel's short-EPG fallback is now stored with the channel id it was fetched for, and activeEpgPrograms merges it only while that channel is still selected. A channel switch moves the selection synchronously but the old fallback is replaced only after the new channel's EPG load runs, so the unscoped merge mixed the previous channel's programmes into the new panel during slow playback resolution — and left them there when resolution failed. The row-preview queue's completion callback now revalidates ownership: a row claimed while the fetch was in flight — by a manual mapping override or by bulk data — is never overwritten by the late portal response. Both races covered by a new focused spec (verified to fail on the pre-fix component); stalker-epg.md updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(stalker): supersede the preview backlog on view exit and own empty mappings Review follow-up (Codex round 3 on #1386): The preview queue is now superseded when the rendered channel list empties (a legacy-paged category switch clears it before the new channels arrive) and when the view leaves ITV for radio — an abandoned view's backlog no longer keeps issuing get_short_epg requests for rows that are gone. Mapping ownership is now tracked separately from the mapped guide's programs: a saved mapping whose XMLTV channel currently has no entries still owns its channel, so hasItvEpgMappingOverride() keeps the portal short-EPG fallback out — consistent with a mapping's purpose of replacing portal data. Both covered by regression tests (verified to fail pre-fix; the ITV-exit test re-arms the backlog after init because the playlist effect's first run resets the queue); stalker-epg.md updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(stalker): reconcile every EPG contract reference with the row fallback Review follow-up (Codex round 4 on #1386): the overview, get_short_epg API notes, and data-mapping sections of stalker-epg.md still stated that rows never issue per-row requests, and the stalker-portal skill instructed that only the active channel may fall back — contradicting the contract this PR establishes. All references now describe the bulk-first row previews with the throttled short-EPG fallback queue. skills:validate passes (the skill stays within its 500-word budget). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(stalker): publish empty-mapping ownership reactively Review follow-up (Codex round 5 on #1386): when the row-preview fetch finishes before the mapping lookup, a portal programme is already rendered. An empty mapped guide then recorded ownership only in a plain Set — no state was patched, the preview effect never reran, and the stale portal row survived. applyMappedItvEpg now re-patches bulkItvEpgByChannel (identical content, new reference — deliberately) whenever it establishes new ownership, even without programs, so the rerun sync removes the fallback row. Store regression test extended (fails pre-fix); stalker-epg.md updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
91 lines
3.9 KiB
Markdown
91 lines
3.9 KiB
Markdown
---
|
|
name: stalker-portal
|
|
description: Use when changing Stalker or Ministra routes, stores, catalog or series shapes, playback progress, favorites and recent items, EPG, or remote control.
|
|
---
|
|
|
|
# Stalker Portal
|
|
|
|
## Read First
|
|
|
|
- `docs/architecture/stalker-portal.md`
|
|
- `docs/architecture/stalker-epg.md` for ITV EPG
|
|
- `docs/architecture/remote-control.md` for live remote control
|
|
|
|
## Ownership
|
|
|
|
- Routed UI: `libs/portal/stalker/feature/src/lib/`
|
|
- Session, store, and normalization:
|
|
`libs/portal/stalker/data-access/src/lib/`
|
|
- Wire-format and identity contracts: `libs/shared/interfaces/src/lib/` —
|
|
portal-mode predicate, MAC/device-ID utils, auth-failure classifier, `cmd`
|
|
encoder, URL/identity builders. There because Electron main cannot import
|
|
renderer libs; never fork them.
|
|
- Electron transport: `apps/electron-backend/src/app/events/stalker.events.ts`
|
|
- Provider-neutral collections: `libs/portal/shared/data-access/src/lib/`
|
|
|
|
Keep Stalker shape and store rules in Stalker data access. Shared portal UI
|
|
must remain provider-neutral.
|
|
|
|
## Portal Mode And Session
|
|
|
|
Full vs. simple mode is decided by observed behavior, not URL shape, and read
|
|
only through `isFullStalkerPortalPlaylist()`. Route playlist-backed catalog,
|
|
content and playback calls through `executeStalkerRequest()`. Auth, discovery,
|
|
account-profile refresh and row-less collection resolution go direct; read
|
|
`stalker-request.utils.ts` before adding a fifth. Repair is lazy per session,
|
|
never eager.
|
|
Full portals reuse the persisted idempotent handshake token while its session
|
|
fingerprint matches, and ping `get_events` at the profile cadence (default
|
|
120 s). Auth failures are HTTP 200 plus plain text.
|
|
|
|
## Series Contract
|
|
|
|
Inside Stalker portal code, `isStalkerSeriesFlag()` is the canonical predicate
|
|
and accepts exactly `true`, `1`, and `'1'`. `normalizeStalkerSeriesFlag()`
|
|
delegates to it and produces the normalized positive marker `true` or
|
|
`undefined`. The activity normalizer in shared interfaces keeps its
|
|
dependency-neutral equivalent for favorites/recent and dashboard
|
|
classification. Preserve all three modes: regular `/series`, VOD with embedded
|
|
`series[]`, and lazy Ministra VOD `is_series`.
|
|
|
|
Favorites/recent preserve the normalized positive marker and VOD origin so
|
|
reopening still uses the correct lazy or embedded mode. Keep quick-start
|
|
translation parameters and the naturally ordered season fallback when
|
|
`season_number` is absent.
|
|
|
|
Lazy episodes use a deterministic tracking ID scoped by parent series,
|
|
provider episode, season key, and episode number. `legacyTrackingId` is only a
|
|
guarded compatibility alias. Reconciliation is limited to the current parent
|
|
series and optional matching season/episode metadata; an exact scoped row
|
|
always wins the resolved display position, while a compatible legacy row may
|
|
remain tracked only for cleanup. The scoped ID is the in-memory key. At the
|
|
strict migration boundary, save the scoped row before clearing a confirmed
|
|
legacy row, and keep legacy progress when the save fails.
|
|
|
|
Before inline or external handoff, attach parent `seriesXtreamId` and resolved
|
|
season/episode numbers. Keep them on subsequent position writes.
|
|
|
|
## Live Contract
|
|
|
|
- Start bulk ITV EPG eagerly once channel rows exist. Rows read the bulk
|
|
cache, falling back to throttled `get_short_epg` previews when it lacks
|
|
"now".
|
|
- Radio skips EPG and external players, preserves live collection identity
|
|
with `radio: 'true'`, and uses the shared inline audio player.
|
|
|
|
## Validation
|
|
|
|
Run:
|
|
|
|
- `pnpm nx test shared-interfaces`
|
|
- `pnpm nx test portal-stalker-data-access`
|
|
- `pnpm nx test portal-stalker-feature`
|
|
- the affected `portal-shared-data-access` / `portal-shared-ui` target for
|
|
collection or radio behavior
|
|
- the affected `workspace-dashboard-data-access` and
|
|
`workspace-dashboard-feature` test targets
|
|
|
|
For the user workflow, run
|
|
`pnpm nx run web-e2e:e2e-ci--src/stalker.e2e.ts` or document the strongest
|
|
focused coverage available.
|