mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
fix(playback): reset the media element for rejected DRM and widen ClearKey fallback suppression
- Switching from a playing stream to an unsupported-DRM DASH channel loads no new source, but play() still ran and the un-loaded element could resume the previous stream underneath the diagnostic banner. The HTML5 player now resets the element instead of playing. - Any inline failure on a KODIPROP ClearKey channel (manifest, codec, media, network — not just DRM-category errors) is unsolvable in MPV/VLC, which never receive the license config; the external fallback hint is now suppressed for all diagnostics of such channels. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ccc1752a3a
commit
208d8d0fc2
4 files changed
+61
-6
No files matched your search
@@ -224,6 +224,35 @@ describe('HtmlVideoPlayerComponent', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('does not resume the previous source when a channel declares unsupported DRM', () => {
|
||||
const video = component.videoPlayer.nativeElement;
|
||||
const loadSpy = jest
|
||||
.spyOn(video, 'load')
|
||||
.mockImplementation(() => undefined);
|
||||
const playSpy = jest.spyOn(video, 'play').mockResolvedValue(undefined);
|
||||
|
||||
component.playChannel({
|
||||
...TEST_CHANNEL,
|
||||
url: 'https://stream.example/movie.mp4',
|
||||
});
|
||||
playSpy.mockClear();
|
||||
loadSpy.mockClear();
|
||||
|
||||
component.playChannel({
|
||||
...TEST_CHANNEL,
|
||||
url: 'https://stream.example/enc.mpd',
|
||||
drm: {
|
||||
licenseType: 'com.widevine.alpha',
|
||||
supported: false,
|
||||
},
|
||||
});
|
||||
|
||||
// No source is loaded for unsupported DRM: play() must not run, and
|
||||
// the element is reset so the old stream cannot keep playing.
|
||||
expect(playSpy).not.toHaveBeenCalled();
|
||||
expect(loadSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('emits a playback issue when the native video element reports an unsupported source', () => {
|
||||
const issues: unknown[] = [];
|
||||
component.channel = TEST_CHANNEL;
|
||||
|
||||
@@ -197,7 +197,14 @@ export class HtmlVideoPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
url,
|
||||
channel.drm
|
||||
);
|
||||
this.handlePlayOperation();
|
||||
if (channel.drm && !channel.drm.supported) {
|
||||
// No source is loaded for unsupported DRM; reset the
|
||||
// element so the previous stream cannot resume playing
|
||||
// underneath the diagnostic banner.
|
||||
this.videoPlayer.nativeElement.load();
|
||||
} else {
|
||||
this.handlePlayOperation();
|
||||
}
|
||||
} else if (
|
||||
(extension === 'ts' || !extension) &&
|
||||
mpegts.isSupported()
|
||||
|
||||
@@ -114,7 +114,7 @@ describe('ShakaVideoSession', () => {
|
||||
expect(session.getPlayer()).toBeNull();
|
||||
});
|
||||
|
||||
it('drops the external-fallback hint for DRM errors on ClearKey channels', async () => {
|
||||
it('drops the external-fallback hint for every failure on ClearKey channels', async () => {
|
||||
const environment = createFakeShakaEnvironment();
|
||||
const session = createSession(environment);
|
||||
session.start(video, 'http://example.com/enc.mpd', {
|
||||
@@ -135,6 +135,24 @@ describe('ShakaVideoSession', () => {
|
||||
// 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);
|
||||
|
||||
// Non-DRM failures (media/codec/manifest/…) are equally unsolvable
|
||||
// externally while the stream itself stays encrypted.
|
||||
session.start(video, 'http://example.com/enc.mpd', {
|
||||
licenseType: 'clearkey',
|
||||
supported: true,
|
||||
clearKeys: { abc: 'def' },
|
||||
});
|
||||
await flush();
|
||||
environment.instances[1].dispatch('error', {
|
||||
severity: 2,
|
||||
category: 3,
|
||||
code: 3016,
|
||||
});
|
||||
|
||||
expect(issues).toHaveLength(2);
|
||||
expect(issues[1].code).toBe(PlaybackDiagnosticCode.MediaDecodeError);
|
||||
expect(issues[1].externalFallbackRecommended).toBe(false);
|
||||
});
|
||||
|
||||
it('emits a diagnostic and tears the engine down when load rejects', async () => {
|
||||
|
||||
@@ -228,15 +228,16 @@ export class ShakaVideoSession {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Channels carrying KODIPROP ClearKey config cannot be handed to MPV/VLC
|
||||
* at all — external players never receive the license config, so the
|
||||
* encrypted stream fails there regardless of what broke inline (DRM,
|
||||
* manifest, codec, network, …). Suppress the fallback hint entirely.
|
||||
*/
|
||||
private withoutUnusableDrmFallback(
|
||||
issue: PlaybackDiagnostic,
|
||||
drmProvided: boolean
|
||||
): PlaybackDiagnostic {
|
||||
if (!drmProvided || issue.code !== DiagnosticCode.DrmOrEncryption) {
|
||||
if (!drmProvided || !issue.externalFallbackRecommended) {
|
||||
return issue;
|
||||
}
|
||||
return { ...issue, externalFallbackRecommended: false };
|
||||
|
||||
Reference in new issue
Block a user