初始提交:短剧库源码(含转码优化 ultrafast)
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
(() => {
|
||||
function createMediaLoader(environment, video, onError) {
|
||||
let hls = null;
|
||||
let generation = 0;
|
||||
let cancelPending = null;
|
||||
function destroy() {
|
||||
generation++;
|
||||
if (cancelPending) cancelPending();
|
||||
cancelPending = null;
|
||||
if (hls) hls.destroy();
|
||||
hls = null;
|
||||
}
|
||||
function failure(message, network) {
|
||||
const error = new Error(message);
|
||||
error.playbackNetwork = network;
|
||||
error.playbackDecode = !network;
|
||||
return error;
|
||||
}
|
||||
async function load(plan, nativeHls, signal, offset = 0) {
|
||||
destroy();
|
||||
const current = generation;
|
||||
if (signal.aborted) throw new DOMException('已取消', 'AbortError');
|
||||
if (plan.player === 'mp4' && plan.mime && !video.canPlayType(plan.mime)) throw failure('浏览器不支持此媒体编码,正在尝试兼容播放', false);
|
||||
await new Promise((resolve, reject) => {
|
||||
let settled = false;
|
||||
const timer = setTimeout(() => finish(failure('媒体加载超时,请重试', true)), 60000);
|
||||
const abort = () => finish(new DOMException('已取消', 'AbortError'));
|
||||
const metadata = () => finish();
|
||||
const failed = () => finish(failure('浏览器无法读取此视频', video.error?.code === 2));
|
||||
function finish(error) {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
clearTimeout(timer);
|
||||
signal.removeEventListener('abort', abort);
|
||||
video.removeEventListener('loadedmetadata', metadata);
|
||||
video.removeEventListener('error', failed);
|
||||
cancelPending = null;
|
||||
if (error && current === generation) {
|
||||
generation++;
|
||||
if (hls) hls.destroy();
|
||||
hls = null;
|
||||
}
|
||||
if (error) reject(error); else resolve();
|
||||
}
|
||||
cancelPending = abort;
|
||||
signal.addEventListener('abort', abort, {once: true});
|
||||
video.addEventListener('loadedmetadata', metadata, {once: true});
|
||||
video.addEventListener('error', failed, {once: true});
|
||||
try {
|
||||
if (plan.player === 'hls' && !nativeHls) {
|
||||
const Hls = environment.Hls;
|
||||
if (!Hls?.isSupported()) {finish(failure('此浏览器没有可用的 HLS 播放通道', false)); return;}
|
||||
hls = new Hls({enableWorker: true, lowLatencyMode: false, maxBufferLength: 30, maxMaxBufferLength: 60, backBufferLength: 20,
|
||||
manifestLoadingMaxRetry: 1, levelLoadingMaxRetry: 1, fragLoadingMaxRetry: 1, startPosition: Math.max(0, Number(offset) || 0)});
|
||||
hls.on(Hls.Events.ERROR, (_, data) => {
|
||||
if (!data.fatal || current !== generation || signal.aborted) return;
|
||||
const error = failure(data.type === Hls.ErrorTypes.NETWORK_ERROR ? '视频连接失败,请重试' : '此媒体需要兼容播放', data.type === Hls.ErrorTypes.NETWORK_ERROR);
|
||||
if (!settled) finish(error); else onError(error);
|
||||
});
|
||||
hls.on(Hls.Events.MEDIA_ATTACHED, () => {
|
||||
if (current !== generation || signal.aborted) return;
|
||||
try {hls.loadSource(plan.url);} catch (error) {finish(failure(error.message || '无法加载 HLS 媒体', false));}
|
||||
});
|
||||
hls.attachMedia(video);
|
||||
} else {
|
||||
video.src = plan.url;
|
||||
video.load();
|
||||
}
|
||||
} catch (error) {finish(failure(error.message || '无法初始化播放器', false));}
|
||||
});
|
||||
}
|
||||
return {load, destroy};
|
||||
}
|
||||
if (typeof module !== 'undefined' && module.exports) module.exports = createMediaLoader;
|
||||
else window.JukuPlayerMedia = createMediaLoader;
|
||||
})();
|
||||
Reference in New Issue
Block a user