mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
* docs(playback): design recovery recommendations * docs(playback): plan recovery recommendations * refactor(playback): extract diagnostic utilities * feat(playback): define recovery recommendation contracts * feat(playback): rank recovery recommendations * feat(playback): track session recovery attempts * feat(playback): identify content recovery sessions * feat(ui): add ranked playback diagnostic panel * feat(playback): switch temporarily to recommended players * test(playback): cover temporary player recommendation * test(playback): verify recommendation capability guards * docs(playback): document recovery recommendations * fix(playback): keep recovery keys credential-free * fix(playback): remove derived tracking ownership * fix(playback): preserve distinct recovery fallbacks * fix(playback): reset resume for new sources * fix(playback): preserve desktop recovery guidance * docs(playback): clarify recovery policy exceptions * fix(playback): reject stale progress updates * fix(playback): keep protected recovery guidance neutral * test(playback): cover stale progress output * fix(playback): neutralize protected diagnostic copy * fix(playback): harden runtime guidance ownership * fix(playback): stabilize recovery application ownership * fix(ci): classify playback util coverage * fix(e2e): preserve playback fixture bytes
39 lines
1.2 KiB
TypeScript
39 lines
1.2 KiB
TypeScript
/**
|
|
* Host-owned canonical logical content identity. Source and content IDs must
|
|
* not come from the currently selected provider copy or playback URL.
|
|
*/
|
|
export type PlaybackSessionIdentity =
|
|
| {
|
|
readonly kind: 'live';
|
|
readonly sourceId: string;
|
|
readonly contentId: string | number;
|
|
}
|
|
| {
|
|
readonly kind: 'vod';
|
|
readonly sourceId: string;
|
|
readonly contentId: string | number;
|
|
}
|
|
| {
|
|
readonly kind: 'episode';
|
|
readonly sourceId: string;
|
|
readonly contentId: string | number;
|
|
readonly seriesId?: string | number;
|
|
readonly seasonNumber?: number;
|
|
readonly episodeNumber?: number;
|
|
};
|
|
|
|
export function createPlaybackSessionKey(
|
|
identity: PlaybackSessionIdentity
|
|
): string {
|
|
const parts = [
|
|
identity.kind,
|
|
identity.sourceId,
|
|
String(identity.contentId),
|
|
identity.kind === 'episode' ? String(identity.seriesId ?? '') : '',
|
|
identity.kind === 'episode' ? String(identity.seasonNumber ?? '') : '',
|
|
identity.kind === 'episode' ? String(identity.episodeNumber ?? '') : '',
|
|
];
|
|
|
|
return parts.map((part) => `${part.length}:${part}`).join('|');
|
|
}
|