Files
iptvnator/libs/playback/util/src/lib/diagnostics/vhs-playback-evidence.util.ts
T
4gray fd96b85c19 feat(playback): recommend recovery actions (#1374)
* 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
2026-08-08 01:04:39 +02:00

77 lines
2.6 KiB
TypeScript

import type {
NativePlaybackErrorInput,
VhsPlaybackEngineType as VhsPlaybackEngineTypeValue,
VhsPlaybackEvidence,
VhsPlaybackMediaErrorCode as VhsPlaybackMediaErrorCodeValue,
VhsPlaybackStage as VhsPlaybackStageValue,
} from './playback-diagnostics.model';
import {
VhsPlaybackDisposition,
VhsPlaybackEngineType,
VhsPlaybackMediaErrorCode,
VhsPlaybackStage,
VhsPlaybackUnknownEngineType,
} from './playback-diagnostics.model';
const ENGINE_TYPES = new Set<string>(Object.values(VhsPlaybackEngineType));
const SEGMENT_ENGINE_TYPES = new Set<VhsPlaybackEngineTypeValue>([
VhsPlaybackEngineType.StreamingFailedToSelectNextSegment,
VhsPlaybackEngineType.StreamingFailedToDecryptSegment,
VhsPlaybackEngineType.StreamingFailedToTransmuxSegment,
VhsPlaybackEngineType.StreamingFailedToAppendSegment,
]);
export function createVhsPlaybackEvidence(
error: NativePlaybackErrorInput
): VhsPlaybackEvidence {
const engineType = getEngineType(error.metadata?.errorType);
const httpStatus = getHttpStatus(error.status);
const evidence: VhsPlaybackEvidence = {
engineType,
mediaErrorCode: getMediaErrorCode(error.code),
disposition: VhsPlaybackDisposition.Terminal,
stage: getStage(engineType),
};
return httpStatus === undefined ? evidence : { ...evidence, httpStatus };
}
function getEngineType(value: unknown): VhsPlaybackEngineTypeValue {
return typeof value === 'string' && ENGINE_TYPES.has(value)
? (value as VhsPlaybackEngineTypeValue)
: VhsPlaybackUnknownEngineType;
}
function getMediaErrorCode(value: unknown): VhsPlaybackMediaErrorCodeValue {
return typeof value === 'number' &&
Number.isInteger(value) &&
value >= VhsPlaybackMediaErrorCode.Custom &&
value <= VhsPlaybackMediaErrorCode.Encrypted
? (value as VhsPlaybackMediaErrorCodeValue)
: VhsPlaybackMediaErrorCode.Unknown;
}
function getHttpStatus(value: unknown): number | undefined {
return typeof value === 'number' &&
Number.isInteger(value) &&
value >= 400 &&
value <= 599
? value
: undefined;
}
function getStage(
engineType: VhsPlaybackEngineTypeValue
): VhsPlaybackStageValue {
if (engineType === VhsPlaybackEngineType.StreamingHlsPlaylistParserError) {
return VhsPlaybackStage.Playlist;
}
if (engineType === VhsPlaybackEngineType.StreamingDashManifestParserError) {
return VhsPlaybackStage.Manifest;
}
if (SEGMENT_ENGINE_TYPES.has(engineType)) {
return VhsPlaybackStage.Segment;
}
return VhsPlaybackStage.Unknown;
}