Files
OrionTV/services/m3u8.ts
zimplexing 836285dbd5 feat(player): enhance video playback with SSL error fallback and performance optimizations
- Add comprehensive SSL certificate error detection and automatic source switching
- Implement smart video source fallback strategy with failed source tracking
- Enhance video component with optimized event handlers and useCallback patterns
- Add explicit playAsync() call in onLoad to improve auto-play reliability
- Integrate performance monitoring with detailed logging throughout playback chain
- Optimize Video component props with useMemo and custom useVideoHandlers hook
- Add source matching fixes for fallback scenarios in DetailStore
- Enhance error handling with user-friendly messages and recovery strategies
2025-08-15 22:41:18 +08:00

77 lines
2.5 KiB
TypeScript

interface CacheEntry {
resolution: string | null;
timestamp: number;
}
const resolutionCache: { [url: string]: CacheEntry } = {};
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
export const getResolutionFromM3U8 = async (
url: string,
signal?: AbortSignal
): Promise<string | null> => {
const perfStart = performance.now();
console.info(`[PERF] M3U8 resolution detection START - url: ${url.substring(0, 100)}...`);
// 1. Check cache first
const cachedEntry = resolutionCache[url];
if (cachedEntry && Date.now() - cachedEntry.timestamp < CACHE_DURATION) {
const perfEnd = performance.now();
console.info(`[PERF] M3U8 resolution detection CACHED - took ${(perfEnd - perfStart).toFixed(2)}ms, resolution: ${cachedEntry.resolution}`);
return cachedEntry.resolution;
}
if (!url.toLowerCase().endsWith(".m3u8")) {
console.info(`[PERF] M3U8 resolution detection SKIPPED - not M3U8 file`);
return null;
}
try {
const fetchStart = performance.now();
const response = await fetch(url, { signal });
const fetchEnd = performance.now();
console.info(`[PERF] M3U8 fetch took ${(fetchEnd - fetchStart).toFixed(2)}ms, status: ${response.status}`);
if (!response.ok) {
return null;
}
const parseStart = performance.now();
const playlist = await response.text();
const lines = playlist.split("\n");
let highestResolution = 0;
let resolutionString: string | null = null;
for (const line of lines) {
if (line.startsWith("#EXT-X-STREAM-INF")) {
const resolutionMatch = line.match(/RESOLUTION=(\d+)x(\d+)/);
if (resolutionMatch) {
const height = parseInt(resolutionMatch[2], 10);
if (height > highestResolution) {
highestResolution = height;
resolutionString = `${height}p`;
}
}
}
}
const parseEnd = performance.now();
console.info(`[PERF] M3U8 parsing took ${(parseEnd - parseStart).toFixed(2)}ms, lines: ${lines.length}`);
// 2. Store result in cache
resolutionCache[url] = {
resolution: resolutionString,
timestamp: Date.now(),
};
const perfEnd = performance.now();
console.info(`[PERF] M3U8 resolution detection COMPLETE - took ${(perfEnd - perfStart).toFixed(2)}ms, resolution: ${resolutionString}`);
return resolutionString;
} catch (error) {
const perfEnd = performance.now();
console.info(`[PERF] M3U8 resolution detection ERROR - took ${(perfEnd - perfStart).toFixed(2)}ms, error: ${error}`);
return null;
}
};