mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
fix(m3u): honor DASH catch-up URLs and drop unusable DRM fallbacks
Two Codex round-2 findings: - The inline-playback DASH gate only examined the channel URL, while the external-player guard checks the resolved catch-up URL — a replay that resolves to an .mpd manifest with MPV/VLC configured ended up with no player at all. The gate now uses the effective playback URL (activePlaybackUrl ?? channel.url). - The unsupported-DRM diagnostic advertised MPV/VLC fallback actions, but external players cannot receive the KODIPROP license config either — the diagnostic no longer recommends them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
61651b659b
commit
13cc563c5b
5 files changed
+43
-9
No files matched your search
@@ -646,6 +646,22 @@ describe('VideoPlayerComponent', () => {
|
||||
expect(dataServiceMock.sendIpcEvent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('routes catch-up playback that resolves to a DASH URL inline as well', () => {
|
||||
syncStoreState(sampleChannel);
|
||||
activePlaybackUrl.set('http://localhost/archive/replay.mpd');
|
||||
player.set(VideoPlayer.MPV);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const playerView = fixture.debugElement.query(
|
||||
By.directive(StubWebPlayerViewComponent)
|
||||
);
|
||||
expect(playerView).not.toBeNull();
|
||||
const stub =
|
||||
playerView.componentInstance as StubWebPlayerViewComponent;
|
||||
expect(stub.playerOverride()).toBe(VideoPlayer.Html5Player);
|
||||
});
|
||||
|
||||
it('keeps ArtPlayer for DASH channels and forwards the ClearKey DRM config', () => {
|
||||
const drm = {
|
||||
licenseType: 'clearkey',
|
||||
|
||||
@@ -24,7 +24,7 @@ import { ResizableDirective } from '@iptvnator/ui/components';
|
||||
import {
|
||||
applyChannelNameStrip,
|
||||
getM3uArchiveDays,
|
||||
isDashChannel,
|
||||
isDashStreamUrl,
|
||||
isM3uCatchupPlaybackSupported,
|
||||
} from '@iptvnator/shared/m3u-utils';
|
||||
import { PlaylistContextFacade } from '@iptvnator/playlist/shared/util';
|
||||
@@ -174,9 +174,16 @@ export class VideoPlayerComponent implements OnInit, OnDestroy {
|
||||
readonly archivePlaybackAvailable = computed(() =>
|
||||
isM3uCatchupPlaybackSupported(this.activeChannel())
|
||||
);
|
||||
/** DASH (.mpd) channels always play inline via the Shaka engine. */
|
||||
/**
|
||||
* DASH (.mpd) playback always runs inline via the Shaka engine. Uses the
|
||||
* effective playback URL, so catch-up/archive replays that resolve to a
|
||||
* DASH manifest route inline too — matching the external-player guard in
|
||||
* the m3u-state effects, which also checks the resolved URL.
|
||||
*/
|
||||
readonly activeChannelIsDash = computed(() =>
|
||||
isDashChannel(this.activeChannel())
|
||||
isDashStreamUrl(
|
||||
this.activePlaybackUrl() ?? this.activeChannel()?.url
|
||||
)
|
||||
);
|
||||
/**
|
||||
* Player forced for DASH channels: ArtPlayer keeps ArtPlayer (it has a
|
||||
@@ -1009,9 +1016,10 @@ export class VideoPlayerComponent implements OnInit, OnDestroy {
|
||||
return false;
|
||||
}
|
||||
|
||||
// DASH channels bypass the external-player setting (radio precedent):
|
||||
// MPV/VLC cannot receive the KODIPROP ClearKey configuration.
|
||||
if (isDashChannel(channel)) {
|
||||
// DASH playback bypasses the external-player setting (radio
|
||||
// precedent): MPV/VLC cannot receive the KODIPROP ClearKey
|
||||
// configuration. Checked on the effective (possibly catch-up) URL.
|
||||
if (this.activeChannelIsDash()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -237,6 +237,9 @@ export function createPlaybackDiagnostic(options: {
|
||||
readonly details?: string;
|
||||
readonly nativeErrorCode?: number;
|
||||
readonly nativeErrorMessage?: string;
|
||||
/** Overrides the code-derived recommendation, e.g. when external players
|
||||
* are known to be unable to handle the stream either. */
|
||||
readonly externalFallbackRecommended?: boolean;
|
||||
}): PlaybackDiagnostic {
|
||||
const {
|
||||
code,
|
||||
@@ -259,7 +262,9 @@ export function createPlaybackDiagnostic(options: {
|
||||
details: details || undefined,
|
||||
nativeErrorCode,
|
||||
nativeErrorMessage,
|
||||
externalFallbackRecommended: isExternalFallbackRecommended(code),
|
||||
externalFallbackRecommended:
|
||||
options.externalFallbackRecommended ??
|
||||
isExternalFallbackRecommended(code),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ describe('classifyShakaPlaybackIssue', () => {
|
||||
});
|
||||
|
||||
describe('createUnsupportedDrmDiagnostic', () => {
|
||||
it('creates a DRM diagnostic carrying the license type', () => {
|
||||
it('creates a DRM diagnostic without recommending unusable external fallbacks', () => {
|
||||
const issue = createUnsupportedDrmDiagnostic(
|
||||
'com.widevine.alpha',
|
||||
metadata
|
||||
@@ -94,6 +94,8 @@ describe('createUnsupportedDrmDiagnostic', () => {
|
||||
expect(issue.code).toBe(PlaybackDiagnosticCode.DrmOrEncryption);
|
||||
expect(issue.source).toBe(PlaybackDiagnosticSource.Shaka);
|
||||
expect(issue.details).toContain('com.widevine.alpha');
|
||||
expect(issue.externalFallbackRecommended).toBe(true);
|
||||
// MPV/VLC cannot receive KODIPROP license config, so the diagnostic
|
||||
// must not offer them as a fallback.
|
||||
expect(issue.externalFallbackRecommended).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -111,6 +111,9 @@ export function createUnsupportedDrmDiagnostic(
|
||||
details: licenseType
|
||||
? `Unsupported DRM license configuration: ${licenseType}`
|
||||
: 'Unsupported DRM license configuration',
|
||||
// External MPV/VLC cannot receive the KODIPROP license config either,
|
||||
// so offering them as a fallback would just fail differently.
|
||||
externalFallbackRecommended: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user