mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 20:56:19 -08:00
* docs(playback): design recovery recommendations * docs(playback): plan recovery recommendations * refactor(playback): extract diagnostic utilities * feat(playback): define recovery recommendation contracts * feat(playback): rank recovery recommendations * feat(playback): track session recovery attempts * feat(playback): identify content recovery sessions * feat(ui): add ranked playback diagnostic panel * feat(playback): switch temporarily to recommended players * test(playback): cover temporary player recommendation * test(playback): verify recommendation capability guards * docs(playback): document recovery recommendations * fix(playback): keep recovery keys credential-free * fix(playback): remove derived tracking ownership * fix(playback): preserve distinct recovery fallbacks * fix(playback): reset resume for new sources * fix(playback): preserve desktop recovery guidance * docs(playback): clarify recovery policy exceptions * fix(playback): reject stale progress updates * fix(playback): keep protected recovery guidance neutral * test(playback): cover stale progress output * fix(playback): neutralize protected diagnostic copy * fix(playback): harden runtime guidance ownership * fix(playback): stabilize recovery application ownership * fix(ci): classify playback util coverage * fix(e2e): preserve playback fixture bytes
105 lines
2.8 KiB
TypeScript
105 lines
2.8 KiB
TypeScript
import { getPlaybackMediaExtensionFromUrl } from '@iptvnator/playback/util';
|
|
|
|
/**
|
|
* ArtPlayer option overrides for the legacy and shared-control surfaces.
|
|
*
|
|
* The flag-off branch deliberately mirrors the existing runtime options. The
|
|
* flag-on branch disables every optional ArtPlayer interaction owner; a
|
|
* transparent capture surface blocks the core click/double-click handlers that
|
|
* ArtPlayer installs independently of these options.
|
|
*/
|
|
export function buildArtPlayerChrome(
|
|
sharedControls: boolean
|
|
): Record<string, unknown> {
|
|
if (!sharedControls) {
|
|
return {
|
|
pip: true,
|
|
autoPlayback: true,
|
|
autoSize: true,
|
|
autoMini: true,
|
|
screenshot: true,
|
|
setting: true,
|
|
playbackRate: true,
|
|
aspectRatio: true,
|
|
fullscreen: true,
|
|
fullscreenWeb: true,
|
|
airplay: true,
|
|
};
|
|
}
|
|
|
|
return {
|
|
controls: [],
|
|
pip: false,
|
|
autoPlayback: false,
|
|
autoSize: false,
|
|
autoMini: false,
|
|
screenshot: false,
|
|
setting: false,
|
|
playbackRate: false,
|
|
aspectRatio: false,
|
|
fullscreen: false,
|
|
fullscreenWeb: false,
|
|
airplay: false,
|
|
hotkey: false,
|
|
fastForward: false,
|
|
autoOrientation: false,
|
|
lock: false,
|
|
gesture: false,
|
|
miniProgressBar: false,
|
|
subtitleOffset: false,
|
|
};
|
|
}
|
|
|
|
export function resolveArtPlayerIsLive(
|
|
sharedControls: boolean,
|
|
authoritativeIsLive: boolean,
|
|
url: string
|
|
): boolean {
|
|
if (sharedControls) {
|
|
return authoritativeIsLive;
|
|
}
|
|
|
|
const extension = getPlaybackMediaExtensionFromUrl(url);
|
|
return extension === 'm3u8' || extension === 'ts' || !extension;
|
|
}
|
|
|
|
export function getArtPlayerVideoType(url: string): string {
|
|
const extension = getPlaybackMediaExtensionFromUrl(url);
|
|
switch (extension) {
|
|
case 'mkv':
|
|
return 'video/matroska';
|
|
case 'm3u8':
|
|
return 'm3u8';
|
|
case 'mp4':
|
|
return 'mp4';
|
|
case 'mpd':
|
|
return 'mpd';
|
|
case 'ts':
|
|
return 'ts';
|
|
default:
|
|
// Extensionless IPTV proxy/script URLs are predominantly raw
|
|
// MPEG-TS and retain the established ArtPlayer fallback.
|
|
return extension ? 'auto' : 'ts';
|
|
}
|
|
}
|
|
|
|
export function exitOwnedArtPlayerFullscreen(
|
|
sharedControls: boolean,
|
|
surface: HTMLElement | undefined,
|
|
reportError: (error: unknown) => void
|
|
): void {
|
|
if (
|
|
!sharedControls ||
|
|
document.fullscreenElement !== surface ||
|
|
typeof document.exitFullscreen !== 'function'
|
|
) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
void Promise.resolve(document.exitFullscreen()).catch(reportError);
|
|
} catch (error: unknown) {
|
|
reportError(error);
|
|
}
|
|
}
|