Files
iptvnator/libs/playback/util/src/lib/playback-source-routing.ts
T
4grayandClaude Fable 5.1 5e51c1ea5d fix(playback): route non-HLS containers to the native source path (#1510)
The HTML5 player chose its engine by exclusion: anything that was not
mpd/ts/mp4 went to hls.js, so .mkv (the default Xtream series/VOD
container), .webm, .avi, .mov and .m4v were fed to hls.js as manifests.
hls.js raised a manifest error and the player showed the network/provider
diagnostic over media Chromium plays natively.

Add resolvePlaybackUrlSourceKind() to @iptvnator/playback/util as the one
URL-to-engine rule (mpd -> dash, m3u8/m3u -> hls, ts/m2ts/extension-less
-> mpegts, everything else -> native) and read it from both the HTML5
player and ArtPlayer's getArtPlayerVideoType(), so the two engines agree.
ArtPlayer serves every native container through a single
ART_PLAYER_NATIVE_SOURCE_TYPE custom type, keeping the source session the
owner of teardown and controls binding. The HTML5 native <source> carries
the video/mp4 hint only for MP4-family files: a hint the browser's
canPlayType() rejects makes it skip the source, and Chromium demuxes
containers it does not advertise there.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 09:43:33 +02:00

47 lines
1.9 KiB
TypeScript

import { getPlaybackMediaExtensionFromUrl } from '@iptvnator/shared/m3u-utils';
import { PlaybackSourceKind } from './playback-recommendation.model';
/**
* Engine family a playback URL is routed to BEFORE any engine runs.
*
* `resolvePlaybackSourceKind()` answers the opposite question — which family
* a diagnostic came out of after an engine failed. Every built-in web player
* selects its source engine through this function, so the HTML5 player and
* ArtPlayer cannot disagree on what a URL is. A URL never yields `unknown`:
* an unrecognized container is exactly what the native `<video>` element is
* for.
*/
export type PlaybackUrlSourceKind = Exclude<
PlaybackSourceKind,
typeof PlaybackSourceKind.Unknown
>;
const DASH_MANIFEST_EXTENSION = 'mpd';
const HLS_MANIFEST_EXTENSIONS: ReadonlySet<string> = new Set(['m3u', 'm3u8']);
/**
* `.m2ts` (BDAV, 192-byte packets) rides with `.ts`: mpegts.js probes the
* packet size itself, so its `mpegts` player type covers both.
*/
const MPEG_TS_EXTENSIONS: ReadonlySet<string> = new Set(['ts', 'm2ts']);
export function resolvePlaybackUrlSourceKind(
url: string
): PlaybackUrlSourceKind {
const extension = getPlaybackMediaExtensionFromUrl(url);
if (extension === DASH_MANIFEST_EXTENSION) {
return PlaybackSourceKind.Dash;
}
if (HLS_MANIFEST_EXTENSIONS.has(extension)) {
return PlaybackSourceKind.Hls;
}
// Extension-less IPTV proxy/script URLs (`/live/user/pass/1`, `.php`)
// are predominantly raw MPEG-TS and keep the established engine.
if (!extension || MPEG_TS_EXTENSIONS.has(extension)) {
return PlaybackSourceKind.MpegTs;
}
// Every other container — mkv, webm, mp4, avi, mov, m4v, audio files —
// is handed to the browser. hls.js only ever receives HLS manifests: fed
// an .mkv it raised a manifest error over media Chromium plays natively.
return PlaybackSourceKind.Native;
}