diff --git a/RememberPlaybackSpeed.js b/RememberPlaybackSpeed.js index 094bdb9..252efaa 100644 --- a/RememberPlaybackSpeed.js +++ b/RememberPlaybackSpeed.js @@ -16,11 +16,13 @@ class RememberPlaybackSpeed { this.STORAGE_KEY = 'emby_playback_speed'; this.isRestoring = false; this.isTheater = isTheater; + this.normalSpeedDecisionTimer = null; this.init(); } init() { console.log('[倍速记忆] 初始化'); + this.bindSpeedControlMonitor(); this.waitForPlayer(); } @@ -42,7 +44,7 @@ class RememberPlaybackSpeed { if (this.isRestoring) return; const savedSpeed = this.getSavedSpeed(); - if (!savedSpeed || savedSpeed === 1) return; + if (!this.isValidSpeed(savedSpeed)) return; this.isRestoring = true; console.log(`[倍速记忆] 恢复倍速: ${savedSpeed}x`); @@ -62,18 +64,6 @@ class RememberPlaybackSpeed { if (success) { console.log(`[倍速记忆] ✓ 恢复成功: ${savedSpeed}x`); this.isRestoring = false; - - // 保护期:防止被重置为 1x - let count = 0; - const protect = setInterval(() => { - document.querySelectorAll('video').forEach(video => { - if (video.playbackRate === 1) { - video.playbackRate = savedSpeed; - console.log(`[倍速记忆] 防止重置为 1x`); - } - }); - if (++count >= 10) clearInterval(protect); - }, 500); } else { setTimeout(applySpeed, 300); } @@ -93,14 +83,24 @@ class RememberPlaybackSpeed { // 监听倍速变化(保存用户修改) video.addEventListener('ratechange', () => { const speed = video.playbackRate; - const isPlaying = !video.paused || video.currentTime > 0; - if (isPlaying && speed !== 1 && !this.isRestoring) { - this.saveSpeed(speed); - console.log(`[倍速记忆] 保存倍速: ${speed}x`); + if (!this.isValidSpeed(speed) || this.isRestoring) return; + + const savedSpeed = this.getSavedSpeed(); + if ( + this.isNormalSpeed(speed) && + this.isValidSpeed(savedSpeed) && + !this.isNormalSpeed(savedSpeed) + ) { + this.handleNormalSpeedChange(video, restoreSpeed); + return; } + + this.cancelNormalSpeedDecision(); + this.saveSpeed(speed); + console.log(`[倍速记忆] 保存倍速: ${speed}x`); }); - + // 关键时机恢复倍速 ['loadedmetadata', 'canplay', 'play'].forEach(event => { video.addEventListener(event, () => { @@ -134,6 +134,79 @@ class RememberPlaybackSpeed { console.log('[倍速记忆] 监控已启动'); } + bindSpeedControlMonitor() { + document.addEventListener('click', event => { + const selectedSpeed = this.parseSpeedFromEvent(event); + if (this.isValidSpeed(selectedSpeed)) { + this.cancelNormalSpeedDecision(); + this.saveSpeed(selectedSpeed); + console.log(`[倍速记忆] 检测到倍速菜单选择: ${selectedSpeed}x`); + } + }, true); + } + + handleNormalSpeedChange(video, restoreSpeed) { + this.cancelNormalSpeedDecision(); + + this.normalSpeedDecisionTimer = setTimeout(() => { + this.normalSpeedDecisionTimer = null; + + const savedSpeed = this.getSavedSpeed(); + if (!this.isValidSpeed(savedSpeed) || this.isNormalSpeed(savedSpeed)) return; + if (!this.isNormalSpeed(video.playbackRate)) return; + + console.log(`[倍速记忆] 检测到播放器自动重置为 1x,恢复 ${savedSpeed}x`); + restoreSpeed(); + }, 400); + } + + cancelNormalSpeedDecision() { + if (this.normalSpeedDecisionTimer) { + clearTimeout(this.normalSpeedDecisionTimer); + this.normalSpeedDecisionTimer = null; + } + } + + parseSpeedFromEvent(event) { + const path = typeof event.composedPath === 'function' ? event.composedPath() : [event.target]; + + for (const element of path) { + if (!element || element === document || element === window) continue; + + const candidates = [ + element.getAttribute && element.getAttribute('aria-label'), + element.getAttribute && element.getAttribute('title'), + element.getAttribute && element.getAttribute('data-value'), + element.getAttribute && element.getAttribute('value'), + element.textContent + ]; + + for (const candidate of candidates) { + const speed = this.parseSpeedLabel(candidate); + if (this.isValidSpeed(speed)) return speed; + } + } + + return null; + } + + parseSpeedLabel(text) { + if (!text) return null; + + const label = text.trim().replace(/\s+/g, ' '); + if (!label || label.length > 24) return null; + + if (/^(normal|default|标准|正常|原速)$/i.test(label)) return 1; + + const match = label.match(/^(\d+(?:\.\d+)?)\s*(?:x|倍)$/i) || + label.match(/^x\s*(\d+(?:\.\d+)?)$/i); + + if (!match) return null; + + const speed = parseFloat(match[1]); + return speed > 0 && speed <= 16 ? speed : null; + } + // localStorage 操作 saveSpeed(speed) { if (this.isTheater) { @@ -149,6 +222,14 @@ class RememberPlaybackSpeed { const speed = localStorage.getItem(this.STORAGE_KEY); return speed ? parseFloat(speed) : null; } + + isValidSpeed(speed) { + return Number.isFinite(speed) && speed > 0; + } + + isNormalSpeed(speed) { + return Math.abs(speed - 1) < 0.01; + } } // 页面加载后自动启动