mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 20:56:19 -08:00
fix(playback): suppress unusable external fallback for ClearKey DRM failures
Runtime DRM errors on channels that carry KODIPROP ClearKey config (wrong or rotated keys) advertised MPV/VLC fallback actions, but external players never receive the license config — the fallback could only fail differently. DRM-classified diagnostics from such channels no longer recommend external players; clear channels keep the hint. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
13cc563c5b
commit
f547219dd5
2 files changed
+65
-8
No files matched your search
@@ -107,11 +107,36 @@ describe('ShakaVideoSession', () => {
|
||||
player.dispatch('error', { severity: 2, category: 6, code: 6001 });
|
||||
expect(issues).toHaveLength(1);
|
||||
expect(issues[0].code).toBe(PlaybackDiagnosticCode.DrmOrEncryption);
|
||||
// Without KODIPROP config the DRM hint may still help externally.
|
||||
expect(issues[0].externalFallbackRecommended).toBe(true);
|
||||
// Critical errors end playback: the dead engine must be torn down.
|
||||
expect(player.destroyCount).toBe(1);
|
||||
expect(session.getPlayer()).toBeNull();
|
||||
});
|
||||
|
||||
it('drops the external-fallback hint for DRM errors on ClearKey channels', async () => {
|
||||
const environment = createFakeShakaEnvironment();
|
||||
const session = createSession(environment);
|
||||
session.start(video, 'http://example.com/enc.mpd', {
|
||||
licenseType: 'clearkey',
|
||||
supported: true,
|
||||
clearKeys: { abc: 'def' },
|
||||
});
|
||||
await flush();
|
||||
|
||||
environment.instances[0].dispatch('error', {
|
||||
severity: 2,
|
||||
category: 6,
|
||||
code: 6001,
|
||||
});
|
||||
|
||||
expect(issues).toHaveLength(1);
|
||||
expect(issues[0].code).toBe(PlaybackDiagnosticCode.DrmOrEncryption);
|
||||
// MPV/VLC never receive the KODIPROP license config, so they are not
|
||||
// offered as a fallback for key failures on ClearKey channels.
|
||||
expect(issues[0].externalFallbackRecommended).toBe(false);
|
||||
});
|
||||
|
||||
it('emits a diagnostic and tears the engine down when load rejects', async () => {
|
||||
const loadError = { severity: 2, category: 4, code: 4001 };
|
||||
const environment = createFakeShakaEnvironment({
|
||||
|
||||
@@ -165,7 +165,7 @@ export class ShakaVideoSession {
|
||||
|
||||
const player = new module.Player();
|
||||
this.player = player;
|
||||
this.bindPlayerListeners(player, generation, url);
|
||||
this.bindPlayerListeners(player, generation, url, drm !== undefined);
|
||||
|
||||
if (drm?.clearKeys) {
|
||||
player.configure({ drm: { clearKeys: drm.clearKeys } });
|
||||
@@ -175,7 +175,13 @@ export class ShakaVideoSession {
|
||||
await player.attach(video);
|
||||
await player.load(url);
|
||||
} catch (error: unknown) {
|
||||
this.handleLoadFailure(generation, player, url, error);
|
||||
this.handleLoadFailure(
|
||||
generation,
|
||||
player,
|
||||
url,
|
||||
error,
|
||||
drm !== undefined
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -195,7 +201,8 @@ export class ShakaVideoSession {
|
||||
generation: number,
|
||||
player: ShakaPlayerLike,
|
||||
url: string,
|
||||
error: unknown
|
||||
error: unknown,
|
||||
drmProvided: boolean
|
||||
): void {
|
||||
const shakaError = asShakaError(error);
|
||||
if (
|
||||
@@ -207,9 +214,12 @@ export class ShakaVideoSession {
|
||||
}
|
||||
|
||||
this.config.emitPlaybackIssue(
|
||||
classifyShakaPlaybackIssue(
|
||||
shakaError ?? { message: toErrorMessage(error) },
|
||||
this.createMetadata(url)
|
||||
this.withoutUnusableDrmFallback(
|
||||
classifyShakaPlaybackIssue(
|
||||
shakaError ?? { message: toErrorMessage(error) },
|
||||
this.createMetadata(url)
|
||||
),
|
||||
drmProvided
|
||||
)
|
||||
);
|
||||
// Never leave a non-functional engine attached to the media element
|
||||
@@ -217,10 +227,26 @@ export class ShakaVideoSession {
|
||||
this.beginPlayerTeardown();
|
||||
}
|
||||
|
||||
/**
|
||||
* For channels carrying KODIPROP ClearKey config, DRM failures (wrong or
|
||||
* rotated keys, …) cannot be solved by MPV/VLC either — they never
|
||||
* receive the license config — so the diagnostic must not offer them.
|
||||
*/
|
||||
private withoutUnusableDrmFallback(
|
||||
issue: PlaybackDiagnostic,
|
||||
drmProvided: boolean
|
||||
): PlaybackDiagnostic {
|
||||
if (!drmProvided || issue.code !== DiagnosticCode.DrmOrEncryption) {
|
||||
return issue;
|
||||
}
|
||||
return { ...issue, externalFallbackRecommended: false };
|
||||
}
|
||||
|
||||
private bindPlayerListeners(
|
||||
player: ShakaPlayerLike,
|
||||
generation: number,
|
||||
url: string
|
||||
url: string,
|
||||
drmProvided: boolean
|
||||
): void {
|
||||
const errorListener = (event: Event): void => {
|
||||
if (this.isStale(generation) || this.player !== player) {
|
||||
@@ -234,7 +260,13 @@ export class ShakaVideoSession {
|
||||
}
|
||||
|
||||
this.config.emitPlaybackIssue(
|
||||
classifyShakaPlaybackIssue(detail, this.createMetadata(url))
|
||||
this.withoutUnusableDrmFallback(
|
||||
classifyShakaPlaybackIssue(
|
||||
detail,
|
||||
this.createMetadata(url)
|
||||
),
|
||||
drmProvided
|
||||
)
|
||||
);
|
||||
// Critical errors end playback; never leave the dead engine
|
||||
// attached or exposed to the shared-controls bridge.
|
||||
|
||||
Reference in new issue
Block a user