mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-12 12:06:16 -08:00
feat(epg): manual EPG mapping for Stalker portals (#1173)
* feat(epg): manual EPG mapping for Stalker portals Extends the manual EPG-to-channel mapping (PR #1165) to Stalker: - shared key helper buildStalkerEpgMappingKey — playlist-scoped stalker:{playlistId}:{channelId} keys, mirroring the Xtream scheme - ITV sidebar: right-click context menu with "Map EPG channel"; after the dialog closes with a change, the bulk EPG cache is rebuilt so the panel and row previews reflect the new mapping immediately - withStalkerEpg().applyMappedItvEpg(): batch-resolves mappings for rendered channels (one getEpgMappingsBatch IPC per new id set) and overlays uploaded-XMLTV programs onto bulkItvEpgByChannel; overrides survive ensureBulkItvEpg reloads - stream-resolver: mapping check in loadStalkerEpgItems (detail) and batched prefetch in loadStalkerEpgBatch (previews); mappingCandidateKeys/prefetchEpgMappings generalized beyond Xtream - global favorites: stalker branch for the Map-EPG menu entry (item id extracted from the stalker::{playlistId}::{id} uid) - docs: manual-mapping section in docs/architecture/stalker-epg.md and a CLAUDE.md EPG bullet covering the whole mapping feature - tests: applyMappedItvEpg suite, stalker preview mapping in the stream-resolver spec, key-builder specs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(epg): harden Stalker mapping edges found in adversarial review - stream-resolver: stalker items resolve only the playlist-scoped mapping key — bare tvgId/name candidates (tvgId mirrors the raw provider id) could only produce false matches against unrelated M3U mappings, and previews would disagree with the detail path - applyMappedItvEpg: staleness guard after every await so an in-flight call cannot write portal A's mapped EPG into portal B's state after a playlist switch (the store is a root singleton) - applyMappedItvEpg: ids are marked checked only after a successful lookup — a transient IPC failure no longer suppresses the mapping for the rest of the session - live layout: post-dialog refresh re-applies overrides for the unfiltered channel list, so an active search cannot drop the playing channel's mapping - global favorites: new epgMappingChanged output emitted when the dialog actually changed a mapping; unified live tab reloads its EPG previews in response Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b1fc23abbb
commit
c707af1334
15 files changed
+624
-13
No files matched your search
@@ -1,4 +1,7 @@
|
||||
import { buildXtreamEpgMappingKey } from './epg-mapping-key.util';
|
||||
import {
|
||||
buildStalkerEpgMappingKey,
|
||||
buildXtreamEpgMappingKey,
|
||||
} from './epg-mapping-key.util';
|
||||
|
||||
describe('buildXtreamEpgMappingKey', () => {
|
||||
it('scopes the key to the playlist', () => {
|
||||
@@ -19,3 +22,17 @@ describe('buildXtreamEpgMappingKey', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildStalkerEpgMappingKey', () => {
|
||||
it('scopes the key to the playlist', () => {
|
||||
expect(buildStalkerEpgMappingKey('portal-a', '205')).toBe(
|
||||
'stalker:portal-a:205'
|
||||
);
|
||||
});
|
||||
|
||||
it('never collides with the Xtream key space', () => {
|
||||
expect(buildStalkerEpgMappingKey('p', 1)).not.toBe(
|
||||
buildXtreamEpgMappingKey('p', 1)
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -6,11 +6,11 @@
|
||||
* channel name) directly — those identifiers are meaningful across
|
||||
* playlists, so a mapping saved once applies everywhere.
|
||||
*
|
||||
* Xtream stream IDs, on the other hand, are provider-local integers:
|
||||
* stream 12345 in portal A has nothing to do with stream 12345 in
|
||||
* portal B. Mapping keys for Xtream channels therefore embed the
|
||||
* playlist ID so mappings never leak across portals. Shared between the
|
||||
* renderer and the Electron main process/worker, like
|
||||
* Xtream stream IDs and Stalker channel IDs, on the other hand, are
|
||||
* provider-local: stream 12345 in portal A has nothing to do with
|
||||
* stream 12345 in portal B. Mapping keys for portal channels therefore
|
||||
* embed the playlist ID so mappings never leak across portals. Shared
|
||||
* between the renderer and the Electron main process/worker, like
|
||||
* `title-normalization.util.ts`.
|
||||
*/
|
||||
export function buildXtreamEpgMappingKey(
|
||||
@@ -19,3 +19,10 @@ export function buildXtreamEpgMappingKey(
|
||||
): string {
|
||||
return `xtream:${playlistId}:${xtreamId}`;
|
||||
}
|
||||
|
||||
export function buildStalkerEpgMappingKey(
|
||||
playlistId: string,
|
||||
stalkerId: number | string
|
||||
): string {
|
||||
return `stalker:${playlistId}:${stalkerId}`;
|
||||
}
|
||||
Reference in new issue
Block a user