PageSourceSearch

https://xoigac.top/dist/js/player.bundle.js?v=8u5CWjOuanIR8_RT1hwbFVrUcYrqqHSdSl_i6iFuPEQ

js xoigac.top collected 2026-10-10 02:21:58 UTC 74,951 bytes, 1 lines download raw bytes

1!function(){"use strict";if(window.IVSPlayerAdapter)return;let sdkLoadPromise=null,sdkLoaded=!1,debugPanel=null,debugLogs=[];const DEBUG_ENABLED=function(){try{if("undefined"==typeof location)return!1;const host=location.hostname||"";return"localhost"===host||"127.0.0.1"===host||"1"===new URLSearchParams(location.search||"").get("ivsdebug")}catch(e){return!1}}();function createDebugPanel(){if(!DEBUG_ENABLED||debugPanel)return;debugPanel=document.createElement("div"),debugPanel.id="ivs-debug-panel",debugPanel.innerHTML='\n            <style>\n                #ivs-debug-panel {\n                    position: fixed;\n                    bottom: 10px;\n                    left: 10px;\n                    right: 10px;\n                    max-height: 200px;\n                    background: rgba(0,0,0,0.9);\n                    color: #0f0;\n                    font-family: monospace;\n                    font-size: 11px;\n                    padding: 8px;\n                    border-radius: 8px;\n                    z-index: 99999;\n                    overflow-y: auto;\n                    display: none;\n                    /* 防止触摸事件冒泡到页面 */\n                    touch-action: pan-y;\n                    overscroll-behavior: contain;\n                }\n                #ivs-debug-panel.show { display: block; }\n                #ivs-debug-panel .log-error { color: #f55; }\n                #ivs-debug-panel .log-warn { color: #fa0; }\n                #ivs-debug-panel .log-info { color: #0af; }\n                #ivs-debug-panel .log-entry { \n                    margin: 2px 0; \n                    word-break: break-all;\n                    border-bottom: 1px solid #333;\n                    padding-bottom: 2px;\n                }\n                #ivs-debug-toggle {\n                    position: fixed;\n                    bottom: 10px;\n                    right: 10px;\n                    width: 40px;\n                    height: 40px;\n                    background: #333;\n                    color: #0f0;\n                    border: none;\n                    border-radius: 50%;\n                    font-size: 18px;\n                    z-index: 100000;\n                    cursor: pointer;\n                    /* 防止触摸事件冒泡 */\n                    touch-action: none;\n                }\n                #ivs-debug-clear {\n                    position: absolute;\n                    top: 5px;\n                    right: 5px;\n                    background: #555;\n                    color: #fff;\n                    border: none;\n                    padding: 2px 8px;\n                    border-radius: 4px;\n                    font-size: 10px;\n                    cursor: pointer;\n                    /* 防止触摸事件冒泡 */\n                    touch-action: none;\n                }\n                #ivs-debug-copy {\n                    position: absolute;\n                    top: 5px;\n                    right: 50px;\n                    background: #555;\n                    color: #fff;\n                    border: none;\n                    padding: 2px 8px;\n                    border-radius: 4px;\n                    font-size: 10px;\n                    cursor: pointer;\n                    /* 防止触摸事件冒泡 */\n                    touch-action: none;\n                }\n                #ivs-debug-copy.copied {\n                    background: #0a0;\n                }\n                #ivs-debug-content {\n                    margin-top: 25px;\n                    /* 允许内容区域滚动 */\n                    overflow-y: auto;\n                    max-height: 165px;\n                }\n            </style>\n            <button id="ivs-debug-copy">复制</button>\n            <button id="ivs-debug-clear">清空</button>\n            <div id="ivs-debug-content"></div>\n        ',document.body.appendChild(debugPanel),debugPanel.addEventListener("touchstart",e=>{e.stopPropagation()},{passive:!0}),debugPanel.addEventListener("touchmove",e=>{const content=debugPanel.querySelector("#ivs-debug-content");content&&content.contains(e.target)&&e.stopPropagation()},{passive:!0}),debugPanel.querySelector("#ivs-debug-clear").onclick=()=>{debugLogs=[],updateDebugPanel()};const copyBtn=debugPanel.querySelector("#ivs-debug-copy");copyBtn.onclick=async()=>{const logText=debugLogs.map(log=>`[${log.time}] [${log.type.toUpperCase()}] ${log.msg}`).join("\n");try{await navigator.clipboard.writeText(logText),copyBtn.textContent="已复制✓",copyBtn.classList.add("copied"),setTimeout(()=>{copyBtn.textContent="复制",copyBtn.classList.remove("copied")},2e3)}catch(err){const textarea=document.createElement("textarea");textarea.value=logText,textarea.style.position="fixed",textarea.style.opacity="0",document.body.appendChild(textarea),textarea.select();try{document.execCommand("copy"),copyBtn.textContent="已复制✓",copyBtn.classList.add("copied"),setTimeout(()=>{copyBtn.textContent="复制",copyBtn.classList.remove("copied")},2e3)}catch(e){copyBtn.textContent="复制失败",setTimeout(()=>{copyBtn.textContent="复制"},2e3)}document.body.removeChild(textarea)}}}function updateDebugPanel(){if(!debugPanel)return;const content=debugPanel.querySelector("#ivs-debug-content");content&&(content.innerHTML=debugLogs.slice(-50).map(log=>`<div class="log-entry log-${log.type}">[${log.time}] ${log.msg}</div>`).join(""),content.scrollTop=content.scrollHeight)}function debugLog(type,...args){const time=(new Date).toLocaleTimeString(),msg=args.map(a=>"object"==typeof a?JSON.stringify(a):String(a)).join(" ");debugLogs.push({type:type,time:time,msg:msg}),"error"===type?console.error("[IVS-DEBUG]",...args):"warn"===type&&console.warn("[IVS-DEBUG]",...args),updateDebugPanel()}function isMobileDevice(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)}function isIOSDevice(){return!(!/iPad|iPhone|iPod/.test(navigator.userAgent)||window.MSStream)||"MacIntel"===navigator.platform&&navigator.maxTouchPoints>1}function isIOSSafari(){const ua=navigator.userAgent;return!(!isIOSDevice()||/CriOS/i.test(ua)||/FxiOS/i.test(ua)||/EdgiOS/i.test(ua)||/OPiOS/i.test(ua)||!/Safari/i.test(ua))}async function loadIVSSDK(){if(!sdkLoaded||!window.IVSPlayer)return sdkLoadPromise||(sdkLoadPromise=new Promise((resolve,reject)=>{if(window.IVSPlayer)return sdkLoaded=!0,void resolve();const script=document.createElement("script");script.src="https://player.live-video.net/1.48.0/amazon-ivs-player.min.js",script.async=!0,script.onload=()=>{window.IVSPlayer?(sdkLoaded=!0,resolve()):reject(new Error("SDK 加载后未找到 IVSPlayer"))},script.onerror=()=>{sdkLoadPromise=null,reject(new Error("SDK 加载失败"))},document.head.appendChild(script)}),sdkLoadPromise)}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",createDebugPanel):createDebugPanel(),"serviceWorker"
1in navigator&&navigator.serviceWorker.addEventListener("message",event=>{if(event.data&&"IVS_SW_DEBUG"===event.data.type){const{logType:logType,message:message,data:data}=event.data;debugLog(logType,"[SW]",message,data)}}),window.IVSPlayerAdapter=class IVSPlayerAdapter{constructor(videoElement,config={}){this.video=videoElement,this.player=null,this.playbackUrl=null,this.eventListeners=new Map,this.qualitySelector=null,this.latencyInterval=null;const ios=isIOSDevice();this.config={autoplay:!0,muted:!0,lowLatency:!ios,showQualitySelector:!0,qualitySelectorPosition:"top-right",qualitySelectorExpanded:!isMobileDevice(),logLevel:"error",initialBufferDuration:ios?2.5:null,enableLatencyMonitor:DEBUG_ENABLED,...config},ios&&void 0===config.lowLatency&&(this.config.lowLatency=!1),this.state="idle",this.destroyed=!1,this._initializing=!1,isMobileDevice(),isIOSDevice(),this.config.qualitySelectorExpanded}async initialize(playbackUrl){if(this.destroyed)throw new Error("播放器已销毁");if(this._initializing)debugLog("warn","正在初始化中,忽略重复调用");else{this._initializing=!0,this.playbackUrl=playbackUrl,this._setState("loading"),this.emit("loading"),debugLog("info","开始初始化播放器"),debugLog("info","URL:",playbackUrl),debugLog("info","iOS:",isIOSDevice(),"Safari:",isIOSSafari());try{if(debugLog("info","加载 IVS SDK..."),await loadIVSSDK(),debugLog("info","SDK 加载成功"),!window.IVSPlayer.isPlayerSupported)throw new Error("当前浏览器不支持 IVS 播放器");debugLog("info","浏览器支持检查通过");let playerConfig={},usedServiceWorker=!1;debugLog("info","iOS Safari: 标准模式(延迟 10-11秒)");try{debugLog("info","创建播放器实例...",playerConfig),this.player=window.IVSPlayer.create(playerConfig),debugLog("info","播放器实例创建成功")}catch(createError){if(debugLog("error","播放器创建失败:",createError.message),!usedServiceWorker)throw createError;debugLog("warn","SW 模式失败,降级到标准模式(延迟 10+ 秒)");try{delete playerConfig.serviceWorker,this.player=window.IVSPlayer.create(playerConfig),debugLog("info","播放器实例创建成功(标准模式)"),usedServiceWorker=!1}catch(fallbackError){throw debugLog("error","降级模式也失败:",fallbackError.message),fallbackError}}if(debugLog("info","附加到视频元素..."),this.player.attachHTMLVideoElement(this.video),isIOSDevice()){const onLoadedData=()=>{debugLog("info","iOS: 视频数据已加载(第一帧)"),this.video.style.opacity="1",this.video.classList.add("loaded"),this.video.removeEventListener("loadeddata",onLoadedData)};this.video.addEventListener("loadeddata",onLoadedData);const onCanPlay=()=>{debugLog("info","iOS: 视频可以播放"),this.video.style.opacity="1",this.video.classList.add("loaded"),this.video.removeEventListener("canplay",onCanPlay)};this.video.addEventListener("canplay",onCanPlay)}if(this.config.lowLatency)this.player.setLiveLowLatencyEnabled(!0),debugLog("info","低延迟模式已启用");else try{this.player.setLiveLowLatencyEnabled(!1),debugLog("info","低延迟模式已关闭(省电/稳播)")}catch(e){debugLog("warn","无法关闭低延迟:",e.message)}try{let bufferSec=this.config.initialBufferDuration;null==bufferSec&&(isIOSDevice()?(this.config.lowLatency,bufferSec=2.5):bufferSec=isMobileDevice()?this.config.lowLatency?.3:1:this.config.lowLatency?.2:1),this.player.setInitialBufferDuration(bufferSec),debugLog("info",`初始缓冲: ${bufferSec}s`)}catch(e){debugLog("warn","无法设置初始缓冲:",e.message),console.warn("[IVSPlayer] 无法设置初始缓冲:",e.message)}if(this.config.lowLatency&&!isIOSDevice())try{this.player.setRebufferToLive(!0),debugLog("info","rebufferToLive 已启用")}catch(e){debugLog("warn","无法设置 rebufferToLive:",e.message),console.warn("[IVSPlayer] 无法设置 rebufferToLive:",e.message)}try{const levelName=String(this.config.logLevel||"error").toUpperCase(),levels=window.IVSPlayer&&window.IVSPlayer.Player&&window.IVSPlayer.Player.LogLevel;if(levels&&"function"==typeof this.player.setLogLevel){const level=null!=levels[levelName]?levels[levelName]:levels.ERROR;this.player.setLogLevel(level),debugLog("info","IVS logLevel:",levelName)}}catch(e){debugLog("warn","无法设置 logLevel:",e.message)}
1this.player.setAutoplay(this.config.autoplay),this.player.setAutoQualityMode(!0),this.player.setVolume(.5),this._setupEventListeners();let finalPlaybackUrl=playbackUrl;debugLog("info","使用原始 URL 播放"),isIOSSafari()&&debugLog("info","iOS Safari 标准延迟: 10-11秒"),await new Promise(resolve=>{"function"==typeof requestAnimationFrame?requestAnimationFrame(()=>requestAnimationFrame(resolve)):setTimeout(resolve,50)}),debugLog("info","加载流:",finalPlaybackUrl),this.player.load(finalPlaybackUrl),isIOSDevice()&&(this.video.setAttribute("playsinline",""),this.video.setAttribute("webkit-playsinline",""),this.video.muted=!0,debugLog("info","iOS 视频属性已设置"));try{const playPromise=this.player.play();void 0!==playPromise&&playPromise.then(()=>{debugLog("info","自动播放成功")}).catch(error=>{debugLog("warn","自动播放失败:",error.message),console.warn("[IVSPlayer] 自动播放失败,需要用户交互:",error.message),this.emit("autoplayBlocked")})}catch(playError){debugLog("warn","播放调用失败:",playError.message),console.warn("[IVSPlayer] 播放调用失败:",playError.message)}this._setState("ready"),this.emit("initialized"),debugLog("info","初始化完成,等待播放..."),this._initializing=!1}catch(error){throw debugLog("error","初始化失败:",error.message,error.stack),console.error("[IVSPlayer] 初始化失败:",error.message),this._setState("error"),this.emit("error",{type:"INIT_ERROR",message:error.message}),this._initializing=!1,error}}}_setupEventListeners(){if(!this.player||!window.IVSPlayer)return;const{PlayerState:PlayerState,PlayerEventType:PlayerEventType}=window.IVSPlayer;this.player.addEventListener(PlayerState.READY,()=>{debugLog("info","状态: READY"),this._setState("ready"),this.emit("ready"),this.config.showQualitySelector&&(isIOSDevice()?(debugLog("info","iOS 浏览器只支持自动质量模式"),this._iosAutoOnly=!0):setTimeout(()=>this._setupQualitySelector(),500))}),this.player.addEventListener(PlayerState.PLAYING,()=>{debugLog("info","状态: PLAYING ✓"),this._setState("playing"),this.emit("playing"),isIOSDevice()&&this.video&&(this.video.style.opacity="1",this.video.classList.add("loaded"),debugLog("info","iOS 视频已显示"))}),this.player.addEventListener(PlayerState.BUFFERING,()=>{debugLog("warn","状态: BUFFERING..."),this._setState("buffering"),this.emit("buffering")}),this.player.addEventListener(PlayerState.IDLE,()=>{debugLog("info","状态: IDLE"),this.destroyed||this._setState("idle"),this.emit("idle")}),this.player.addEventListener(PlayerState.ENDED,()=>{debugLog("info","状态: ENDED"),this.emit("ended")}),this.player.addEventListener(PlayerEventType.ERROR,error=>{const isRecoverableNoSource="ErrorNoSource"===error.type&&!1!==error.recoverable;(this.isDestroying||window.isSwitchingStreamer)&&("ErrorNoSource"===error.type||error.message&&error.message.includes("Empty src attribute"))?debugLog("info","销毁/切换过程中的正常错误,忽略:",error.type,error.message):error.message&&error.message.includes("Empty src attribute")?debugLog("warn","Empty src attribute 错误,可能是切换过程中的正常现象"):isRecoverableNoSource?debugLog("info","源未就绪(可恢复,SDK 将自动重试):",error.message):(debugLog("error","播放错误:",error.type,error.message,error.code),console.error("[IVSPlayer] 错误:",error),this._setState("error"),this.emit("error",{type:error.type||"UNKNOWN",message:error.message||"播放错误",code:error.code,recoverable:error.recoverable}))}),this.player.addEventListener(PlayerEventType.QUALITY_CHANGED,quality=>{debugLog("info","质量变化:",quality?.name,quality?.height+"p"),this._updateQualityButtonText(),this.emit("qualityChanged",quality)}),this.config.enableLatencyMonitor&&this._startLatencyMonitor()}_t(key,fallback){if(window.L&&window.L.T){const translated=window.L.T(key);if(translated&&!translated.includes(key.split(".").pop()))return translated}return fallback}_onQualitiesAvailable(){if(this._updateQualityButtonText(),this.qualitySelector){const menu=this.qual
1itySelector.querySelector(".ivs-quality-menu");menu&&menu.classList.contains("show")&&this._buildQualityMenu()}}_setupQualitySelector(){this.player&&this.video&&(isIOSDevice()||this._createQualitySelector())}_createQualitySelector(){if(!this.player||!this.video)return;const playerWrapper=this.video.closest(".focus-player-wrapper")||this.video.closest(".live-player-wrapper");let actionsContainer=null;playerWrapper&&(actionsContainer=playerWrapper.querySelector(".focus-player-actions"));const container=actionsContainer||this.video.closest(".focus-player-container")||this.video.closest(".live-player-container")||this.video.parentElement;if(!container)return void console.warn("[IVSPlayer] 未找到播放器容器");const existing=document.querySelector(".ivs-quality-selector");existing&&existing.remove();const selector=document.createElement("div");selector.className="ivs-quality-selector";const isInActions=null!==actionsContainer,autoText=this._t("match.player.quality.auto","自动");if(selector.innerHTML=`\n                <button class="ivs-quality-btn ${isInActions?"in-header":""}" type="button">\n                    <span class="ivs-quality-icon">\n                        <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">\n                            <path d="M19.14 12.94c.04-.31.06-.63.06-.94 0-.31-.02-.63-.06-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.04.31-.06.63-.06.94s.02.63.06.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>\n                        </svg>\n                    </span>\n                    <span class="ivs-quality-text">${autoText}</span>\n                </button>\n                <div class="ivs-quality-menu"></div>\n            `,isInActions){const insertAnchor=actionsContainer.querySelector("#focusMatchDetailLink")||actionsContainer.querySelector(".player-more-dropdown")||actionsContainer.firstChild;actionsContainer.insertBefore(selector,insertAnchor)}else"static"===getComputedStyle(container).position&&(container.style.position="relative"),container.appendChild(selector);this.qualitySelector=selector;const btn=selector.querySelector(".ivs-quality-btn"),menu=selector.querySelector(".ivs-quality-menu");let lastToggleTime=0,touchHandled=!1;const handleToggle=e=>{if(e.preventDefault(),e.stopPropagation(),"click"===e.type&&touchHandled)return void(touchHandled=!1);"touchend"===e.type&&(touchHandled=!0,setTimeout(()=>{touchHandled=!1},300));const now=Date.now();now-lastToggleTime<300||(lastToggleTime=now,this._toggleQualityMenu())};btn.addEventListener("click",handleToggle),btn.addEventListener("touchend",handleToggle,{passive:!1});const closeMenu=e=>{selector.contains(e.target)||menu.classList.remove("show")};document.addEventListener("click",closeMenu),document.addEventListener("touchend",closeMenu),this._updateQualityButtonText()}
1_toggleQualityMenu(){if(!this.qualitySelector||!this.player)return;const menu=this.qualitySelector.querySelector(".ivs-quality-menu");if(menu.classList.contains("show"))menu.classList.remove("show");else if(this._buildQualityMenu(),menu.classList.add("show"),0===(this.player.getQualities()||[]).length){const retryDelays=isIOSDevice()?[500,1e3,2e3,3e3,5e3]:[500,1500];retryDelays.forEach(delay=>{setTimeout(()=>{if(menu.classList.contains("show")&&this.player){const currentQualities=this.player.getQualities()||[];currentQualities.length,(currentQualities.length>0||delay===retryDelays[retryDelays.length-1])&&this._buildQualityMenu()}},delay)})}}_buildQualityMenu(){if(!this.qualitySelector||!this.player)return;const menu=this.qualitySelector.querySelector(".ivs-quality-menu"),qualities=this.player.getQualities()||[],isAuto=this.player.isAutoQualityMode(),currentQuality=this.player.getQuality(),autoText=this._t("match.player.quality.auto","自动"),loadingText=this._t("match.player.quality.loading","加载中...");qualities.length,menu.innerHTML="";const autoOption=document.createElement("div");autoOption.className="ivs-quality-option"+(isAuto?" active":""),autoOption.innerHTML=`\n                <span class="ivs-quality-label">${autoText}</span>\n                ${isAuto?'<span class="ivs-quality-check">✓</span>':""}\n            `;const bindOptionClick=(el,qualityValue)=>{let touchHandled=!1;const handler=e=>{e.preventDefault(),e.stopPropagation(),"click"===e.type&&touchHandled?touchHandled=!1:("touchend"===e.type&&(touchHandled=!0,setTimeout(()=>{touchHandled=!1},300)),this._selectQuality(qualityValue))};el.addEventListener("click",handler),el.addEventListener("touchend",handler,{passive:!1})};if(bindOptionClick(autoOption,"auto"),menu.appendChild(autoOption),0===qualities.length){const loadingOption=document.createElement("div");return loadingOption.className="ivs-quality-option ivs-quality-loading",loadingOption.innerHTML=`<span class="ivs-quality-label">${loadingText}</span>`,void menu.appendChild(loadingOption)}[...qualities].filter(q=>q.height&&q.height>0).sort((a,b)=>(b.height||0)-(a.height||0)).forEach(quality=>{const isActive=!isAuto&&currentQuality&&currentQuality.name===quality.name,option=document.createElement("div");option.className="ivs-quality-option"+(isActive?" active":"");let label=`${quality.height}p`;quality.bitrate&&quality.bitrate>0&&(label+=` <span class="ivs-quality-bitrate">${(quality.bitrate/1e6).toFixed(1)}Mbps</span>`),option.innerHTML=`\n                    <span class="ivs-quality-label">${label}</span>\n                    ${isActive?'<span class="ivs-quality-check">✓</span>':""}\n                `,bindOptionClick(option,quality),menu.appendChild(option)}),menu.children.length}async _selectQuality(quality){if(!this.player)return;
1const menu=this.qualitySelector?.querySelector(".ivs-quality-menu");menu&&menu.classList.remove("show");const textEl=this.qualitySelector?.querySelector(".ivs-quality-text"),autoText=this._t("match.player.quality.auto","自动"),switchingText=this._t("match.player.quality.switching","切换中...");if("auto"===quality)this.player.setAutoQualityMode(!0),textEl&&(textEl.textContent=autoText);else{quality.name,quality.height,textEl&&(textEl.textContent=switchingText);try{this.video&&this.video.removeAttribute("controls");const wasPlaying=!this.player.isPaused();wasPlaying&&(this.player.pause(),await new Promise(r=>setTimeout(r,100))),this.player.setAutoQualityMode(!1),await new Promise(r=>setTimeout(r,100)),this.player.setQuality(quality),quality.name,await new Promise(r=>setTimeout(r,200)),wasPlaying&&this.player.play(),textEl&&(textEl.textContent=`${quality.height}p`),setTimeout(()=>{const newQuality=this.player.getQuality();newQuality&&(newQuality.name,quality.name)},1e3)}catch(error){console.error("[IVSPlayer] 质量切换错误:",error),this._updateQualityButtonText()}}}_updateQualityButtonText(){if(!this.qualitySelector||!this.player)return;
1const textEl=this.qualitySelector.querySelector(".ivs-quality-text");if(!textEl)return;const isAuto=this.player.isAutoQualityMode(),quality=this.player.getQuality(),autoText=this._t("match.player.quality.auto","自动");isAuto?textEl.textContent=autoText:!isAuto&&quality&&quality.height?textEl.textContent=`${quality.height}p`:textEl.textContent=autoText}_startLatencyMonitor(){(this.config.enableLatencyMonitor||DEBUG_ENABLED)&&(this.latencyInterval&&clearInterval(this.latencyInterval),this.latencyInterval=setInterval(()=>{if(this.player&&!this.destroyed){if("undefined"==typeof document||!document.hidden)try{const latency=this.player.getLiveLatency();null!=latency&&(this.emit("latencyUpdate",latency),!this._lastLatencyLog||Date.now()-this._lastLatencyLog>5e3)&&(debugLog("info",`当前延迟: ${latency.toFixed(2)}s`),this._lastLatencyLog=Date.now())}catch(e){}}else clearInterval(this.latencyInterval)},1e3))}_setState(state){this.state=state}getState(){return this.state}seekToLive(){if(!this.player)return!1;try{if("function"==typeof this.player.seekTo){const duration="function"==typeof this.player.getDuration?this.player.getDuration():Number.MAX_SAFE_INTEGER;this.player.seekTo(duration)}return"function"==typeof this.player.setRebufferToLive&&this.player.setRebufferToLive(!0),this.play(),!0}catch(e){return debugLog("warn",`seekToLive failed: ${e.message}`),!1}}play(){this.player&&this.player.play()}pause(){this.player&&this.player.pause()}setMuted(muted){this.player&&this.player.setMuted(muted),this.video&&(this.video.muted=muted)}setVolume(level){this.player&&this.player.setVolume(Math.max(0,Math.min(1,level)))}getQualities(){return this.player&&this.player.getQualities()||[]}getCurrentQuality(){return this.player?this.player.getQuality():null}getLiveLatency(){return this.player&&"function"==typeof this.player.getLiveLatency&&this.player.getLiveLatency()||0}isPlaying(){return"playing"===this.state}async reconnect(){if(!this.player||!this.playbackUrl)throw new Error("无法重连");this.player.load(this.playbackUrl),this.player.play()}async loadStream(playbackUrl){return console.warn("[IVSPlayer] loadStream() 方法已废弃,请使用 initialize() 方法"),await this.initialize(playbackUrl)}async loadStream(playbackUrl){return console.warn("[IVSPlayer] loadStream() 方法已废弃,请使用 initialize() 方法"),this.initialize(playbackUrl)}destroy(){if(!this.destroyed){if(this.destroyed=!0,this.isDestroying=!0,this.latencyInterval&&(clearInterval(this.latencyInterval),this.latencyInterval=null),this.qualitySelector&&(this.qual
1itySelector.remove(),this.qualitySelector=null),this.player){try{this.player.pause(),this.player.delete()}catch(e){console.warn("[IVSPlayer] 销毁时出错:",e.message)}this.player=null}this.video&&(this.video.src="",this.video.load()),this.playbackUrl=null,this._setState("destroyed"),this.emit("destroyed"),this.eventListeners.clear(),this.isDestroying=!1}}on(event,callback){this.eventListeners.has(event)||this.eventListeners.set(event,[]),this.eventListeners.get(event).push(callback)}off(event,callback){if(!this.eventListeners.has(event))return;const listeners=this.eventListeners.get(event),index=listeners.indexOf(callback);index>-1&&listeners.splice(index,1)}emit(event,data){this.eventListeners.has(event)&&this.eventListeners.get(event).forEach(cb=>{try{cb(data)}catch(e){console.error("[IVSPlayer] 事件处理错误:",e)}})}},window.loadIVSSDK=loadIVSSDK}();const CLOUDFLARE_ICE_SERVERS=[{urls:"stun:stun.cloudflare.com:3478"}];let cloudflarePC=null,cloudflareVideoElement=null,cloudflareCleanupVideoListeners=null,cloudflareVideoTrack=null,cloudflareAudioTrack=null;async function initCloudflareWhepPlayer(videoElement,whepUrl){if(cloudflarePC){try{cloudflarePC.signalingState,cloudflarePC.ontrack=null,cloudflarePC.onconnectionstatechange=null,cloudflarePC.oniceconnectionstatechange=null,cloudflarePC.onicegatheringstatechange=null,cloudflarePC.onsignalingstatechange=null,"closed"!==cloudflarePC.signalingState&&cloudflarePC.close()}catch(e){console.warn("[CloudflareWHEP] 关闭旧连接失败:",e)}cloudflarePC=null}if(cloudflareCleanupVideoListeners&&cloudflareVideoElement){try{cloudflareCleanupVideoListeners()}catch(e){console.warn("[CloudflareWHEP] 清理旧的视频事件监听器失败:",e)}cloudflareCleanupVideoListeners=null,cloudflareVideoElement=null}videoElement.srcObject&&(videoElement.srcObject.getTracks().forEach(track=>track.stop()),videoElement.srcObject=null),cloudflareVideoElement=videoElement;try{const pc=new RTCPeerConnection({iceServers:CLOUDFLARE_ICE_SERVERS,bundlePolicy:"max-bundle",rtcpMuxPolicy:"require"});cloudflarePC=pc,pc._isInitializing=!0,pc.signalingState;const mediaStream=new MediaStream;videoElement.srcObject=mediaStream;const isIOS=/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream;if(isIOS){videoElement.setAttribute("playsinline",""),videoElement.setAttribute("webkit-playsinline",""),videoElement.muted=!0;const onLoadedData=()=>{videoElement.style.opacity="1",videoElement.classList.add("loaded"),videoElement.removeEventListener("loadeddata",onLoadedData)};videoElement.addEventListener("loadeddata",onLoadedData);const onCanPlay=()=>{videoElement.style.opacity="1",videoElement.classList.add("loaded"),videoElement.removeEventListener("canplay",onCanPlay)};videoElement.addEventListener("canplay",onCanPlay)}const videoEventListeners={stalled:()=>{setTimeout(()=>{(videoElement.paused||videoElement.ended)&&window.dispatchEvent(new CustomEvent("cloudflareWhepDisconnected",{detail:{whepUrl:whepUrl,reason:"video_stalled"}}))},3e3)},waiting:()=>{},suspend:()=>{},abort:()=>{window.dispatchEvent(new CustomEvent("cloudflareWhepDisconnected",{detail:{whepUrl:whepUrl,reason:"video_abort"}}))},error:event=>{window.dispatchEvent(new CustomEvent("cloudflareWhepError",{detail:{error:"Video error",whepUrl:whepUrl}}))}};Object.keys(videoEventListeners).forEach(eventName=>{videoElement.addEventListener(eventName,videoEventListeners[eventName])});const cleanupVideoListeners=()=>{Object.keys(videoEventListeners).forEach(eventName=>{videoElement.removeEventListener(eventName,videoEventListeners[eventName])})};cloudflareCleanupVideoListeners=cleanupVideoListeners,pc.addTransceiver("video",{direction:"recvonly"}),pc.addTransceiver("audio",{direction:"recvonly"}),pc.ontrack=event=>{event.track.kind,mediaStream.addTrack(event.track),mediaStream.getTracks().map(t=>t.kind).join(", "),"video"===event.track.kind&&(cloudflareVideoTrack=event.track,event.track.onunmute=()=>{videoElement.classList.add("loaded"),isIOS&&(videoElement.style.opacity="1");const metadataEvent=new Event("loadedmetadata");videoElement.dispatchEvent(metadataEvent)},event.track.onended=()=>{event.track.muted,event.track.readyState,window.dispatchEvent(new CustomEvent("cloudflareWhepDisconnected",{detail:{whepUrl:whepUrl,reason:"track_ended"}}))}),"audio"===event.track.kind&&(cloudflareAudioTrack=event.track,event.track.onended=()=>{})},pc.onconnectionstatechange=()=>{if(pc.connectionState,"connected"===pc.connectionState){isIOS&&(videoElement.style.opacity="1",videoElement.classList.add("loaded"));
1const playPromise=videoElement.play();void 0!==playPromise&&playPromise.then(()=>{}).catch(e=>{console.warn("[CloudflareWHEP] 自动播放失败,需要用户交互:",e)}),window.dispatchEvent(new CustomEvent("cloudflareWhepConnected",{detail:{whepUrl:whepUrl}}))}else"failed"===pc.connectionState?(console.error("[CloudflareWHEP] 连接失败"),cleanupVideoListeners(),window.dispatchEvent(new CustomEvent("cloudflareWhepError",{detail:{error:"Connection failed",whepUrl:whepUrl}}))):"disconnected"===pc.connectionState?(console.warn("[CloudflareWHEP] 连接断开"),window.dispatchEvent(new CustomEvent("cloudflareWhepDisconnected",{detail:{whepUrl:whepUrl,reason:"connection_disconnected"}}))):"closed"===pc.connectionState&&(cleanupVideoListeners(),window.dispatchEvent(new CustomEvent("cloudflareWhepClosed",{detail:{whepUrl:whepUrl}})))},pc.oniceconnectionstatechange=()=>{pc.iceConnectionState};const offer=await pc.createOffer();if("closed"===pc.signalingState)throw new Error("RTCPeerConnection 在创建 offer 后被关闭");await pc.setLocalDescription(offer);const response=await fetch(whepUrl,{method:"POST",headers:{"Content-Type":"application/sdp"},body:offer.sdp});if(!response.ok){const errorText=await response.text();if(409===response.status){const waitError=new Error(`WHEP 请求失败: ${response.status} - ${errorText}`);throw waitError.isWaitingForStream=!0,waitError.status=409,waitError}throw new Error(`WHEP 请求失败: ${response.status} - ${errorText}`)}if("closed"===pc.signalingState)throw console.warn("[CloudflareWHEP] RTCPeerConnection 在收到响应后被关闭"),new Error("RTCPeerConnection 在收到响应后被关闭");const answerSdp=await response.text();if("closed"===pc.signalingState)throw console.warn("[CloudflareWHEP] RTCPeerConnection 在收到 answer 后被关闭"),new Error("RTCPeerConnection 已关闭,无法设置远程描述");if(pc!==cloudflarePC)throw console.warn("[CloudflareWHEP] RTCPeerConnection 实例已被替换,停止初始化"),new Error("RTCPeerConnection 实例已被替换");return await pc.setRemoteDescription({type:"answer",sdp:answerSdp}),pc._isInitializing=!1,pc}catch(error){if(console.error("[CloudflareWHEP] 初始化失败:",error),cloudflarePC){try{cloudflarePC.close()}catch(e){}cloudflarePC=null}throw window.dispatchEvent(new CustomEvent("cloudflareWhepError",{detail:{error:error.message,originalError:error,whepUrl:whepUrl}})),error.message&&error.message.includes("RTCPeerConnection 已关闭")&&"function"==typeof showAutoHideErrorTip&&showAutoHideErrorTip("播放器正在切换,请稍候...",2e3,"info"),error}}async function destroyCloudflareWhepPlayer(){if(cloudflareVideoTrack){try{cloudflareVideoTrack.onended=null,cloudflareVideoTrack.onunmute=null}catch(e){console.warn("[CloudflareWHEP] 移除视频轨道监听器失败:",e)}cloudflareVideoTrack=null}if(cloudflareAudioTrack){try{cloudflareAudioTrack.onended=null}catch(e){console.warn("[CloudflareWHEP] 移除音频轨道监听器失败:",e)}cloudflareAudioTrack=null}if(cloudflarePC){try{cloudflarePC.signalingState,cloudflarePC._isInitializing&&await new Promise(resolve=>setTimeout(resolve,100)),cloudflarePC.ontrack=null,cloudflarePC.onconnectionstatechange=null,cloudflarePC.oniceconnectionstatechange=null,cloudflarePC.onicegatheringstatechange=null,cloudflarePC.onsignalingstatechange=null,"closed"!==cloudflarePC.signalingState&&cloudflarePC.close()}catch(e){console.warn("[CloudflareWHEP] 关闭连接失败:",e)}cloudflarePC=null}}function getCloudflareWhepState(){return cloudflarePC?cloudflarePC.connectionState:null}function isCloudflareWhepConnected(){return cloudflarePC&&"connected"===cloudflarePC.connectionState}window.initCloudflareWhepPlayer=initCloudflareWhepPlayer,window.destroyCloudflareWhepPlayer=destroyCloudflareWhepPlayer,window.getCloudflareWhepState=getCloudflareWhepState,window.isCloudflareWhepConnected=isCloudflareWhepConnected,window.initCloudflareWhepPlayer,window.destroyCloudflareWhepPlayer,window.getCloudflareWhepState,window.isCloudflareWhepConnected,Object.defineProperty(window,"initCloudflareWhepPlayer",{value:initCloudflareWhepPlayer,writable:!1,
1configurable:!1}),window.CLOUDFLARE_WHEP_PLAYER_LOADED=!0;const PlayerType={HLS:"HLS",WEBRTC:"WebRTC",AWS_IVS:"AWS-IVS",CLOUDFLARE_STREAM:"Cloudflare-Stream",UNKNOWN:"UNKNOWN"},PlayerStatus={IDLE:"idle",LOADING:"loading",PLAYING:"playing",PAUSED:"paused",BUFFERING:"buffering",ERROR:"error",ENDED:"ended"};class UnifiedPlayerManager{constructor(videoElement,containerElement,config={}){this.video=videoElement,this.container=containerElement,this.currentPlayerType=null,this.currentAdapter=null,this.status=PlayerStatus.IDLE,this.eventListeners=new Map,this.retryCount=0,this.config={maxRetries:3,retryDelay:3e3,autoplay:!0,muted:!0,enableIVSPlayer:!0,ivsFallbackToHLS:!0,logLevel:"info",...config},this.log("info","统一播放器管理器已创建")}detectStreamType(streamingType){if(!streamingType)return PlayerType.HLS;switch(streamingType.toUpperCase().replace("-","_")){case"AWS_IVS":case"AWSIVS":case"IVS":return PlayerType.AWS_IVS;case"CLOUDFLARE_STREAM":case"CLOUDFLARESTREAM":case"CLOUDFLARE":case"CF":return PlayerType.CLOUDFLARE_STREAM;case"MUX":case"HLS":default:return PlayerType.HLS;case"WEBRTC":return PlayerType.WEBRTC}}getStreamTypeFromMeta(){const metaTag=document.querySelector('meta[name="match-streaming-type"]'),streamingType=metaTag?.content||"HLS";return this.detectStreamType(streamingType)}async initialize(matchId,streamingType,playbackUrl=null){this.log("info",`初始化播放器: matchId=${matchId}, type=${streamingType}`),await this.destroy();const playerType=this.detectStreamType(streamingType);this.currentPlayerType=playerType,this.status=PlayerStatus.LOADING,this.emit("loading");try{switch(playerType){case PlayerType.AWS_IVS:return await this._initializeIVSPlayer(matchId,playbackUrl);case PlayerType.CLOUDFLARE_STREAM:return await this._initializeCloudflarePlayer(matchId,playbackUrl);case PlayerType.WEBRTC:return await this._initializeWebRTCPlayer(matchId);default:return await this._initializeHLSPlayer(matchId)}}catch(error){return this.log("error","播放器初始化失败:",error.message),this.status=PlayerStatus.ERROR,this.emit("error",{message:error.message,type:"INIT_ERROR"}),!(playerType!==PlayerType.AWS_IVS||!this.config.ivsFallbackToHLS)&&(this.log("info","IVS 播放器失败,回退到 HLS"),await this._initializeHLSPlayer(matchId))}}async _initializeIVSPlayer(matchId,playbackUrl){if(this.log("info","初始化 IVS 播放器"),"undefined"==typeof IVSPlayerAdapter)throw new Error("IVS 播放器适配器未加载");if(playbackUrl||(playbackUrl=await this._fetchIVSPlaybackUrl(matchId)),!playbackUrl)throw new Error("无法获取 IVS 播放地址");return this.currentAdapter=new IVSPlayerAdapter(this.video,{autoplay:this.config.autoplay,muted:this.config.muted,lowLatency:!0,maxRetries:this.config.maxRetries,retryDelay:this.config.retryDelay,logLevel:this.config.logLevel}),this._setupIVSEventListeners(),await this.currentAdapter.initialize(playbackUrl),this.log("info","IVS 播放器初始化成功"),!0}_setupIVSEventListeners(){this.currentAdapter&&(this.currentAdapter.on("ready",()=>{this.log("info","IVS 播放器就绪"),this.emit("ready")}),this.currentAdapter.on("playing",()=>{this.status=PlayerStatus.PLAYING,this.retryCount=0,this.emit("playing")}),this.currentAdapter.on("buffering",()=>{this.status=PlayerStatus.BUFFERING,this.emit("buffering")}),this.currentAdapter.on("ended",()=>{this.status=PlayerStatus.ENDED,this.emit("ended")}),this.currentAdapter.on("error",error=>{this.log("error","IVS 播放器错误:",error),this._handleError(error)}),this.currentAdapter.on("qualityChanged",quality=>{this.emit("qualityChanged",quality)}))}async _fetchIVSPlaybackUrl(matchId){try{const metaPlayUrl=document.querySelector('meta[name="match-play-url"]')?.content;if(metaPlayUrl&&metaPlayUrl.includes(".m3u8"))return metaPlayUrl;const response=await fetch(`/api/stream/info/${matchId}`);if(!response.ok)throw new Error(`API 请求失败: ${response.status}`);const data=await response.json();return data.playUrl||data.playbackUrl||null}catch(error){return this.log("error","获取 IVS 播放地址失败:",error.message),null}}async _initializeWebRTCPlayer(matchId){if(this.log("info","初始化 WebRTC 播放器"),"function"==typeof loadWebRtcStream)return await loadWebRtcStream(matchId),this.currentPlayerType=PlayerType.WEBRTC,!0;throw new Error("WebRTC 播放器函数未定义")}async _initializeCloudflarePlayer(matchId,playbackUrl){if(this.log("info","初始化 Cloudflare Stream WHEP 播放器"),!playbackUrl){const metaPlayUrl=document.querySelector('meta[name="match-play-url"]')?.content;if(metaPlayUrl&&metaPlayUrl.includes("cloudflarestream.com"))playbackUrl=metaPlayUrl;else try{const response=await fetch(`/api/stream/info/${matchId}`);if(response.ok){const data=await response.json();playbackUrl=data.playUrl||data.whepUrl}}catch(e){this.log("error","获取 Cloudflare 播放地址失败:",e.message)}}if(!playbackUrl)throw new Error("无法获取 Cloudflare Stream 播放地址");if("function"==typeof initCloudflareWhepPlayer)return await initCloudflareWhepPlayer(this.video,playbackUrl),this.currentPlayerType=PlayerType.CLOUDFLARE_STREAM,this.status=PlayerStatus.PLAYING,this.emit
1("playing"),!0;throw new Error("Cloudflare WHEP 播放器函数未定义")}async _initializeHLSPlayer(matchId){this.log("info","初始化 HLS 播放器");const activeSource=document.querySelector(".source-btn.active"),sourceUrl=activeSource?.dataset?.sourceUrl,hlsUrl=sourceUrl||`/hls/${matchId}/index.m3u8`;if("function"==typeof loadHlsStream)return await loadHlsStream(hlsUrl,matchId),this.currentPlayerType=PlayerType.HLS,!0;throw new Error("HLS 播放器函数未定义")}async play(){this.currentAdapter&&"function"==typeof this.currentAdapter.play?await this.currentAdapter.play():this.video&&await this.video.play()}pause(){this.currentAdapter&&"function"==typeof this.currentAdapter.pause?this.currentAdapter.pause():this.video&&this.video.pause()}async destroy(){if(this.log("info","销毁播放器"),this.currentAdapter&&("function"==typeof this.currentAdapter.destroy&&this.currentAdapter.destroy(),this.currentAdapter=null),"undefined"!=typeof hlsInstance&&hlsInstance&&(hlsInstance.destroy(),hlsInstance=null),"undefined"!=typeof livekitRoom&&livekitRoom){try{await livekitRoom.disconnect()}catch(e){this.log("warn","断开 LiveKit 连接失败:",e.message)}livekitRoom=null}this.video&&(this.video.src="",this.video.srcObject=null,this.video.load()),this.currentPlayerType=null,this.status=PlayerStatus.IDLE,this.emit("destroyed")}
1async switchPlayer(newType,matchId){return this.log("info",`切换播放器: ${this.currentPlayerType} -> ${newType}`),await this.destroy(),await this.initialize(matchId,newType)}_handleError(error){this.status=PlayerStatus.ERROR;const errorInfo={type:error.type||"UNKNOWN",message:error.message||"未知错误",recoverable:!1!==error.recoverable,playerType:this.currentPlayerType};this.emit("error",errorInfo),this.currentPlayerType===PlayerType.AWS_IVS&&this.config.ivsFallbackToHLS&&!errorInfo.recoverable&&(this.log("info","IVS 播放器严重错误,回退到 HLS"),this._fallbackToHLS())}async _fallbackToHLS(){const matchId=this._getCurrentMatchId();matchId&&(this.emit("fallback",{from:PlayerType.AWS_IVS,to:PlayerType.HLS}),await this.switchPlayer(PlayerType.HLS,matchId))}_getCurrentMatchId(){const metaTag=document.querySelector('meta[name="match-id"]');if(metaTag?.content)return parseInt(metaTag.content,10);const match=window.location.pathname.match(/\/(\d+)$/);return match?parseInt(match[1],10):null}getPlayerType(){return this.currentPlayerType}getStatus(){return this.status}isPlaying(){return this.currentAdapter&&"function"==typeof this.currentAdapter.isPlaying?this.currentAdapter.isPlaying():this.video&&!this.video.paused&&!this.video.ended}getQualities(){return this.currentAdapter&&"function"==typeof this.currentAdapter.getQualities?this.currentAdapter.getQualities():[]}setQuality(quality){this.currentAdapter&&"function"==typeof this.currentAdapter.setQuality&&this.currentAdapter.setQuality(quality)}getLiveLatency(){return this.currentAdapter&&"function"==typeof this.currentAdapter.getLiveLatency?this.currentAdapter.getLiveLatency():0}on(event,callback){this.eventListeners.has(event)||this.eventListeners.set(event,[]),this.eventListeners.get(event).push(callback)}off(event,callback){if(!this.eventListeners.has(event))return;const listeners=this.eventListeners.get(event),index=listeners.indexOf(callback);index>-1&&listeners.splice(index,1)}emit(event,data){this.eventListeners.has(event)&&this.eventListeners.get(event).forEach(callback=>{try{callback(data)}catch(e){this.log("error",`事件处理器错误 [${event}]:`,e.message)}})}log(level,...args){const levels=["debug","info","warn","error"],configLevel=levels.indexOf(this.config.logLevel);if(levels.indexOf(level)<configLevel)return;const prefix=`[PlayerManager ${(new Date).toISOString()}]`;switch(level){case"debug":case"info":break;case"warn":console.warn(prefix,...args);break;case"error":console.error(prefix,...args)}}}let globalPlayerManager=null;function getPlayerManager(videoElement,containerElement,config={}){return globalPlayerManager||(globalPlayerManager=new UnifiedPlayerManager(videoElement,containerElement,config)),globalPlayerManager}function destroyPlayerManager(){globalPlayerManager&&(globalPlayerManager.destroy(),globalPlayerManager=null)}window.UnifiedPlayerManager=UnifiedPlayerManager,window.PlayerType=PlayerType,window.PlayerStatus=PlayerStatus,window.getPlayerManager=getPlayerManager,window.destroyPlayerManager=destroyPlayerManager;const STORAGE_KEYS={PLAYBACK_STATE:"persistent_playback_state",PIP_USER_DISABLED:"pip_user_disabled",USER_GESTURE_RECORDED:"user_gesture_recorded"};class PlaybackState{constructor(playerId="default"){this.playerId=playerId,this.wasPlaying=!1,this.streamType=null,this.matchId=null,this.lastPosition=0,this.timestamp=0}_getStorageKey(){return`${STORAGE_KEYS.PLAYBACK_STATE}_${this.playerId}`}save(state){if(!state||"object"!=typeof state)return void console.warn("[PlaybackState] Invalid state object");this.wasPlaying=!!state.wasPlaying,this.streamType=state.streamType||null,this.matchId=state.matchId||null,this.lastPosition=state.lastPosition||0,this.timestamp=Date.now();const stateToStore={wasPlaying:this.wasPlaying,streamType:this.streamType,matchId:this.matchId,playerId:this.playerId,lastPosition:this.lastPosition,timestamp:this.timestamp};try{sessionStorage.setItem(this._getStorageKey(),JSON.stringify(stateToStore))}catch(e){console.warn("[PlaybackState] Failed to save state:",e)}}load(){try{const stored=sessionStorage.getItem(this._getStorageKey());if(!stored)return null;const state=JSON.parse(stored),MAX_AGE=18e5;
1return state.timestamp&&Date.now()-state.timestamp>MAX_AGE?(this.clear(),null):(this.wasPlaying=state.wasPlaying,this.streamType=state.streamType,this.matchId=state.matchId,this.lastPosition=state.lastPosition||0,this.timestamp=state.timestamp,state)}catch(e){return console.warn("[PlaybackState] Failed to load state:",e),null}}clear(){this.wasPlaying=!1,this.streamType=null,this.matchId=null,this.lastPosition=0,this.timestamp=0;try{sessionStorage.removeItem(this._getStorageKey())}catch(e){console.warn("[PlaybackState] Failed to clear state:",e)}}hasActiveState(){const state=this.load();return null!==state&&!0===state.wasPlaying}canRecover(){const state=this.load();return null!==state&&!0===state.wasPlaying&&null!==state.streamType&&null!==state.matchId}getSnapshot(){return{wasPlaying:this.wasPlaying,streamType:this.streamType,matchId:this.matchId,playerId:this.playerId,lastPosition:this.lastPosition,timestamp:this.timestamp}}}"undefined"!=typeof window&&(window.PlaybackState=PlaybackState,window.PLAYBACK_STORAGE_KEYS=STORAGE_KEYS),"undefined"!=typeof module&&module.exports&&(module.exports={PlaybackState:PlaybackState,STORAGE_KEYS:STORAGE_KEYS});class PiPManager{constructor(videoElement,options={}){this.video=videoElement,this.options={enableDesktopAutoPiP:!0,enableMobileAutoPiP:!0,scrollThreshold:.2,...options},this.isPiPActive=!1,this.isPiPUserDisabled=!1,this.hasUserGesture=!1,this.isManualPiP=!1,this.intersectionObserver=null,this.isInitialized=!1,this.isMobile=this._detectMobile(),this.isIOS=this._detectIOS(),this._container=null,this._placeholder=null,this._closeBtn=null,this._observedTarget=null,this._scrollCheckQueued=!1,this._onIntersection=this._onIntersection.bind(this),this._onCloseClick=this._onCloseClick.bind(this),this._onVisibilityChange=this._onVisibilityChange.bind(this),this._onDocGesture=this._onDocGesture.bind(this),this._onScrollOrResize=this._onScrollOrResize.bind(this)}_detectMobile(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||window.innerWidth<=768}_detectIOS(){return/iPhone|iPad|iPod/i.test(navigator.userAgent)||"MacIntel"===navigator.platform&&navigator.maxTouchPoints>1}isPiPSupported(){return!!this._getContainer()}_getContainer(){return this._container&&document.contains(this._container)?this._container:this.video?(this._container=this.video.closest("#focusPlayerContainer, #livePlayerContainer, #beautyWatchPlayerContainer, .focus-player-container, .live-player-container, .beauty-watch-player, .manual-football-watch-player")||this.video.closest(".video-container")||this.video.parentElement,this._container):null}_getScrollAnchor(){if(this.isPiPActive&&this._placeholder&&document.contains(this._placeholder))return this._placeholder;const container=this._getContainer();if(!container)return null;const focusWrapper=container.closest(".focus-player-wrapper");if(focusWrapper)return focusWrapper;const detailSection=container.closest("#livePlayerSection, .live-player-section");if(detailSection)return detailSection;return container.closest(".live-player-wrapper")||container}_isFullscreenActive(){const container=this._getContainer();if(!container)return!1;if(container.closest(".fullscreen, .live-player-section.fullscreen, .focus-live-section.fullscreen"))return!0;const fs=document.fullscreenElement||document.webkitFullscreenElement;return!(!fs||fs!==container&&!fs.contains(container)&&!container.contains(fs))}_isVideoPlaying(){return!(!this.video||this.video.paused||this.video.ended)}_getAnchorVisibleRatio(anchor){if(!anchor)return 0;const rect=anchor.getBoundingClientRect(),vh=window.innerHeight||document.documentElement.clientHeight||0;if(vh<=0||rect.height<=0)return 0;const visibleHeight=Math.min(rect.bottom,vh)-Math.max(rect.top,0);return visibleHeight<=0?0:Math.min(1,visibleHeight/rect.height)}_isAnchorVisible(anchor){return this._getAnchorVisibleRatio(anchor)>this.options.scrollThreshold}initialize(){!this.isInitialized&&this.video&&(this._getContainer(),this._loadUserPreference(),this._setupGestureTracking(),(this.options.enableDesktopAutoPiP||this.options.enableMobileAutoPiP)&&(this._setupIntersectionObserver(),this._setupScrollFallback()),this.isMobile&&this.options.enableMobileAutoPiP&&document.addEventListener("visibilitychange",this._onVisibilityChange),this.isInitialized=!0,requestAnimationFrame(()=>this._evaluateScrollPiP()))}_setupGestureTracking(){["pointerdown","touchstart","keydown","wheel"].forEach(evt=>{document.addEventListener(evt,this._onDocGesture,{passive:!0,capture:!0})})}_onDocGesture(){this.recordUserGesture()}_setupScrollFallback(){window.addEventListener("scroll",this._onScrollOrResize,{passive:!0,capture:!0}),window.addEventListener("resize",this._onScrollOrResize,{passive:!0})}_onScrollOrResize(){this._scrollCheckQueued||(this._scrollCheckQueued=!0,requestAnimationFrame(()=>{this._scrollCheckQueued=!1,this._evaluateScrollPiP()}))}_evaluateScrollPiP(){if(this._isFullscreenActive())return;const anchor=this._getScrollAnchor();if(!anchor)return;const visible=this._isAnchorVisible(anchor);visible||this.isPiPActive?visible&&this.isPiPActive&&!this.isManualPiP?(this.exitPiP().catch(()=>{}),this._clearUserDisabled()):visible&&!this.isPiPActive&&this.isPiPUserDisabled?this._clearUserDisabled():!visible&&this.isPiPActive&&this.isManualPiP&&(this.isManualPiP=!1):(this._isVideoPlaying()&&this.recordUserGesture(),this._tryAutoPiP())}_setupIntersectionObserver(){"IntersectionObserver"in window?(this.intersectionObserver&&this.intersectionObserver.disconnect(),this.intersectionObserver=new IntersectionObserver(this._onIntersection,{threshold:[0,.1,.15,.2,.25,.5,1],rootMargin:"0px 0px -10% 0p
1x"}),this._observeAnchor()):console.warn("[PiPManager] IntersectionObserver not supported")}_observeAnchor(){if(!this.intersectionObserver)return;if(this._observedTarget){try{this.intersectionObserver.unobserve(this._observedTarget)}catch(_){}this._observedTarget=null}const target=this._getScrollAnchor();target&&(this._observedTarget=target,this.intersectionObserver.observe(target))}_onIntersection(entries){entries[0]&&this._evaluateScrollPiP()}_onVisibilityChange(){this.isMobile}async _tryAutoPiP(){this.isPiPSupported()&&(this.isPiPUserDisabled||this.isPiPActive||this._isFullscreenActive()||this._isVideoPlaying()&&(this.hasUserGesture||this.recordUserGesture(),await this.requestPiP({manual:!1})))}async requestPiP(options={}){if(this.isPiPActive)return options.manual&&(this.isManualPiP=!0),!0;const container=this._getContainer();if(!container||!this.video)return!1;if(this._isFullscreenActive())return!1;const manual=!!options.manual;manual&&(this.isManualPiP=!0,this.isPiPUserDisabled=!1,this.hasUserGesture=!0,this._saveUserPreference());try{const rect=container.getBoundingClientRect(),placeholder=document.createElement("div");return placeholder.className="page-pip-placeholder",placeholder.setAttribute("aria-hidden","true"),placeholder.style.width="100%",placeholder.style.height=Math.max(rect.height,1)+"px",placeholder.style.minHeight=Math.max(rect.height,1)+"px",!!container.parentNode&&(container.parentNode.insertBefore(placeholder,container),this._placeholder=placeholder,document.body.appendChild(container),container.classList.add("is-page-pip"),document.body.classList.add("has-page-pip"),this._ensureCloseButton(container),this.isPiPActive=!0,this._syncPipButton(!0),this._observeAnchor(),this.options.onPiPEnter&&this.options.onPiPEnter(),!0)}catch(error){return manual&&(this.isManualPiP=!1),this._cleanupDom(),!1}}async exitPiP(){if(!this.isPiPActive)return!0;try{return this._cleanupDom(),this.isPiPActive=!1,this.isManualPiP=!1,this._syncPipButton(!1),this._observeAnchor(),this.options.onPiPExit&&this.options.onPiPExit(),!0}catch(error){return!1}}_cleanupDom(){const container=this._getContainer();if(container&&container.classList.remove("is-page-pip"),document.body.classList.remove("has-page-pip"),this._closeBtn&&(this._closeBtn.removeEventListener("click",this._onCloseClick),this._closeBtn.remove(),this._closeBtn=null),this._placeholder){if(this.intersectionObserver&&this._observedTarget===this._placeholder){try{this.intersectionObserver.unobserve(this._placeholder)}catch(_){}this._observedTarget=null}container&&this._placeholder.parentNode&&this._placeholder.parentNode.insertBefore(container,this._placeholder),this._placeholder.parentNode&&this._placeholder.parentNode.removeChild(this._placeholder),this._placeholder=null}else if(container&&container.parentNode===document.body){const fallbackParent=document.querySelector(".live-player-wrapper, .focus-player-wrapper");fallbackParent&&fallbackParent.appendChild(container)}}_ensureCloseButton(container){if(this._closeBtn&&container.contains(this._closeBtn))return;const btn=document.createElement("button");btn.type="button",btn.className="page-pip-close-btn",btn.setAttribute("aria-label","Close"),btn.innerHTML='<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>',btn.addEventListener("click",this._onCloseClick),container.appendChild(btn),this._closeBtn=btn}_onCloseClick(e){e.preventDefault(),e.stopPropagation(),this._onUserClosePiP(),this.exitPiP().catch(()=>{})}_syncPipButton(active){const container=this._getContainer();if(!container)return;const pipBtn=container.querySelector(".live-pip-btn");pipBtn&&(pipBtn.classList.toggle("is-active",!!active),pipBtn.setAttribute("aria-pressed",active?"true":"false"))}async togglePiP(){if(this.isPiPActive){this.isManualPiP=!1;const anchor=this._getScrollAnchor();return anchor&&!this._isAnchorVisible(anchor)&&this._onUserClosePiP(),this.exitPiP()}return this.requestPiP({manual:!0})}_onUserClosePiP(){this.isPiPUserDisabled=!0,this.isManualPiP=!1,this._saveUserPreference()}recordUserGesture(){if(!this.hasUserGesture){this.hasUserGesture=!0;try{sessionStorage.setItem("pip_user_gesture_recorded","true")}catch(e){}}}_loadUserPreference(){try{"true"===sessionStorage.getItem("pip_user_gesture_recorded")&&(this.hasUserGesture=!0),"true"===sessionStorage.getItem("pip_user_disabled")&&(this.isPiPUserDisabled=!0)}catch(e){}}_saveUserPreference(){try{this.isPiPUserDisabled?sessionStorage.setItem("pip_user_disabled","true"):sessionStorage.removeItem("pip_user_disabled")}catch(e){}}_clearUserDisabled(){this.isPiPUserDisabled&&(this.isPiPUserDisabled=!1,this._saveUserPreference())}resetUserDisabled(){this._clearUserDisabled()}handleMobileAppSwitch(isVisible){this.isMobile}destroy(){this.isInitialized&&(this.intersectionObserver&&(this.intersectionObserver.disconnect(),this.intersectionObserver=null),this._observedTarget=null,document.removeEventListener("visibilitychange",this._onVisibilityChange),["pointerdown","touchstart","keydown","wheel"].forEach(evt=>{document.removeEventListener(evt,this._onDocGesture,{capture:!0})}),window.removeEventListener("scroll",this._onScrollOrResize,{capture:!0}),window.removeEventListener("resize",this._onScrollOrResize),this.isPiPActive?this.exitPiP().catch(()=>{}):this._cleanupDom(),this.isInitialized=!1)}}"undefined"!=typeof window&&(window.PiPManager=PiPManager),"undefined"!=typeof module&&module.exports&&(module.exports={PiPManager:PiPManager});class PersistentPlaybackManager{constructor(videoElement,options={}){this.video=videoElement,this.options={enableAutoPiP:!0,enableAutoResume:!0,enableMobileAutoPiP:!0,pauseOnHideMobile:!0,mobileHidePauseDelay:2500,resumeDelay:100,reconnectAttempts:3,reconnectDelay:1e3,playerId:"default",onResume:null,onReconnect:null,onError:null,onShowLoading:null,onHideLoading:null,getStreamInfo:null,reconnectStream:null,resumePlayer:null,pausePlayer:null,isSourceActive:null,showLoadingOnResume:!1,skipVisibilityHandling:!1,...options},this.playbackState=new PlaybackState(this.options.playerId),this.pipManager=null,this.isInitialized=!1,this.isResuming=!1,this.resumeAttempts=0,this.errorDeduplicator=new ErrorDeduplicator,this.hiddenAt=null,this._resumeTimer=null,this._mobileHidePauseTimer=null,this._pausedForMobileHide=!1,this.wasPlayingBeforeHidden=!1,this._onVisibilityChange=this._onVisibilityChange.bind(this),this._onVideoPlay=this._onVideoPlay.bind(this),this._onVideoPlaying=this._onVideoPlaying.bind(this),this._onVideoPause=this._onVideoPause.bind(this),this._onVideoError=this._onVideoError.bind(this),this._onUserInteraction=this._onUserInteraction.bind(this)}initialize(){if(!this.isInitialized&&this.video){if(this.options.playerId,this.options.enableAutoPiP){const existing="focusLivePlayer"===this.video?.id&&window.focusPiPManager||"livePlayer"===this.video?.id&&window.detailPiPManager||null;existing&&existing.video===this.video?(this.pipManager=existing,this.pipManager.options={...this.pipManager.options,enableDesktopAutoPiP:this.options.enableAutoPiP,enableMobileAutoPiP:this.options.enableMobileAutoPiP,onPiPEnter:()=>console.log("[PersistentPlayback] 进入 PiP"),onPiPExit:()=>console.log("[PersistentPlayback] 退出 PiP")},this.pipManager.isInitialized||this.pipManager.initialize()):(this.pipManager=new PiPManager(this.video,{enableDesktopAutoPiP:this.options.enableAutoPiP,enableMobileAutoPiP:this.options.enableMobileAutoPiP,onPiPEnter:()=>console.log("[PersistentPlayback] 进入 PiP"),onPiPExit:()=>console.log("[PersistentPlayback] 退出 PiP")}
1),this.pipManager.initialize())}this.options.skipVisibilityHandling||document.addEventListener("visibilitychange",this._onVisibilityChange),this.video.addEventListener("play",this._onVideoPlay),this.video.addEventListener("playing",this._onVideoPlaying),this.video.addEventListener("pause",this._onVideoPause),this.video.addEventListener("error",this._onVideoError),this._setupUserGestureTracking(),this.playbackState.load(),this.isInitialized=!0}}_setupUserGestureTracking(){const container=this.video.closest("#livePlayerSection, #focusLiveSection, .live-player-section, .focus-live-section, .video-container")||this.video.parentElement||document;["pointerdown","click","touchstart","keydown","wheel"].forEach(event=>{container.addEventListener(event,this._onUserInteraction,{passive:!0,capture:!0})}),document.addEventListener("pointerdown",this._onUserInteraction,{passive:!0,capture:!0}),document.addEventListener("wheel",this._onUserInteraction,{passive:!0,capture:!0})}_onUserInteraction(){this.pipManager&&this.pipManager.recordUserGesture()}_onVisibilityChange(){const isVisible=!document.hidden;this.handleVisibilityChange(isVisible)}_shouldPauseOnHide(){if(!this.options.pauseOnHideMobile)return!1;try{if(void 0!==window.DeviceDetector){if(window.DeviceDetector.isMobile&&window.DeviceDetector.isMobile())return!0;if(window.DeviceDetector.isIOS&&window.DeviceDetector.isIOS())return!0}}catch(e){}const ua=navigator.userAgent||"";return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua)||"MacIntel"===navigator.platform&&navigator.maxTouchPoints>1}handleVisibilityChange(isVisible){if(isVisible){this._clearMobileHidePauseTimer(),this.pipManager&&this.pipManager.handleMobileAppSwitch(!0);const hiddenDuration=this.hiddenAt?Date.now()-this.hiddenAt:0;this.hiddenAt=null;const delay=Math.max(this.options.resumeDelay,this._pausedForMobileHide?200:hiddenDuration<5e3?500:300);this._resumeTimer&&clearTimeout(this._resumeTimer),this._resumeTimer=setTimeout(()=>{this._resumeTimer=null,this._checkAndResumePlayback()},delay)}else this.hiddenAt=Date.now(),this._saveCurrentState(),!this.video||this.video.paused||this.video.ended||(this.wasPlayingBeforeHidden=!0),this._shouldPauseOnHide()&&this.wasPlayingBeforeHidden&&this._scheduleMobileHidePause()}_clearMobileHidePauseTimer(){this._mobileHidePauseTimer&&(clearTimeout(this._mobileHidePauseTimer),this._mobileHidePauseTimer=null)}_scheduleMobileHidePause(){this._clearMobileHidePauseTimer();const delay=Math.max(0,this.options.mobileHidePauseDelay||2500);this._mobileHidePauseTimer=setTimeout(()=>{this._mobileHidePauseTimer=null,document.hidden&&this._pauseForMobileHide()},delay)}async _pauseForMobileHide(){if(this.video&&document.hidden&&!this.video.paused&&!this.video.ended){try{if(document.pictureInPictureElement===this.video)return;if(this.pipManager&&this.pipManager.isInPiP&&this.pipManager.isInPiP())return}catch(e){}this._pausedForMobileHide=!0,this.wasPlayingBeforeHidden=!0;try{await this._invokePausePlayer()}catch(e){e&&e.message}}}_saveCurrentState(){if(!this.video)return;const isPlaying=!this.video.paused&&!this.video.ended;let streamInfo={streamType:null,matchId:null};if(this.options.getStreamInfo)try{streamInfo=this.options.getStreamInfo()||streamInfo}catch(e){}this.playbackState.save({wasPlaying:isPlaying,streamType:streamInfo.streamType,matchId:streamInfo.matchId,lastPosition:this.video.currentTime||0})}async _checkAndResumePlayback(){if(!this.video||!this.options.enableAutoResume)return;const savedState=this.playbackState.load();(this.wasPlayingBeforeHidden||savedState&&savedState.wasPlaying)&&(this.video.paused||this.video.ended?this.video.readyState>=2&&this.video.videoWidth>0&&(await this._delay(400),!this.video.paused&&!this.video.ended)?this.wasPlayingBeforeHidden=!1:(this._isVideoSourceLost()?await this.attemptReconnect():await this.attemptResume(),this.wasPlayingBeforeHidden=!1,this._pausedForMobileHide=!1):this.wasPlayingBeforeHidden=!1)}_isVideoSourceLost(){if(!this.video)return!0;if(this.options.isSourceActive)try{if(this.options.isSourceActive())return!1}catch(e){}return null===this.video.srcObject&&!this.video.src||!this.video.srcObject&&!this.video.src||0===this.video.readyState}async attemptResume(){if(this.isResuming)return!1;this.isResuming=!0,this.resumeAttempts=0,this.options.showLoadingOnResume&&this._showLoading();try{const success=await this._tryResume();return success&&this.options.onResume&&this.options.onResume(),success}finally{this.isResuming=!1,this.options.showLoadingOnResume&&this._hideLoading()}}async _invokePausePlayer(){if(this.options.pausePlayer)return await this.options.pausePlayer(this.video);this.video&&"function"==typeof this.video.pause&&this.video.pause()}async _invokeResume(){if(this.options.resumePlayer)return await this.options.resumePlayer(this.video);try{return await this.video.play(),!0}catch(error){if("NotAllowedError"===error.name)return this.video.muted=!0,await this.video.play(),!0;throw error}}async _tryResume(){const maxAttempts=Math.min(this.options.reconnectAttempts,2);for(;this.resumeAttempts<maxAttempts;){this.resumeAttempts++,this.resumeAttempts;try{await this._invokeResume();for(let i=0;i<10;i++){if(!this.video.paused&&!this.video.ended)return!0;await this._delay(200)}return!this.video.paused}catch(error){const msg=error.message||"";if(this.resumeAttempts,msg.includes("interrupted")&&this.resumeAttempts<maxAttempts){await this._delay(600);continue}this.resumeAttempts<maxAttempts&&await this._delay(500)}}return this._handleResumeFailure(),!1}async attemptReconnect(){if(!this.options.reconnectStream)return!1;const savedState=this.playbackState.load();if(!savedState||!savedState.streamType||!savedState.matchId)return!1;this._showLoading();try{const success=await this.options.reconnectStream(savedState.streamType,savedState.matchId);return success?this.options.onReconnect&&this.options.onReconnect():this._handleReconnectFailure(),success}catch(error){return this._handleReconnectFailure(),!1}finally{this._hideLoading()}}_handleResumeFailure(){this.errorDeduplicator.shouldShowError("resume","playback_resume_failed")&&this.options.onError&&this.options.onError(new Error("播放恢复失败,请点击重试"))}_handleReconnectFailure(){this.errorDeduplicator.shouldShowError("reconnect","stream_reconnect_failed")&&this.options.onError&&this.options.onError(new Error("连接已断开,请点击重试"))}_showLoading(){this.options.onShowLoading&&this.options.onShowLoading()}_hideLoading(){this.options.onHideLoading&&this.options.onHideLoading()}_onVideoPlay(){this.pipManager&&this.pipManager.recordUserGesture()}_onVideoPlaying(){this.wasPlayingBeforeHidden=!1,this.playbackState.save({wasPlaying:!0,streamType:this.playbackState.streamType,matchI
1d:this.playbackState.matchId})}_onVideoPause(){document.hidden,document.hidden||this.isResuming||(this.wasPlayingBeforeHidden=!1,this.playbackState.save({wasPlaying:!1,streamType:this.playbackState.streamType,matchId:this.playbackState.matchId}))}_onVideoError(event){}_delay(ms){return new Promise(resolve=>setTimeout(resolve,ms))}notifyPageHidden(){this.handleVisibilityChange(!1)}async waitForSelfRecovery(getPlayerState,maxMs=2200){if(!this.video)return!1;const isPlaying=()=>!this.video.paused&&!this.video.ended&&this.video.readyState>=2||"function"==typeof getPlayerState&&"playing"===getPlayerState();return!!isPlaying()||new Promise(resolve=>{let settled=!1;const finish=value=>{settled||(settled=!0,this.video.removeEventListener("playing",onPlaying),clearInterval(poll),resolve(value))},onPlaying=()=>finish(!0);this.video.addEventListener("playing",onPlaying);const deadline=Date.now()+maxMs,poll=setInterval(()=>{isPlaying()?finish(!0):Date.now()>=deadline&&finish(!1)},80)})}async resumeAfterShortHide(getPlayerState){this.wasPlayingBeforeHidden=!0;const saved=this.playbackState.load();return saved&&this.playbackState.save({...saved,wasPlaying:!0}),this._isVideoSourceLost()?this.attemptReconnect():(await this._delay(400),await this.waitForSelfRecovery(getPlayerState,2200)?(this.wasPlayingBeforeHidden=!1,!0):this.attemptResume())}async manualResume(){return this.resumeAttempts=0,this._isVideoSourceLost()?await this.attemptReconnect():await this.attemptResume()}clearState(){this.wasPlayingBeforeHidden=!1,this.playbackState.clear()}destroy(){this.isInitialized&&(this._resumeTimer&&(clearTimeout(this._resumeTimer),this._resumeTimer=null),this._clearMobileHidePauseTimer(),this.options.skipVisibilityHandling||document.removeEventListener("visibilitychange",this._onVisibilityChange),this.video&&(this.video.removeEventListener("play",this._onVideoPlay),this.video.removeEventListener("playing",this._onVideoPlaying),this.video.removeEventListener("pause",this._onVideoPause),this.video.removeEventListener("error",this._onVideoError)),this.pipManager&&(this.pipManager.destroy(),this.pipManager=null),this.isInitialized=!1)}}class ErrorDeduplicator{constructor(cooldownMs=5e3){this.lastErrors=new Map,this.cooldownMs=cooldownMs}shouldShowError(errorType,errorMessage){const key=`${errorType}:${errorMessage}`,lastTime=this.lastErrors.get(key),now=Date.now();return!(lastTime&&now-lastTime<this.cooldownMs||(this.lastErrors.set(key,now),0))}clear(){this.lastErrors.clear()}}"undefined"!=typeof window&&(window.PersistentPlaybackManager=PersistentPlaybackManager,window.ErrorDeduplicator=ErrorDeduplicator),"undefined"!=typeof module&&module.exports&&(module.exports={PersistentPlaybackManager:PersistentPlaybackManager,ErrorDeduplicator:ErrorDeduplicator});class PageVisibilityManager{constructor(){this.isVisible=!document.hidden,this.lastVisibilityChange=Date.now(),this.lastResync=0,this.resyncCooldown=5e3,this.init()}init(){document.addEventListener("visibilitychange",()=>{this.handleVisibilityChange()}),window.addEventListener("focus",()=>{this.handlePageFocus()}),window.addEventListener("blur",()=>{this.handlePageBlur()})}handleVisibilityChange(){const now=Date.now(),wasVisible=this.isVisible;if(this.isVisible=!document.hidden,!wasVisible&&this.isVisible){const hiddenDuration=now-this.lastVisibilityChange;if(Math.round(hiddenDuration/1e3),now-this.lastResync<this.resyncCooldown)return void(this.lastVisibilityChange=now);void 0!==window.PersistentPlaybackManager||this.recoverPlayersImmediately(),hiddenDuration>1e4&&(this.lastResync=now,this.smartResync(hiddenDuration))}this.lastVisibilityChange=now}async smartResync(hiddenDuration){try{window.MatchLiveHub&&(window.MatchLiveHub.isConnected()||"function"==typeof window.MatchLiveHub.reconnect&&window.MatchLiveHub.reconnect()),window.MatchStore&&window.MatchStore.isInitialized()?await window.MatchStore.triggerResync("page_visible"):window.MatchStore&&await window.MatchStore.init("live"),await this.refreshNavigationData(),hiddenDuration>3e5&&"function"==typeof window.initFlipCountdowns&&window.initFlipCountdowns()}catch(error){console.warn("[PageVisibility] 增量同步失败:",error)}}recoverPlayersImmediately(){if(void 0!==window.PersistentPlaybackManager)return;const focusPlayer=document.getElementById("focusLivePlayer");if(focusPlayer&&(focusPlayer.paused||0===focusPlayer.currentTime||focusPlayer.readyState<2)&&("function"==typeof window.showFocusLoadingMessage&&window.showFocusLoadingMessage(),"function"==typeof window.hideFocusPlayOverlay&&window.hideFocusPlayOverlay(),"function"==typeof window.hideFocusPlayerError&&window.hideFocusPlayerError(),"function"==typeof window.setUserInitiatedPlay&&window.setUserInitiatedPlay(),"function"==typeof window.startFocusPlayback&&window.focusCurrentMatchId)){const container=document.getElementById("focusPlayerContainer"),identifier=container?.dataset?.identifier,streamingType=container?.dataset?.streamingType||"WebRTC";window.startFocusPlayback(window.focusCurrentMatchId,streamingType,identifier)}const detailPlayer=document.getElementById("livePlayer");if(detailPlayer&&(detailPlayer.paused||0===detailPlayer.currentTime||detailPlayer.readyState<2)&&("function"==typeof window.showLoadingMessage&&window.showLoadingMessage(),"function"==typeof window.hideDetailPlayOverlay&&window.hideDetailPlayOverlay(),"function"==typeof window.hideErrorOverlay&&window.hideErrorOverlay(),"function"==typeof window.setDetailUserInitiatedPlay&&window.setDetailUserInitiatedPlay(),"function"==typeof window.startDetailPlayback&&window.lastMatchId)){const streamingType=window.getStreamingType?window.getStreamingType():"WebRTC";window.startDetailPlayback(window.lastMatchId,streamingType)}}isVideoActuallyPlaying(){const focusPlayer=document.getElementById("focusLivePlayer");if(focusPlayer&&!focusPlayer.paused&&focusPlayer.currentTime>0&&focusPlayer.readyState>=2)return!0;const detailPlayer=document.getElementById("livePlayer");return!!(detailPlayer&&!detailPlayer.paused&&detailPlayer.currentTime>0&&detailPlayer.readyState>=2)}isVideoPlaying(){return this.isVideoActuallyPlaying()}handlePageFocus(){this.isVisible||(this.isVisible=!0,this.handleVisibilityChange())}handlePageBlur(){this.lastVisibilityChange=Date.now()}async refreshNavigationData(){try{if(void 0!==window.MatchLiveHub&&window.MatchLiveHub.refreshLiveCountFromServer)await window.MatchLiveHub.refreshLiveCountFromServer();else{const response=await fetch("/api/match/live-count",{headers:{Accept:"application/json"}});if(response.ok){const data=await response.json(),liveCountElement=document.querySelector(".live-count");liveCountElement&&"number"==typeof data.count&&(liveCountElement.textContent=data.count)}}}catch(error){console.warn("[PageVisibility] 更新导航数据失败:",error)}}manualRefresh(){this.smartResync(6e4)}}window.PageVisibilityManager=new PageVisibilityManager,window.silentRefreshPage=function(){window.PageVisibilityManager&&window.PageVisibilityManager.manualRefresh()},window.isListPage=function(){const path=window.location.pathname.toLowerCase();return"/"===path||"/home"===path||"/home/index"===path||path.startsWith("/match")&&!path.includes("/details")},function(){"use strict";if(window._unifiedPlayerMoreDropdownInitialized)return;const boundElements=new WeakSet;let debounceTimer,activeMenu=null,activeBtn=null;function closeAllMenus(){document.querySelectorAll(".player-more-menu.show").forEach(m=>m.classList.remove("show")),document.querySelectorAll(".player-more-btn.active").forEach(b=>b.classList.remove("active")),document.querySelectorAll(".player-more-menu-active").forEach(el=>el.classList.remove("player-more-menu-active")),activeMenu=null,activeBtn=null}function toggleMenu(btn,menu){const isOpen=menu.classList.contains("show"),dropdown=btn.closest(".player-more-dropdown");closeAllMenus(),isOpen||(menu.classList.add("show"),btn.classList.add("active"),function setMenuActiveState(dropdown,isActive){const scope=dropdown?.closest(".focus-player-wrapper, .live-player
1-wrapper, .focus-live-section, .live-player-section");scope&&scope.classList.toggle("player-more-menu-active",isActive)}(dropdown,!0),activeMenu=menu,activeBtn=btn)}function initDropdown(dropdown){if(boundElements.has(dropdown))return;boundElements.add(dropdown);const btn=dropdown.querySelector(".player-more-btn"),menu=dropdown.querySelector(".player-more-menu");if(!btn||!menu)return;let touchHandled=!1;btn.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),touchHandled=!0,setTimeout(()=>{touchHandled=!1},300),toggleMenu(btn,menu)},{passive:!1}),btn.addEventListener("click",function(e){touchHandled||(e.preventDefault(),e.stopPropagation(),toggleMenu(btn,menu))}),menu.querySelectorAll(".player-more-item").forEach(item=>{let itemTouchHandled=!1;item.addEventListener("touchend",function(e){e.stopPropagation(),itemTouchHandled=!0,setTimeout(()=>{itemTouchHandled=!1},300),setTimeout(closeAllMenus,80)}),item.addEventListener("click",function(e){itemTouchHandled||(e.stopPropagation(),setTimeout(closeAllMenus,80))})})}function initAll(){document.querySelectorAll(".player-more-dropdown").forEach(initDropdown)}document.addEventListener("click",function(e){e.target.closest(".player-more-dropdown")||closeAllMenus()}),document.addEventListener("touchend",function(e){e.target.closest(".player-more-dropdown")||closeAllMenus()},{passive:!0}),document.addEventListener("keydown",function(e){"Escape"===e.key&&closeAllMenus()}),window.initUnifiedPlayerMoreDropdown=initAll,window.closeAllPlayerMoreMenus=closeAllMenus,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",initAll):initAll(),new MutationObserver(function(mutations){clearTimeout(debounceTimer),debounceTimer=setTimeout(function(){mutations.forEach(function(m){m.addedNodes.forEach(function(node){1===node.nodeType&&(node.classList?.contains("player-more-dropdown")&&initDropdown(node),node.querySelectorAll?.(".player-more-dropdown").forEach(initDropdown))})})},100)}).observe(document.body,{childList:!0,subtree:!0}),window._unifiedPlayerMoreDropdownInitialized=!0}();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.