// ==UserScript== // @name 辽宁省执业药师继续教育后台挂机脚本 v5.0 // @namespace http://tampermonkey.net/ // @version 5.0 // @description 自动播放、防暂停、防加速误报,解除复制和右键限制 // @author VX:hapens1986 // @match https://zyysjxjy.com/air2/html/index.html* // @match https://*.zyysjxjy.com/* // @grant unsafeWindow // @grant GM_log // @run-at document-start // ==/UserScript== (function() { 'use strict'; const log = GM_log || console.log.bind(console, '[视频优化]'); log('脚本v5.0已加载 - 针对videoplayer-video优化'); const config = { autoPlay: true, autoPlayNext: true, antiPause: true, smartAntiAcceleration: true, autoRetry: true, delayBeforeNext: 2000, maxPlaybackRate: 3, debug: true, enableCopy: true, enableRightClick: true, defaultVolume: 1.0 }; const state = { currentVideo: null, videoElements: new Set(), isWindowHidden: false, playbackHistory: [], lastVisibilityChange: 0, visibilityCooldown: 1500, originalPlay: null, originalPause: null, panelAdded: false, frameId: generateFrameId(), isVideoFrame: false, panelScale: 1.0, currentVolume: config.defaultVolume, isMuted: false }; function generateFrameId() { return 'frame_' + Math.random().toString(36).substr(2, 9); } function detectVideoFrame() { const videos = document.querySelectorAll('video, .videoplayer-video'); const hasVideos = videos.length > 0; const videoSelectors = [ '.video-player', '.video-player-container', '.videoplayer-container', '[class*="video"]', '[class*="player"]', '#video-player', '#player-container' ]; let hasVideoPlayer = false; for (const selector of videoSelectors) { if (document.querySelector(selector)) { hasVideoPlayer = true; break; } } state.isVideoFrame = hasVideos || hasVideoPlayer; state.panelScale = state.isVideoFrame ? 0.7 : 1.0; log(`框架检测: ${state.isVideoFrame ? '视频框架' : '非视频框架'},视频数量: ${videos.length},面板缩放: ${state.panelScale}`); return state.isVideoFrame; } function setupVolumeControl(video) { if (!video) return; video.volume = state.currentVolume; video.muted = state.isMuted; video.addEventListener('volumechange', function() { if (video !== state.currentVideo) return; state.currentVolume = video.volume; state.isMuted = video.muted; updateVolumeDisplay(); }); } function updateVolumeDisplay() { if (!state.isVideoFrame) return; const volumeSlider = document.getElementById(`volume-slider-${state.frameId}`); const volumeDisplay = document.getElementById(`volume-display-${state.frameId}`); const muteBtn = document.getElementById(`btn-mute-${state.frameId}`); if (!volumeSlider || !volumeDisplay || !muteBtn) return; const volumePercent = Math.round(state.currentVolume * 100); volumeDisplay.textContent = state.isMuted ? '🔇 静音' : `${volumePercent}%`; volumeSlider.value = volumePercent; muteBtn.textContent = state.isMuted ? '🔇' : '🔊'; muteBtn.style.background = state.isMuted ? '#ff9800' : '#2196f3'; } function setVolume(volume) { const newVolume = Math.max(0, Math.min(1, volume)); state.currentVolume = newVolume; state.isMuted = false; state.videoElements.forEach(video => { video.volume = newVolume; video.muted = false; }); updateVolumeDisplay(); log(`音量设置为: ${Math.round(newVolume * 100)}%`); } function toggleMute() { state.isMuted = !state.isMuted; state.videoElements.forEach(video => { video.muted = state.isMuted; }); updateVolumeDisplay(); log(state.isMuted ? '已静音' : '已取消静音'); showNotification(state.isMuted ? '已静音' : '音量恢复', state.isMuted ? '#ff9800' : '#2196f3'); } function enableCopySelection() { if (!config.enableCopy) return; log('启用解除复制限制功能'); try { document.oncontextmenu = null; document.oncopy = null; document.onselectstart = null; const style = document.createElement('style'); style.id = 'force-enable-selection'; style.textContent = ` * { user-select: text !important; -webkit-user-select: text !important; -moz-user-select: text !important; -ms-user-select: text !important; } ::selection { background: rgba(0, 120, 215, 0.3) !important; } `; if (document.head) { document.head.appendChild(style); } else { document.addEventListener('DOMContentLoaded', () => { if (document.head) document.head.appendChild(style); }); } document.addEventListener('selectstart', function(e) { e.stopPropagation(); }, true); document.addEventListener('copy', function(e) { e.stopPropagation(); }, true); document.addEventListener('contextmenu', function(e) { e.stopPropagation(); }, true); log('复制限制已解除'); } catch (e) { log(`解除复制限制时出错: ${e.message}`); } } function enableRightClick() { if (!config.enableRightClick) return; log('启用解除右键限制功能'); try { document.oncontextmenu = null; document.addEventListener('contextmenu', function(e) { return true; }, true); log('右键限制已解除'); } catch (e) { log(`解除右键限制时出错: ${e.message}`); } } function init() { log('初始化视频优化脚本v5.0 - 框架ID: ' + state.frameId); detectVideoFrame(); if (config.enableCopy) enableCopySelection(); if (config.enableRightClick) enableRightClick(); setupVisibilityMonitor(); setupGlobalEventListeners(); setupPlaybackMonitor(); setupVideoDetector(); if (config.debug) { setTimeout(() => { if (!document.getElementById('video-optimizer-panel-' + state.frameId)) { addEnhancedControlPanel(); } }, 1500); } exposeGlobalControls(); log('脚本初始化完成 - 视频框架: ' + state.isVideoFrame + ' 面板缩放: ' + state.panelScale); } function setupVisibilityMonitor() { if (!config.antiPause) return; document.addEventListener('visibilitychange', function(e) { const now = Date.now(); state.lastVisibilityChange = now; state.isWindowHidden = document.hidden; log(`页面可见性变化: ${document.hidden ? '隐藏' : '显示'}`); if (document.hidden) { handlePageHidden(); } else { handlePageVisible(); } setTimeout(() => { if (config.antiPause && document.hidden) { gentleResumePlayback(); } }, 300); }, true); log('页面可见性监控已设置'); } function handlePageHidden() { log('页面隐藏,保持视频播放状态'); state.videoElements.forEach(video => { video._protectedState = { wasPlaying: !video.paused, currentTime: video.currentTime, playbackRate: video.playbackRate }; }); } function handlePageVisible() { log('页面显示,检查视频状态'); state.videoElements.forEach(video => { if (video._protectedState && video._protectedState.wasPlaying && video.paused) { log(`恢复视频播放: ${getVideoInfo(video)}`); safePlayVideo(video); } }); } function gentleResumePlayback() { if (!state.currentVideo) return; const video = state.currentVideo; if (video.paused && !video.ended) { log('温和恢复视频播放'); const beforeTime = video.currentTime; setTimeout(() => { video.play().then(() => { const afterTime = video.currentTime; const timeJump = Math.abs(afterTime - beforeTime); log(`视频恢复成功: ${beforeTime.toFixed(1)}s -> ${afterTime.toFixed(1)}s`); if (timeJump > 5 && config.smartAntiAcceleration) { const safeTime = beforeTime + 1; video.currentTime = safeTime; log(`调整时间: ${afterTime.toFixed(1)}s -> ${safeTime.toFixed(1)}s`); } }).catch(err => { if (config.debug) log(`恢复播放失败: ${err.message}`); }); }, 500); } } function setupVideoDetector() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.addedNodes.length > 0) { mutation.addedNodes.forEach((node) => { if (node.nodeName === 'VIDEO') { handleVideoElement(node); checkAndMaybeAddPanel(); } if (node.querySelector) { const videos = node.querySelectorAll('video'); if (videos.length > 0) { videos.forEach(handleVideoElement); checkAndMaybeAddPanel(); } const playerVideos = node.querySelectorAll('.videoplayer-video'); if (playerVideos.length > 0) { playerVideos.forEach(handleVideoElement); checkAndMaybeAddPanel(); } } }); } }); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'src', 'id'] }); setTimeout(() => { const videos = document.querySelectorAll('video'); const playerVideos = document.querySelectorAll('.videoplayer-video'); if (videos.length > 0 || playerVideos.length > 0) { videos.forEach(video => handleVideoElement(video)); playerVideos.forEach(video => handleVideoElement(video)); state.isVideoFrame = true; state.panelScale = 0.4; log('检测到视频,更新为视频框架,面板缩放为0.4'); updatePanelFrameInfo(); updatePanelScale(); } }, 1000); log('视频检测器已启动'); } function checkAndMaybeAddPanel() { if (!state.panelAdded && config.debug) { const videos = document.querySelectorAll('video, .videoplayer-video'); if (videos.length > 0) { setTimeout(() => { if (!document.getElementById('video-optimizer-panel-' + state.frameId)) { addEnhancedControlPanel(); } }, 1000); } } } function handleVideoElement(video) { if (video._optimized) return; video._optimized = true; state.videoElements.add(video); log(`优化视频元素: ${getVideoInfo(video)}`); optimizeVideoElement(video); setupVolumeControl(video); if (config.autoPlay) setupAutoPlay(video); if (config.autoPlayNext) setupAutoPlayNext(video); if (config.smartAntiAcceleration) setupAntiAccelerationProtection(video); if (!state.currentVideo || video === document.querySelector('.videoplayer-video')) { state.currentVideo = video; log(`设为当前视频: ${getVideoInfo(video)}`); } } function optimizeVideoElement(video) { if (!state.originalPause) { state.originalPause = video.pause; state.originalPlay = video.play; } video.pause = function() { const stack = new Error().stack || ''; if (stack.includes('visibilitychange') || stack.includes('onViewHide') || stack.includes('EVENT_HIDE') || (stack.includes('pause') && stack.includes('blur'))) { log(`拦截页面失去焦点触发的暂停: ${getVideoInfo(video)}`); video._protectedState = { wasPlaying: true, currentTime: video.currentTime, timestamp: Date.now() }; return; } log(`执行正常暂停: ${getVideoInfo(video)}`); video._protectedState = { wasPlaying: false }; return state.originalPause.call(video); }; video.play = function() { log(`播放视频: ${getVideoInfo(video)}`); state.playbackHistory.push({ video: getVideoInfo(video), time: Date.now(), action: 'play' }); if (state.playbackHistory.length > 50) state.playbackHistory.shift(); return state.originalPlay.call(video); }; setupVideoEventListeners(video); } function setupVideoEventListeners(video) { video.addEventListener('play', () => { state.currentVideo = video; log(`视频开始播放: ${getVideoInfo(video)}`); if (video.playbackRate > config.maxPlaybackRate) { video.playbackRate = 1.0; log(`调整播放速度: ${video.playbackRate} -> 1.0`); } updatePanelInfo(); }); video.addEventListener('pause', (e) => { log(`视频暂停: ${getVideoInfo(video)}`); if (video._protectedState && video._protectedState.wasPlaying) { const pauseTime = Date.now(); const timeSinceProtected = pauseTime - (video._protectedState.timestamp || 0); if (timeSinceProtected < 2000) { setTimeout(() => { if (video.paused && config.antiPause) { log('自动恢复受保护视频'); safePlayVideo(video); } }, 300); } } updatePanelInfo(); }); video.addEventListener('ended', () => { log(`视频播放结束: ${getVideoInfo(video)}`); state.playbackHistory.push({ video: getVideoInfo(video), time: Date.now(), action: 'ended' }); if (config.autoPlayNext) { setTimeout(() => playNextChapter(video), config.delayBeforeNext); } }); video.addEventListener('error', (e) => { log(`视频错误: ${getVideoInfo(video)}`); if (config.autoRetry) { setTimeout(() => { log('尝试重新加载视频'); video.load(); safePlayVideo(video); }, 3000); } }); let lastTimeUpdate = 0, lastCurrentTime = 0; video.addEventListener('timeupdate', () => { const now = Date.now(), currentTime = video.currentTime; if (lastTimeUpdate > 0) { const realTimePassed = (now - lastTimeUpdate) / 1000; const videoTimePassed = currentTime - lastCurrentTime; const playbackRate = videoTimePassed / realTimePassed; if (playbackRate > config.maxPlaybackRate && realTimePassed > 1) { log(`检测到异常播放速度: ${playbackRate.toFixed(2)}倍`); if (config.smartAntiAcceleration) { const safeTime = lastCurrentTime + (realTimePassed * 1.1); video.currentTime = safeTime; log(`调整时间: ${currentTime.toFixed(1)} -> ${safeTime.toFixed(1)}`); } } } lastTimeUpdate = now; lastCurrentTime = currentTime; updatePanelInfo(); }); } function setupAutoPlay(video) { if (video.readyState >= 2) { safePlayVideo(video); } else { video.addEventListener('loadeddata', () => { setTimeout(() => safePlayVideo(video), 500); }, { once: true }); } } function safePlayVideo(video) { if (!video || video.ended) return; if (video.readyState < 1) { video.load(); setTimeout(() => safePlayVideo(video), 1000); return; } video.play().then(() => { log(`视频播放成功: ${getVideoInfo(video)}`); }).catch(err => { log(`视频播放失败: ${err.message}`); if (config.autoRetry) setTimeout(() => safePlayVideo(video), 3000); }); } function setupAutoPlayNext(video) { if (!window._videoEndHandlers) window._videoEndHandlers = new WeakMap(); const oldHandler = window._videoEndHandlers.get(video); if (oldHandler) video.removeEventListener('ended', oldHandler); const endHandler = () => { log(`视频结束,准备播放下一个: ${getVideoInfo(video)}`); if (config.autoPlayNext) { setTimeout(() => playNextChapter(video), config.delayBeforeNext); } }; video.addEventListener('ended', endHandler); window._videoEndHandlers.set(video, endHandler); } function playNextChapter(currentVideo) { log('寻找下一个章节...'); const allVideos = Array.from(document.querySelectorAll('video.videoplayer-video, video')) .filter(v => !v.ended && v.src && v.src !== currentVideo.src); if (allVideos.length > 0) { const currentIndex = allVideos.findIndex(v => v === currentVideo); if (currentIndex !== -1 && currentIndex + 1 < allVideos.length) { switchToVideo(allVideos[currentIndex + 1]); return; } const otherVideo = allVideos.find(v => v !== currentVideo); if (otherVideo) { switchToVideo(otherVideo); return; } } const nextChapter = findNextChapterElement(); if (nextChapter) { log('找到下一个章节元素,尝试点击'); simulateClick(nextChapter); return; } const nextPageBtn = findNextPageButton(); if (nextPageBtn) { log('找到下一页按钮,尝试点击'); simulateClick(nextPageBtn); return; } log('未找到下一个章节或视频'); showAllCompleteMessage(); } function switchToVideo(video) { if (!video || !video.src) return; log(`切换到视频: ${getVideoInfo(video)}`); if (state.currentVideo && !state.currentVideo.paused) state.currentVideo.pause(); state.currentVideo = video; setTimeout(() => { safePlayVideo(video); video.scrollIntoView({ behavior: 'smooth', block: 'center' }); }, 500); } function setupAntiAccelerationProtection(video) { let lastSeekTime = 0, lastReportedTime = 0; video.addEventListener('seeking', () => { lastSeekTime = Date.now(); log(`视频跳转: ${video.currentTime.toFixed(1)}s`); }); video.addEventListener('seeked', () => { const seekDuration = Date.now() - lastSeekTime; log(`跳转完成,耗时: ${seekDuration}ms`); }); setInterval(() => { if (!video.paused && !video.ended) { const now = Date.now(); if (now - lastReportedTime > 5000) { lastReportedTime = now; log(`播放进度报告: ${video.currentTime.toFixed(1)}s / ${video.duration.toFixed(1)}s`); } } }, 1000); } function getVideoInfo(video) { if (!video) return '无视频'; const src = video.src || ''; const shortSrc = src.split('/').pop() || '无src'; const time = video.currentTime.toFixed(1); const duration = video.duration ? video.duration.toFixed(1) : '未知'; return `${shortSrc.substring(0, 20)}... [${time}/${duration}s]`; } function findNextChapterElement() { const selectors = ['.courseItem:not(.finished)', '.chapter-item:not(.active)', '[class*="item"]:not([class*="finished"]):not([class*="active"])', '.enterStudyBtn', '.study-btn']; for (const selector of selectors) { const elements = document.querySelectorAll(selector); for (const el of elements) { if (el.offsetParent !== null && el.getBoundingClientRect().width > 0) return el; } } return null; } function findNextPageButton() { const buttons = ['.next-page', '.next-btn', '[class*="next"]', '[onclick*="next"]'] .map(selector => document.querySelector(selector)) .find(btn => btn && btn.offsetParent !== null); return buttons; } function simulateClick(element) { if (!element) return; element.click(); ['mousedown', 'mouseup', 'click'].forEach(eventType => { element.dispatchEvent(new MouseEvent(eventType, { view: window, bubbles: true, cancelable: true })); }); } function showAllCompleteMessage() { const msg = document.createElement('div'); msg.innerHTML = `
🎉
学习完成
所有视频已播放完成
`; document.body.appendChild(msg); setTimeout(() => { if (msg.parentNode) msg.parentNode.removeChild(msg); }, 4000); } function setupGlobalEventListeners() { window.addEventListener('blur', () => { state.isWindowHidden = true; log('窗口失去焦点'); }); window.addEventListener('focus', () => { state.isWindowHidden = false; log('窗口获得焦点'); setTimeout(() => { if (state.currentVideo && state.currentVideo.paused) safePlayVideo(state.currentVideo); }, 500); }); window.addEventListener('beforeunload', () => { state.videoElements.clear(); }); } function setupPlaybackMonitor() { setInterval(() => { if (state.currentVideo) { if (state.currentVideo.paused && !state.currentVideo.ended && config.antiPause) { const pauseDuration = Date.now() - (state.currentVideo._lastPlayTime || 0); if (pauseDuration > 3000 && state.currentVideo._protectedState?.wasPlaying) { log(`视频意外暂停 ${pauseDuration}ms,尝试恢复`); safePlayVideo(state.currentVideo); } } if (!state.currentVideo.paused) state.currentVideo._lastPlayTime = Date.now(); } const now = Date.now(); state.playbackHistory = state.playbackHistory.filter(record => now - record.time < 300000); }, 2000); } function addEnhancedControlPanel() { const panelId = 'video-optimizer-panel-' + state.frameId; if (document.getElementById(panelId)) return; state.panelAdded = true; const panel = document.createElement('div'); panel.id = panelId; let isDragging = false; let dragOffsetX = 0; let dragOffsetY = 0; let currentX = 0; let currentY = 0; function savePosition(x, y) { try { localStorage.setItem('videoPanelPos_' + state.frameId, JSON.stringify({x, y})); } catch(e) { log('保存位置失败: ' + e.message); } } function loadPosition() { try { const saved = localStorage.getItem('videoPanelPos_' + state.frameId); if (saved) return JSON.parse(saved); } catch(e) { log('读取位置失败: ' + e.message); } return null; } function setPanelPosition(x, y) { panel.style.left = x + 'px'; panel.style.top = y + 'px'; currentX = x; currentY = y; } function startDrag(e) { if (e.button !== 0) return; isDragging = true; dragOffsetX = e.clientX - currentX; dragOffsetY = e.clientY - currentY; panel.style.cursor = 'grabbing'; panel.style.userSelect = 'none'; e.preventDefault(); e.stopPropagation(); document.addEventListener('mousemove', doDrag); document.addEventListener('mouseup', stopDrag); log('开始拖拽面板'); } function doDrag(e) { if (!isDragging) return; let x = e.clientX - dragOffsetX; let y = e.clientY - dragOffsetY; const margin = 10; const panelWidth = panel.offsetWidth; const panelHeight = panel.offsetHeight; const maxX = window.innerWidth - panelWidth - margin; const maxY = window.innerHeight - panelHeight - margin; x = Math.max(margin, Math.min(x, maxX)); y = Math.max(margin, Math.min(y, maxY)); setPanelPosition(x, y); e.preventDefault(); } function stopDrag(e) { if (!isDragging) return; isDragging = false; panel.style.cursor = 'grab'; panel.style.userSelect = 'auto'; savePosition(currentX, currentY); document.removeEventListener('mousemove', doDrag); document.removeEventListener('mouseup', stopDrag); log('拖拽结束,位置已保存: ' + currentX + ', ' + currentY); if (e) { e.preventDefault(); e.stopPropagation(); } } const frameInfo = state.isVideoFrame ? '🎬 视频框架' : '📄 导航框架'; const scaleInfo = state.isVideoFrame ? ' (底部显示)' : ''; panel.innerHTML = `
${state.isVideoFrame ? '🎬' : '📄'}
视频控制台${scaleInfo}
${frameInfo} - ${state.frameId.substring(0, 8)}
${state.isVideoFrame ? `
音量控制
0% 100%
${Math.round(state.currentVolume * 100)}%
` : ''} ${state.isVideoFrame ? `
播放速度 1.0x
0.5x 1.0x 1.5x 2.0x
` : ''} ${state.isVideoFrame ? `
当前视频
等待检测视频...
` : '
导航框架 - 无视频控制功能
'}
视频: 0
状态: 等待
`; document.body.appendChild(panel); const savedPos = loadPosition(); if (savedPos && savedPos.x !== undefined && savedPos.y !== undefined) { setPanelPosition(savedPos.x, savedPos.y); log('使用保存的位置: ' + savedPos.x + ', ' + savedPos.y); } else { if (state.isVideoFrame) { const panelWidth = 320 * state.panelScale; const panelHeight = 450 * state.panelScale; const centerX = (window.innerWidth - panelWidth) / 2; const bottomY = window.innerHeight - panelHeight - 20; setPanelPosition(centerX, bottomY); log('视频框架默认位置: ' + centerX + ', ' + bottomY); } else { const panelWidth = 320; const rightX = window.innerWidth - panelWidth - 20; setPanelPosition(rightX, 80); log('导航框架默认位置: ' + rightX + ', 80'); } } const header = document.getElementById(`panel-header-${state.frameId}`); if (header) { header.addEventListener('mousedown', startDrag); log('拖拽事件已绑定到面板标题'); } else { log('错误:找不到面板标题元素'); } document.getElementById(`btn-copy-${state.frameId}`).addEventListener('click', function() { config.enableCopy = !config.enableCopy; this.textContent = config.enableCopy ? '📋 复制' : '🚫 复制'; this.style.background = config.enableCopy ? '#4caf50' : '#666'; if (config.enableCopy) { enableCopySelection(); showNotification('复制限制已解除', '#4caf50'); } }); document.getElementById(`btn-rightclick-${state.frameId}`).addEventListener('click', function() { config.enableRightClick = !config.enableRightClick; this.textContent = config.enableRightClick ? '🖱️ 右键' : '🚫 右键'; this.style.background = config.enableRightClick ? '#4caf50' : '#666'; if (config.enableRightClick) { enableRightClick(); showNotification('右键限制已解除', '#4caf50'); } }); document.getElementById(`btn-autoplay-${state.frameId}`).addEventListener('click', function() { config.autoPlay = !config.autoPlay; this.textContent = config.autoPlay ? '▶️ 播放' : '⏸️ 播放'; this.style.background = config.autoPlay ? '#4caf50' : '#666'; log(`自动播放 ${config.autoPlay ? '开启' : '关闭'}`); }); document.getElementById(`btn-autonext-${state.frameId}`).addEventListener('click', function() { config.autoPlayNext = !config.autoPlayNext; this.textContent = config.autoPlayNext ? '⏭️ 连播' : '⏹️ 连播'; this.style.background = config.autoPlayNext ? '#4caf50' : '#666'; log(`自动连播 ${config.autoPlayNext ? '开启' : '关闭'}`); }); document.getElementById(`btn-antipause-${state.frameId}`).addEventListener('click', function() { config.antiPause = !config.antiPause; this.textContent = config.antiPause ? '🔒 防暂停' : '🔓 防暂停'; this.style.background = config.antiPause ? '#2196f3' : '#666'; log(`防暂停 ${config.antiPause ? '开启' : '关闭'}`); }); document.getElementById(`btn-next-${state.frameId}`).addEventListener('click', () => { if (state.currentVideo) playNextChapter(state.currentVideo); }); if (state.isVideoFrame) { document.getElementById(`btn-mute-${state.frameId}`).addEventListener('click', toggleMute); const volumeSlider = document.getElementById(`volume-slider-${state.frameId}`); volumeSlider.addEventListener('input', function() { const volume = parseInt(this.value) / 100; setVolume(volume); }); volumeSlider.addEventListener('change', function() { const volume = parseInt(this.value) / 100; setVolume(volume); }); } if (state.isVideoFrame) { let playbackSpeed = 1.0; function updateSpeedDisplay() { document.getElementById(`speed-display-${state.frameId}`).textContent = playbackSpeed.toFixed(1) + 'x'; const sliderValue = 5 + (playbackSpeed - 0.5) * 10; document.getElementById(`speed-slider-${state.frameId}`).value = sliderValue; if (state.currentVideo) { try { state.currentVideo.playbackRate = playbackSpeed; } catch(e) {} } } document.getElementById(`btn-slow-${state.frameId}`).addEventListener('click', () => { playbackSpeed = Math.max(0.5, playbackSpeed - 0.1); updateSpeedDisplay(); }); document.getElementById(`btn-fast-${state.frameId}`).addEventListener('click', () => { playbackSpeed = Math.min(2.0, playbackSpeed + 0.1); updateSpeedDisplay(); }); document.getElementById(`speed-slider-${state.frameId}`).addEventListener('input', function() { const value = parseFloat(this.value); playbackSpeed = 0.5 + (value - 5) * 0.1; updateSpeedDisplay(); }); updateSpeedDisplay(); } if (state.isVideoFrame) { updateVolumeDisplay(); } let isMinimized = false; document.getElementById(`minimize-btn-${state.frameId}`).addEventListener('click', function() { const content = document.getElementById(`panel-content-${state.frameId}`); if (isMinimized) { content.style.display = 'block'; this.textContent = '−'; panel.style.height = 'auto'; } else { content.style.display = 'none'; this.textContent = '□'; panel.style.height = state.isVideoFrame ? '60px' : '60px'; } isMinimized = !isMinimized; }); document.getElementById(`close-btn-${state.frameId}`).addEventListener('click', () => { panel.style.display = 'none'; log('面板已关闭'); }); function updatePanelInfo() { const videoCount = state.videoElements.size; const currentVideo = state.currentVideo; const videoCountEl = panel.querySelector(`#video-count-${state.frameId}`); const statusEl = panel.querySelector(`#status-${state.frameId}`); if (videoCountEl) videoCountEl.textContent = videoCount; if (statusEl) statusEl.textContent = state.isWindowHidden ? '隐藏' : '活跃'; if (state.isVideoFrame) { const videoInfoEl = panel.querySelector(`#video-info-${state.frameId}`); if (currentVideo && videoInfoEl) { const info = getVideoInfo(currentVideo); const progress = currentVideo.duration ? `${(currentVideo.currentTime / currentVideo.duration * 100).toFixed(1)}%` : '加载中'; videoInfoEl.innerHTML = ` ${info}
进度: ${progress}
状态: ${currentVideo.paused ? '⏸️ 暂停' : '▶️ 播放'} `; } else if (videoInfoEl) { videoInfoEl.textContent = '等待检测视频...'; } } } setInterval(updatePanelInfo, 1000); updatePanelInfo(); log(`控制面板已添加到框架: ${state.frameId} (${state.isVideoFrame ? '视频-70%缩放' : '导航-正常大小'})`); } function updatePanelFrameInfo() { const panel = document.getElementById('video-optimizer-panel-' + state.frameId); if (!panel) return; const header = panel.querySelector(`#panel-header-${state.frameId}`); if (header) { const frameInfo = state.isVideoFrame ? '🎬 视频框架' : '📄 导航框架'; const scaleInfo = state.isVideoFrame ? ' (底部显示)' : ''; const infoDiv = header.querySelector('div > div'); if (infoDiv && infoDiv.children.length > 0) { infoDiv.children[0].textContent = '视频控制台' + scaleInfo; if (infoDiv.children.length > 1) { infoDiv.children[1].textContent = frameInfo + ' - ' + state.frameId.substring(0, 8); } } } } function updatePanelScale() { const panel = document.getElementById('video-optimizer-panel-' + state.frameId); if (!panel) return; panel.style.transform = `scale(${state.panelScale})`; } function showNotification(message, color = '#2196f3') { const notification = document.createElement('div'); notification.innerHTML = `
${message}
`; document.body.appendChild(notification); setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 2000); } function exposeGlobalControls() { window.videoOptimizer = { showPanel: function() { const panelId = 'video-optimizer-panel-' + state.frameId; if (!document.getElementById(panelId)) { addEnhancedControlPanel(); } else { const panel = document.getElementById(panelId); panel.style.display = 'block'; } return '面板已显示 - 框架: ' + state.frameId + ' 位置: ' + (state.isVideoFrame ? '底部' : '右上角'); }, hidePanel: function() { const panel = document.getElementById('video-optimizer-panel-' + state.frameId); if (panel) { panel.style.display = 'none'; return '面板已隐藏 - 框架: ' + state.frameId; } return '面板不存在 - 框架: ' + state.frameId; }, resetPosition: function() { const panel = document.getElementById('video-optimizer-panel-' + state.frameId); if (panel) { if (state.isVideoFrame) { const panelWidth = 320 * state.panelScale; const panelHeight = 380 * state.panelScale; const centerX = (window.innerWidth - panelWidth) / 2; const bottomY = window.innerHeight - panelHeight - 20; panel.style.left = centerX + 'px'; panel.style.top = bottomY + 'px'; try { localStorage.setItem('videoPanelPos_' + state.frameId, JSON.stringify({x: centerX, y: bottomY})); } catch(e) {} return '面板已重置到底部中央 - 框架: ' + state.frameId; } else { const panelWidth = 320; const rightX = window.innerWidth - panelWidth - 20; panel.style.left = rightX + 'px'; panel.style.top = '80px'; try { localStorage.setItem('videoPanelPos_' + state.frameId, JSON.stringify({x: rightX, y: 80})); } catch(e) {} return '面板已重置到右上角 - 框架: ' + state.frameId; } } return '面板不存在 - 框架: ' + state.frameId; }, setVolume: function(volume) { if (typeof volume !== 'number' || volume < 0 || volume > 1) { return '音量必须在0-1之间'; } setVolume(volume); return '音量已设置为: ' + Math.round(volume * 100) + '%'; }, toggleMute: function() { toggleMute(); return state.isMuted ? '已静音' : '已取消静音'; }, dragTest: function() { const panel = document.getElementById('video-optimizer-panel-' + state.frameId); if (!panel) return '面板不存在'; const header = panel.querySelector(`#panel-header-${state.frameId}`); if (!header) return '标题元素不存在'; const hasMousedown = header.hasAttribute('onmousedown') || (header.onmousedown !== null && header.onmousedown !== undefined); return '拖拽测试: ' + (hasMousedown ? '事件已绑定' : '事件未绑定'); }, getStatus: function() { const panel = document.getElementById('video-optimizer-panel-' + state.frameId); return { frameId: state.frameId, isVideoFrame: state.isVideoFrame, panelScale: state.panelScale, videos: state.videoElements.size, currentVideo: state.currentVideo ? getVideoInfo(state.currentVideo) : null, volume: state.currentVolume, isMuted: state.isMuted, panelVisible: !!panel && panel.style.display !== 'none', panelPosition: panel ? {left: panel.style.left, top: panel.style.top} : null }; } }; log('全局控制函数已暴露: window.videoOptimizer'); } setTimeout(init, 500); })();