mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
fix(pwa): extract KODIPROP DRM on the web-backend /parse import path
The web-backend keeps its own playlist builder for the PWA URL-import path, so the shared createPlaylistObject() DRM hook never ran there and encrypted DASH channels imported by URL reached Shaka without keys. Apply extractDrmFromRaw() in that builder too and cover the path with a regression test. Addresses Codex review on PR #1225. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4e16729bf6
commit
2b3d7fa1a9
2 files changed
+59
-4
No files matched your search
@@ -196,6 +196,50 @@ https://stream.example/news.m3u8`);
|
||||
);
|
||||
});
|
||||
|
||||
it('extracts KODIPROP ClearKey DRM on the /parse URL-import path', async () => {
|
||||
const httpClient = new StubHttpClient();
|
||||
const kid = '00112233445566778899aabbccddeeff';
|
||||
const key = 'ffeeddccbbaa99887766554433221100';
|
||||
httpClient.queueResponse(`#EXTM3U
|
||||
#EXTINF:-1 tvg-id="ck" group-title="DASH",Encrypted DASH
|
||||
#KODIPROP:inputstream.adaptive.license_type=clearkey
|
||||
#KODIPROP:inputstream.adaptive.license_key=${kid}:${key}
|
||||
https://stream.example/enc.mpd
|
||||
#EXTINF:-1 tvg-id="plain",Plain Channel
|
||||
https://stream.example/live.m3u8`);
|
||||
|
||||
await withServer(
|
||||
createWebBackendApp({
|
||||
clientOrigins: ['http://localhost:4200'],
|
||||
guid: () => 'fixed-id',
|
||||
httpClient,
|
||||
resolveHostname: resolvePublicHost,
|
||||
}),
|
||||
async (baseUrl) => {
|
||||
const targetId = await registerProviderTarget(
|
||||
baseUrl,
|
||||
'https://provider.example/drm.m3u'
|
||||
);
|
||||
const response = await fetch(
|
||||
`${baseUrl}/parse?targetId=${targetId}`,
|
||||
{ headers: { Origin: 'http://localhost:4200' } }
|
||||
);
|
||||
const body = (await response.json()) as {
|
||||
playlist: { items: Array<Record<string, unknown>> };
|
||||
};
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(body.playlist.items).toHaveLength(2);
|
||||
expect(body.playlist.items[0]['drm']).toEqual({
|
||||
licenseType: 'clearkey',
|
||||
supported: true,
|
||||
clearKeys: { [kid]: key },
|
||||
});
|
||||
expect(body.playlist.items[1]['drm']).toBeUndefined();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('allows browser preflight checks for provider target registration', async () => {
|
||||
await withServer(
|
||||
createWebBackendApp({
|
||||
|
||||
@@ -8,6 +8,7 @@ import axios from 'axios';
|
||||
import epgParser from 'epg-parser';
|
||||
import parser from 'iptv-playlist-parser';
|
||||
import { normalizeXtreamServerUrl } from '@iptvnator/shared/interfaces';
|
||||
import { extractDrmFromRaw } from '@iptvnator/shared/m3u-utils';
|
||||
|
||||
export interface WebBackendHttpGetOptions {
|
||||
readonly headers?: Record<string, string>;
|
||||
@@ -514,10 +515,20 @@ function createPlaylistObject(options: {
|
||||
count: options.playlist.items.length,
|
||||
playlist: {
|
||||
...options.playlist,
|
||||
items: options.playlist.items.map((item) => ({
|
||||
id: options.guid(),
|
||||
...item,
|
||||
})),
|
||||
items: options.playlist.items.map((item) => {
|
||||
// Keep this builder aligned with the shared
|
||||
// createPlaylistObject() in @iptvnator/shared/m3u-utils:
|
||||
// KODIPROP ClearKey DRM must survive the /parse URL-import
|
||||
// path too.
|
||||
const drm = extractDrmFromRaw(
|
||||
typeof item['raw'] === 'string' ? item['raw'] : undefined
|
||||
);
|
||||
return {
|
||||
id: options.guid(),
|
||||
...item,
|
||||
...(drm ? { drm } : {}),
|
||||
};
|
||||
}),
|
||||
},
|
||||
importDate: timestamp,
|
||||
lastUsage: timestamp,
|
||||
|
||||
Reference in new issue
Block a user