mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 13:16:16 -08:00
fix(m3u): unify DASH URL detection with playback extension normalization
isDashStreamUrl() used the simpler getStreamExtensionFromUrl(), so URLs the player engines classify as DASH (stream.MPD, ?ext=mpd, ?format=mpd) were not routed to the Shaka-capable inline player and lost their ClearKey metadata with Video.js or external players configured (Codex P2). The normalized getPlaybackMediaExtensionFromUrl() now lives in @iptvnator/shared/m3u-utils (re-exported unchanged from the playback lib) and both routing and engine selection share it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
48d191b0d7
commit
95bd7f7fe0
5 files changed
+145
-122
No files matched your search
@@ -1,27 +1,17 @@
|
||||
import { getExtensionFromUrl } from '@iptvnator/shared/m3u-utils';
|
||||
import {
|
||||
UNSUPPORTED_CONTAINER_EXTENSIONS,
|
||||
getPlaybackMediaExtensionFromUrl,
|
||||
} from '@iptvnator/shared/m3u-utils';
|
||||
|
||||
import type {
|
||||
PlaybackSourceMetadata,
|
||||
PlaybackSourceMetadataInput,
|
||||
} from './playback-diagnostics.model';
|
||||
|
||||
const UNSUPPORTED_CONTAINER_EXTENSIONS = new Set([
|
||||
'avi',
|
||||
'asf',
|
||||
'divx',
|
||||
'flv',
|
||||
'm2ts',
|
||||
'm4v',
|
||||
'mkv',
|
||||
'mov',
|
||||
'mpeg',
|
||||
'mpg',
|
||||
'rm',
|
||||
'rmvb',
|
||||
'ts',
|
||||
'vob',
|
||||
'wmv',
|
||||
]);
|
||||
// Media-extension normalization lives in @iptvnator/shared/m3u-utils so M3U
|
||||
// routing (isDashChannel) and engine selection always agree; re-exported here
|
||||
// to keep the playback-lib import surface stable.
|
||||
export { getPlaybackMediaExtensionFromUrl };
|
||||
|
||||
const UNSUPPORTED_CONTAINER_NAMES = new Set([
|
||||
...UNSUPPORTED_CONTAINER_EXTENSIONS,
|
||||
@@ -31,42 +21,6 @@ const UNSUPPORTED_CONTAINER_NAMES = new Set([
|
||||
'x-msvideo',
|
||||
]);
|
||||
|
||||
const EXPLICIT_MEDIA_EXTENSION_QUERY_KEYS = ['extension', 'ext'];
|
||||
|
||||
const DECLARED_MEDIA_FORMAT_QUERY_KEYS = ['format', 'container'];
|
||||
|
||||
const DECLARED_MEDIA_EXTENSION_ALIASES = new Map([
|
||||
['hls', 'm3u8'],
|
||||
['mpegts', 'ts'],
|
||||
['mpeg-ts', 'ts'],
|
||||
]);
|
||||
|
||||
const DECLARED_MEDIA_EXTENSIONS = new Set([
|
||||
...UNSUPPORTED_CONTAINER_EXTENSIONS,
|
||||
'aac',
|
||||
'flac',
|
||||
'm3u',
|
||||
'm3u8',
|
||||
'm4s',
|
||||
'mp3',
|
||||
'mp4',
|
||||
'mpd',
|
||||
'oga',
|
||||
'ogg',
|
||||
'ogv',
|
||||
'webm',
|
||||
]);
|
||||
|
||||
const NON_MEDIA_URL_EXTENSIONS = new Set([
|
||||
'asp',
|
||||
'aspx',
|
||||
'cgi',
|
||||
'jsp',
|
||||
'mpv',
|
||||
'php',
|
||||
'pl',
|
||||
]);
|
||||
|
||||
const BROWSER_LIMITED_CODEC_PATTERNS: ReadonlyArray<{
|
||||
readonly label: string;
|
||||
readonly pattern: RegExp;
|
||||
@@ -95,35 +49,6 @@ export function createPlaybackSourceMetadata(
|
||||
};
|
||||
}
|
||||
|
||||
export function getPlaybackMediaExtensionFromUrl(url: string): string {
|
||||
const explicitQueryExtension = getMediaExtensionFromQuery(
|
||||
url,
|
||||
EXPLICIT_MEDIA_EXTENSION_QUERY_KEYS
|
||||
);
|
||||
if (explicitQueryExtension) {
|
||||
return explicitQueryExtension;
|
||||
}
|
||||
|
||||
const pathExtension = normalizeExtensionToken(getExtensionFromUrl(url));
|
||||
if (DECLARED_MEDIA_EXTENSIONS.has(pathExtension)) {
|
||||
return pathExtension;
|
||||
}
|
||||
|
||||
const formatQueryExtension = getMediaExtensionFromQuery(
|
||||
url,
|
||||
DECLARED_MEDIA_FORMAT_QUERY_KEYS
|
||||
);
|
||||
if (formatQueryExtension) {
|
||||
return formatQueryExtension;
|
||||
}
|
||||
|
||||
if (NON_MEDIA_URL_EXTENSIONS.has(pathExtension)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return pathExtension;
|
||||
}
|
||||
|
||||
export function getLikelyBrowserUnsupportedCodecLabels(
|
||||
metadata: Pick<PlaybackSourceMetadata, 'audioCodecs' | 'videoCodecs'>
|
||||
): string[] {
|
||||
@@ -188,40 +113,3 @@ function normalizeCodecs(codecs: readonly string[] | undefined): string[] {
|
||||
function normalizeToken(value: string | undefined): string {
|
||||
return value?.trim().toLowerCase() ?? '';
|
||||
}
|
||||
|
||||
function normalizeExtensionToken(value: string | undefined): string {
|
||||
return normalizeToken(value).replace(/^\.+/, '');
|
||||
}
|
||||
|
||||
function getMediaExtensionFromQuery(
|
||||
url: string,
|
||||
queryKeys: readonly string[]
|
||||
): string {
|
||||
try {
|
||||
const parsedUrl = new URL(url, 'http://iptvnator.local');
|
||||
for (const key of queryKeys) {
|
||||
const declaredExtension = normalizeDeclaredMediaExtension(
|
||||
parsedUrl.searchParams.get(key) ?? undefined
|
||||
);
|
||||
if (declaredExtension) {
|
||||
return declaredExtension;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeDeclaredMediaExtension(value: string | undefined): string {
|
||||
const extension = normalizeExtensionToken(value);
|
||||
const normalized =
|
||||
DECLARED_MEDIA_EXTENSION_ALIASES.get(extension) ?? extension;
|
||||
|
||||
if (!normalized || NON_MEDIA_URL_EXTENSIONS.has(normalized)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return DECLARED_MEDIA_EXTENSIONS.has(normalized) ? normalized : '';
|
||||
}
|
||||
Reference in new issue
Block a user