fix(playback): remove derived tracking ownership

This commit is contained in:
4gray committed 2026-08-04 21:27:33 +02:00
1 parent 23ac120144
commit 0dd8c1a57d
3 files changed
+37 -9

No files matched your search

@@ -48,11 +48,13 @@ stream or catch-up URL. VOD and series hosts use the route or catalog
content identity, with series episode coordinates. Stalker episode identity
also includes the explicit series mode, normalized parent, exact season key,
season number, and episode number; synthesized episode hashes are not identity.
The original provider command or episode ID exists only in the short-lived
pending-request guard used to locate the exact selected episode and reject
stale or out-of-order completion. It is never serialized into the recovery
session key. This keeps token refreshes in one logical session while ensuring
colliding tracking hashes cannot select a sibling episode.
Mapped episodes retain the original provider command or episode ID for playback
resolution. Recovery ownership never serializes that value into the session
key or retained recovery state; its recovery-ownership use is limited to a
short-lived exact pending-request snapshot/guard that locates the selected
episode and rejects stale or out-of-order completion. This keeps token refreshes
in one logical session while ensuring colliding tracking hashes cannot select a
sibling episode.
Shared wrappers (`VodDetailsComponent` and `PortalInlinePlayerComponent`) pass
the key unchanged to `WebPlayerViewComponent`.
@@ -76,6 +76,33 @@ describe('createStalkerEpisodePlaybackSessionKey', () => {
}
);
it('retains the exact pending guard without a synthesized tracking hash', () => {
const originalCmd =
'https://stream.example.invalid/episode.mpg?access_token=example-token';
const state = episodeState({
id: 'command-derived-tracking-hash',
originalCmd,
});
const identity = captureStalkerEpisodePlaybackSessionIdentity({
sourceId: 'playlist',
parentSeriesId: 'series',
seriesMode: STALKER_SERIES_DOWNLOAD_MODES.RegularSeries,
episodeState: state,
});
if (!identity) throw new Error('Expected a captured request identity');
expect(identity).toEqual({
sourceId: 'playlist',
parentSeriesId: 'series',
seriesMode: STALKER_SERIES_DOWNLOAD_MODES.RegularSeries,
originalEpisodeIdentity: originalCmd,
seasonKey: state.seasonKey,
seasonNumber: state.seasonNumber,
episodeNumber: state.episodeNumber,
sessionKey: identity.sessionKey,
});
});
it('keeps lazy provider ids transient while rejecting an id refresh for a pending request', () => {
const stateA = episodeState({ originalId: 'provider|episode:token-a' });
const stateB = episodeState({ originalId: 'provider|episode:token-b' });
@@ -25,7 +25,6 @@ export interface StalkerEpisodePlaybackSessionIdentity {
readonly seasonKey: string;
readonly seasonNumber: number;
readonly episodeNumber: number;
readonly episodeTrackingId: string | number;
readonly sessionKey: string;
}
@@ -67,8 +66,9 @@ export function captureStalkerEpisodePlaybackSessionIdentity({
return null;
}
// Provider commands and IDs remain transient request guards below. They
// may contain credentials and must never enter recovery ownership state.
// Recovery ownership uses provider commands and IDs only for the transient
// request guard below. They may contain credentials and must never enter
// the session key or retained recovery state.
const structuralContentId = JSON.stringify([
seriesMode,
seriesId,
@@ -92,7 +92,6 @@ export function captureStalkerEpisodePlaybackSessionIdentity({
seasonKey,
seasonNumber,
episodeNumber,
episodeTrackingId: episodeState.episode.id,
sessionKey,
});
}