mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 20:56:19 -08:00
fix(m3u): symmetric DASH inline gate and lazy DRM for pre-upgrade playlists
- The inline DASH gate is now true when either the channel or the resolved catch-up URL is DASH, mirroring the external-player guard — a .mpd channel whose catch-up resolves to .m3u8 no longer ends up with no player at all. - Playlists imported before the DRM feature carry no drm field, but the raw KODIPROP block survived in the stored items; the M3U page now falls back to extractDrmFromRaw(channel.raw) at playback time, so encrypted channels work without a re-import (Channel gains raw?). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f547219dd5
commit
e30811589e
3 files changed
+66
-9
No files matched your search
@@ -662,6 +662,56 @@ describe('VideoPlayerComponent', () => {
|
||||
expect(stub.playerOverride()).toBe(VideoPlayer.Html5Player);
|
||||
});
|
||||
|
||||
it('keeps a DASH channel inline when its catch-up resolves to a non-DASH URL', () => {
|
||||
syncStoreState({
|
||||
...sampleChannel,
|
||||
url: 'http://localhost/live.mpd',
|
||||
} as Channel);
|
||||
activePlaybackUrl.set('http://localhost/archive/replay.m3u8');
|
||||
player.set(VideoPlayer.MPV);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
// The external-player guard declines DASH channels, so the inline
|
||||
// player must stay — otherwise the session has no player at all.
|
||||
expect(
|
||||
fixture.debugElement.query(
|
||||
By.directive(StubWebPlayerViewComponent)
|
||||
)
|
||||
).not.toBeNull();
|
||||
});
|
||||
|
||||
it('extracts DRM lazily from raw KODIPROP for pre-upgrade playlists', () => {
|
||||
const kid = '00112233445566778899aabbccddeeff';
|
||||
const key = 'ffeeddccbbaa99887766554433221100';
|
||||
syncStoreState({
|
||||
...sampleChannel,
|
||||
url: 'http://localhost/enc.mpd',
|
||||
raw: [
|
||||
'#EXTINF:-1,Encrypted',
|
||||
'#KODIPROP:inputstream.adaptive.license_type=clearkey',
|
||||
`#KODIPROP:inputstream.adaptive.license_key=${kid}:${key}`,
|
||||
'http://localhost/enc.mpd',
|
||||
].join('\r\n'),
|
||||
} as Channel);
|
||||
player.set(VideoPlayer.Html5Player);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const stub = fixture.debugElement.query(
|
||||
By.directive(StubWebPlayerViewComponent)
|
||||
).componentInstance as StubWebPlayerViewComponent;
|
||||
expect(stub.playback()).toEqual(
|
||||
expect.objectContaining({
|
||||
drm: {
|
||||
licenseType: 'clearkey',
|
||||
supported: true,
|
||||
clearKeys: { [kid]: key },
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps ArtPlayer for DASH channels and forwards the ClearKey DRM config', () => {
|
||||
const drm = {
|
||||
licenseType: 'clearkey',
|
||||
|
||||
@@ -24,6 +24,8 @@ import { ResizableDirective } from '@iptvnator/ui/components';
|
||||
import {
|
||||
applyChannelNameStrip,
|
||||
getM3uArchiveDays,
|
||||
extractDrmFromRaw,
|
||||
isDashChannel,
|
||||
isDashStreamUrl,
|
||||
isM3uCatchupPlaybackSupported,
|
||||
} from '@iptvnator/shared/m3u-utils';
|
||||
@@ -175,15 +177,15 @@ export class VideoPlayerComponent implements OnInit, OnDestroy {
|
||||
isM3uCatchupPlaybackSupported(this.activeChannel())
|
||||
);
|
||||
/**
|
||||
* 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.
|
||||
* DASH (.mpd) playback always runs inline via the Shaka engine. True when
|
||||
* either the channel itself or the resolved catch-up URL is DASH —
|
||||
* mirroring the external-player guard in the m3u-state effects, so a
|
||||
* DASH-flavored session can never end up with no player at all.
|
||||
*/
|
||||
readonly activeChannelIsDash = computed(() =>
|
||||
isDashStreamUrl(
|
||||
this.activePlaybackUrl() ?? this.activeChannel()?.url
|
||||
)
|
||||
readonly activeChannelIsDash = computed(
|
||||
() =>
|
||||
isDashStreamUrl(this.activePlaybackUrl() ?? undefined) ||
|
||||
isDashChannel(this.activeChannel())
|
||||
);
|
||||
/**
|
||||
* Player forced for DASH channels: ArtPlayer keeps ArtPlayer (it has a
|
||||
@@ -303,7 +305,10 @@ export class VideoPlayerComponent implements OnInit, OnDestroy {
|
||||
userAgent: http['user-agent'] || undefined,
|
||||
referer: http.referrer || undefined,
|
||||
origin: http.origin || undefined,
|
||||
drm: playbackTarget.drm,
|
||||
// Playlists imported before the DRM feature carry no drm field
|
||||
// yet, but their raw KODIPROP block survived in the stored items
|
||||
// — extract lazily so they work without a re-import.
|
||||
drm: playbackTarget.drm ?? extractDrmFromRaw(playbackTarget.raw),
|
||||
};
|
||||
});
|
||||
readonly sidebarStorageKey = computed(() =>
|
||||
|
||||
@@ -32,4 +32,6 @@ export interface Channel {
|
||||
};
|
||||
radio: string;
|
||||
drm?: ChannelDrm;
|
||||
/** Raw M3U block of the entry as preserved by the playlist parser. */
|
||||
raw?: string;
|
||||
}
|
||||
Reference in new issue
Block a user