Hls.Events.LEVEL_LOADED, function(){ setPreloadPct(28); requestPendingPlay(false); }); hls.on(window.Hls.Events.FRAG_BUFFERED, function(){ setPreloadPct(30); requestPendingPlay(true); updateControls(); }); } // 检查HLS.js是否已加载 if(window.Hls){ doInit(); }else{ // 等待HLS.js加载,增加等待时间和检查频率 var checkCount = 0; var maxChecks = 100; // 最多等待5秒 var checkTimer = setInterval(function(){ checkCount++; if(window.Hls){ clearInterval(checkTimer); doInit(); }else if(checkCount > maxChecks){ clearInterval(checkTimer); console.warn('HLS.js 加载超时,回退到原生播放'); videoEl.src = videoSrc; videoEl.setAttribute('data-loaded','1'); hlsReady = true; try{ videoEl.load(); }catch(e){} } }, 50); } } function fmtTime(sec){ sec = Math.max(0, Math.floor(sec || 0)); var m = Math.floor(sec / 60); var s = sec % 60; return String(m).padStart(2,'0') + ':' + String(s).padStart(2,'0'); } function iconHtml(id){ return ''; } function loadingIconHtml(){ return ''; } function setBtnIcon(btn, id){ if(!btn) return; btn.innerHTML = iconHtml(id); } function setPosterVisible(visible){ if(posterEl){ if(visible) posterEl.classList.remove('is-hidden'); else posterEl.classList.add('is-hidden'); } } function setCenterVisible(visible){ if(centerPlayEl){ if(visible) centerPlayEl.classList.remove('is-hidden'); else centerPlayEl.classList.add('is-hidden'); } } function setCenterLoading(loading){ if(!centerPlayEl) return; centerPlayEl.innerHTML = loading ? loadingIconHtml() : iconHtml('icon-play'); } function updateControls(){ if(!videoEl) return; var d = isFinite(videoEl.duration) ? videoEl.duration : 0; var t = isFinite(videoEl.currentTime) ? videoEl.currentTime : 0; var bEnd = 0; if(d > 0){ try{ var b = videoEl.buffered; if(b && b.length){ for(var i=0;i 0){ var v = Math.round((t / d) * 1000); rangeEl.value = String(Math.max(0, Math.min(1000, v))); var pPct = (t / d) * 100; var bPct = (bEnd / d) * 100; if(bPct < pPct) bPct = pPct; if(bPct < preloadPct) bPct = preloadPct; rangeEl.style.setProperty('--p', pPct.toFixed(2) + '%'); rangeEl.style.setProperty('--b', bPct.toFixed(2) + '%'); }else{ rangeEl.value = '0'; rangeEl.style.setProperty('--p', '0%'); rangeEl.style.setProperty('--b', preloadPct.toFixed(2) + '%'); } } if(btnPlay){ setBtnIcon(btnPlay, videoEl.paused ? 'icon-play' : 'icon-pause'); } if(volEl){ var vv = Math.round((videoEl.muted ? 0 : (videoEl.volume || 0)) * 100); volEl.value = String(Math.max(0, Math.min(100, vv))); volEl.style.setProperty('--p', (Math.max(0, Math.min(100, vv))).toFixed(2) + '%'); } if(btnMute){ var cur = (videoEl.muted ? 0 : (videoEl.volume || 0)); if(cur <= 0.001) setBtnIcon(btnMute, 'icon-volume-mute'); else if(cur < 0.5) setBtnIcon(btnMute, 'icon-volume-down'); else setBtnIcon(btnMute, 'icon-volume-up'); } var atBeginning = t <= 0.02; if(!hasRenderableFrame){ if(pendingPlay){ setPosterVisible(false); setCenterVisible(true); setCenterLoading(true); }else{ setPosterVisible(true); setCenterVisible(true); setCenterLoading(false); } }else if(videoEl.paused && atBeginning){ setPosterVisible(true); setCenterVisible(true); setCenterLoading(false); }else{ setPosterVisible(false); setCenterVisible(false); } } function playToggle(){ if(!videoEl) return; // 首次点击播放时初始化视频 if(!videoInitialized && videoSrc){ ensureVideoLoaded(); } if(videoEl.paused){ pendingPlay = true; requestPendingPlay(true); setCenterVisible(true); setCenterLoading(true); setPosterVisible(false); updateControls(); }else{ pendingPlay = false; clearPlayRetry(); videoEl.pause(); updateControls(); } } function enterFullscreen(){ if(!videoEl) return; var el = videoEl; var fn = el.requestFullscreen || el.webkitRequestFullscreen || el.mozRequestFullScreen || el.msRequestFullscreen; if(fn) { try { fn.call(el); } catch(e) {} } } if(videoEl){ videoEl.controls = false; videoEl.preload = 'auto'; try{ var savedVol = null; try{ savedVol = localStorage.getItem('player_volume'); }catch(e){} if(savedVol !== null){ var sv = parseInt(savedVol, 10); if(!isNaN(sv)) videoEl.volume = Math.max(0, Math.min(1, sv / 100)); } }catch(e){} videoEl.addEventListener('loadedmetadata', updateControls); videoEl.addEventListener('durationchange', updateControls); videoEl.addEventListener('progress', updateControls); videoEl.addEventListener('timeupdate', updateControls); videoEl.addEventListener('canplay', function(){ setPreloadPct(100); if(videoEl.readyState >= 2) markFirstFrameReady(); requestPendingPlay(true); updateControls(); }); videoEl.addEventListener('loadeddata', function(){ setPreloadPct(80); markFirstFrameReady(); requestPendingPlay(false); updateControls(); }); videoEl.addEventListener('play', function(){ if(videoEl.readyState >= 2) markFirstFrameReady(); updateControls(); }); videoEl.addEventListener('playing', function(){ markFirstFrameReady(); pendingPlay = false; clearPlayRetry(); updateControls(); }); videoEl.addEventListener('pause', updateControls); videoEl.addEventListener('ended', function(){ try{ videoEl.currentTime = 0; }catch(e){} hasRenderableFrame = false; pendingPlay = false; clearPlayRetry(); updateControls(); }); if(shellEl){ shellEl.addEventListener('click', function(ev){ try{ if(controlsEl && controlsEl.contains(ev.target)) return; if(rangeEl && rangeEl.contains(ev.target)) return; if(volEl && volEl.contains(ev.target)) return; if(btnFull && btnFull.contains(ev.target)) return; if(btnMute && btnMute.contains(ev.target)) return; if(btnPlay && btnPlay.contains(ev.target)) return; }catch(e){} playToggle(); }); } if(centerPlayEl) centerPlayEl.addEventListener('click', function(ev){ try{ ev.preventDefault(); ev.stopPropagation(); }catch(e){} playToggle(); }); if(btnPlay) btnPlay.addEventListener('click', playToggle); if(btnFull) btnFull.addEventListener('click', enterFullscreen); if(btnMute){ btnMute.addEventListener('click', function(){ if(!videoEl) return; videoEl.muted = !videoEl.muted; if(!videoEl.muted && (videoEl.volume || 0) <= 0.001){ videoEl.volume = 0.8; } try{ localStorage.setItem('player_volume', String(Math.round((videoEl.muted ? 0 : videoEl.volume) * 100))); }catch(e){} updateControls(); }); } if(rangeEl){ rangeEl.addEventListener('input', function(){ if(!videoEl) return; var d = isFinite(videoEl.duration) ? videoEl.duration : 0; if(d <= 0) return; var pct = (parseInt(rangeEl.value,10) || 0) / 1000; try{ videoEl.currentTime = d * pct; }catch(e){} updateControls(); }); } if(volEl){ volEl.addEventListener('input', function(){ if(!videoEl) return; var v = (parseInt(volEl.value,10) || 0) / 100; videoEl.volume = Math.max(0, Math.min(1, v)); videoEl.muted = (v <= 0.001); try{ localStorage.setItem('player_volume', String(Math.round(videoEl.volume * 100))); }catch(e){} updateControls(); }); } updateControls(); } if(videoEl && videoSrc){ ensureVideoLoaded(); updateControls(); } let currentIndex = 0; function updateTab(index) { if (index < 0 || index >= players.length) return; // 移除全部 active players.forEach(p => p.classList.remove('active')); thumbnails.forEach(t => t.classList.remove('active')); // 添加当前 active players[index].classList.add('active'); thumbnails[index].classList.add('active'); currentIndex = index; // 如果是视频类型,设置 iframe.src(首次或切换到视频时) const player = players[index]; if (player.dataset.type === 'video') { ensureVideoLoaded(); } else { try{ if(videoEl) videoEl.pause(); }catch(e){} hasRenderableFrame = false; pendingPlay = false; clearPlayRetry(); setPosterVisible(true); updateControls(); } } // 点击缩略图事件 thumbnails.forEach((thumb, index) => { thumb.addEventListener('click', () => updateTab(index)); }); // 左右按钮事件 prevBtn.addEventListener('click', () => { let newIndex = currentIndex - 1; if (newIndex < 0) newIndex = players.length - 1; updateTab(newIndex); }); nextBtn.addEventListener('click', () => { let newIndex = currentIndex + 1; if (newIndex >= players.length) newIndex = 0; updateTab(newIndex); }); // 初始化:若首项是视频,则默认展示第一张图片;其余情况仍展示第一个 var initialIndex = 0; if(players.length > 1 && players[0] && players[0].dataset && players[0].dataset.type === 'video'){ for(var ii = 1; ii < players.length; ii++){ if(players[ii] && players[ii].dataset && players[ii].dataset.type === 'image'){ initialIndex = ii; break; } } } updateTab(initialIndex); });