// ==UserScript== // @name 灯塔-学习助手 // @namespace https://gbwlxy.dtdjzx.gov.cn/ // @version 2.0.0 // @description 干部网络学院学习自动化助手,支持倍速播放和智能控制 // @author duocaikun // @match https://gbwlxy.dtdjzx.gov.cn/content* // ==/UserScript== (function() { 'use strict'; console.log("学习助手已启动"); // 控制状态 - 所有功能默认开启 let controlState = { masterSwitch: true, // 总开关 autoPlay: true, // 自动播放 autoSkipTest: true, // 自动跳过答题 autoNext: true, // 自动跳转下一个视频 playbackRate: 2 // 播放速度 (0.5, 1, 1.5, 2) }; let interval1; let interval2; let testShow = false; let floatingWindow = null; let controlPanel = null; let playbackRateInterval = null; let videoCheckInterval = null; let isDragging = false; let dragOffsetX = 0; let dragOffsetY = 0; let hidePanelTimeout = null; // 创建悬浮窗和控制面板 function createFloatingUI() { // 主悬浮按钮 floatingWindow = document.createElement('div'); floatingWindow.id = 'study-assistant-float'; floatingWindow.innerHTML = `
`; // 添加样式 const style = document.createElement('style'); style.textContent = ` #study-assistant-float { position: fixed; left: 20px; top: 50%; transform: translateY(-50%); z-index: 10000; font-family: 'HarmonyOS Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; opacity: 0.7; transition: opacity 0.3s ease; cursor: move; user-select: none; } #study-assistant-float:hover { opacity: 1; } #study-assistant-float.dragging { opacity: 1; transition: none; } .assistant-status { width: 50px; height: 50px; background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3); transition: all 0.3s ease; border: 2px solid #fff; } .assistant-status:hover { transform: scale(1.1); box-shadow: 0 6px 16px rgba(24, 144, 255, 0.4); } .assistant-status.inactive { background: linear-gradient(135deg, #8c8c8c 0%, #595959 100%); box-shadow: 0 4px 12px rgba(140, 140, 140, 0.3); } .status-circle { width: 12px; height: 12px; border-radius: 50%; background: #fff; transition: all 0.3s ease; } .assistant-status.active .status-circle { background: #52c41a; box-shadow: 0 0 8px #52c41a; } .control-panel { position: absolute; bottom: 60px; left: 0; width: 200px; background: #fff; border-radius: 12px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); border: 1px solid #e8e8e8; padding: 12px 16px; animation: slideUp 0.3s ease; } @keyframes slideUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .control-item { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; font-size: 13px; color: #595959; } .control-item:last-child { margin-bottom: 0; } .divider { height: 1px; background: #f0f0f0; margin: 4px 0; } .hw-switch { position: relative; display: inline-block; width: 36px; height: 20px; } .hw-switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background: #ccc; transition: .4s; border-radius: 20px; } .slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 2px; bottom: 2px; background: white; transition: .4s; border-radius: 50%; } input:checked + .slider { background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); } input:checked + .slider:before { transform: translateX(16px); } .speed-control { flex-direction: column; align-items: flex-start; } .speed-buttons { display: flex; gap: 4px; margin-top: 8px; width: 100%; } .speed-btn { flex: 1; padding: 6px 0; border: 1px solid #d9d9d9; background: #fff; border-radius: 6px; font-size: 12px; color: #595959; cursor: pointer; transition: all 0.3s ease; } .speed-btn:hover { border-color: #1890ff; color: #1890ff; } .speed-btn.active { background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); color: #fff; border-color: #1890ff; } `; document.head.appendChild(style); document.body.appendChild(floatingWindow); // 获取控制元素 controlPanel = document.getElementById('control-panel'); const statusButton = document.getElementById('assistant-status'); const masterSwitch = document.getElementById('master-switch'); const autoPlaySwitch = document.getElementById('auto-play'); const autoSkipSwitch = document.getElementById('auto-skip'); const autoNextSwitch = document.getElementById('auto-next'); const speedButtons = document.querySelectorAll('.speed-btn'); // 添加拖动功能 function startDrag(e) { isDragging = true; floatingWindow.classList.add('dragging'); const rect = floatingWindow.getBoundingClientRect(); dragOffsetX = e.clientX - rect.left; dragOffsetY = e.clientY - rect.top; e.preventDefault(); } function onDrag(e) { if (!isDragging) return; const x = e.clientX - dragOffsetX; const y = e.clientY - dragOffsetY; // 限制在视口范围内 const maxX = window.innerWidth - floatingWindow.offsetWidth; const maxY = window.innerHeight - floatingWindow.offsetHeight; floatingWindow.style.left = Math.max(0, Math.min(x, maxX)) + 'px'; floatingWindow.style.top = Math.max(0, Math.min(y, maxY)) + 'px'; floatingWindow.style.transform = 'none'; // 移除初始的transform } function stopDrag() { isDragging = false; floatingWindow.classList.remove('dragging'); } // 绑定拖动事件 floatingWindow.addEventListener('mousedown', startDrag); document.addEventListener('mousemove', onDrag); document.addEventListener('mouseup', stopDrag); // 鼠标悬停事件 - 显示控制面板 floatingWindow.addEventListener('mouseenter', function() { if (hidePanelTimeout) { clearTimeout(hidePanelTimeout); hidePanelTimeout = null; } controlPanel.style.display = 'block'; }); // 鼠标离开事件 - 延迟隐藏控制面板 floatingWindow.addEventListener('mouseleave', function(e) { // 检查鼠标是否真的离开了整个悬浮窗区域 const relatedTarget = e.relatedTarget; if (!floatingWindow.contains(relatedTarget)) { hidePanelTimeout = setTimeout(function() { controlPanel.style.display = 'none'; }, 300); } }); // 控制面板内部鼠标进入 - 取消隐藏 controlPanel.addEventListener('mouseenter', function() { if (hidePanelTimeout) { clearTimeout(hidePanelTimeout); hidePanelTimeout = null; } }); // 总开关事件 masterSwitch.addEventListener('change', function() { controlState.masterSwitch = this.checked; if (controlState.masterSwitch) { // 开启总开关时,自动开启所有子功能 controlState.autoPlay = true; controlState.autoSkipTest = true; controlState.autoNext = true; autoPlaySwitch.checked = true; autoSkipSwitch.checked = true; autoNextSwitch.checked = true; // 启动所有功能 startAllFunctions(); } else { // 关闭总开关时,关闭所有功能 controlState.autoPlay = false; controlState.autoSkipTest = false; controlState.autoNext = false; autoPlaySwitch.checked = false; autoSkipSwitch.checked = false; autoNextSwitch.checked = false; // 停止所有功能 stopAllFunctions(); } updateStatusDisplay(); }); // 自动播放开关事件 autoPlaySwitch.addEventListener('change', function() { controlState.autoPlay = this.checked; updateMasterSwitchState(); }); // 跳过答题开关事件 autoSkipSwitch.addEventListener('change', function() { controlState.autoSkipTest = this.checked; updateMasterSwitchState(); }); // 自动下一节开关事件 autoNextSwitch.addEventListener('change', function() { controlState.autoNext = this.checked; updateMasterSwitchState(); }); // 倍速按钮事件 speedButtons.forEach(button => { button.addEventListener('click', function() { const speed = parseFloat(this.dataset.speed); controlState.playbackRate = speed; // 更新按钮状态 speedButtons.forEach(btn => btn.classList.remove('active')); this.classList.add('active'); // 应用播放速度 applyPlaybackRate(); }); }); // 启动播放速度监控 startPlaybackRateMonitor(); // 启动视频检查 startVideoCheck(); } // 启动播放速度监控 function startPlaybackRateMonitor() { if (playbackRateInterval) { clearInterval(playbackRateInterval); } playbackRateInterval = setInterval(() => { updateSpeedButtonsFromVideo(); }, 1000); } // 启动视频检查,确保倍速设置生效 function startVideoCheck() { if (videoCheckInterval) { clearInterval(videoCheckInterval); } videoCheckInterval = setInterval(() => { ensurePlaybackRate(); }, 1500); } // 确保播放速度设置生效 function ensurePlaybackRate() { if (!controlState.masterSwitch) return; const video = document.querySelector('video'); if (video && Math.abs(video.playbackRate - controlState.playbackRate) > 0.1) { console.log(`检测到播放速度被重置为 ${video.playbackRate}x,重新设置为 ${controlState.playbackRate}x`); applyPlaybackRate(); } } // 根据视频实际速度更新倍速按钮状态 function updateSpeedButtonsFromVideo() { const video = document.querySelector('video'); if (!video) return; const currentRate = video.playbackRate; const speedButtons = document.querySelectorAll('.speed-btn'); // 找到与当前播放速度匹配的按钮 let foundMatch = false; speedButtons.forEach(button => { const buttonSpeed = parseFloat(button.dataset.speed); if (Math.abs(buttonSpeed - currentRate) < 0.1) { button.classList.add('active'); foundMatch = true; } else { button.classList.remove('active'); } }); // 如果没有找到匹配的按钮,更新控制状态 if (!foundMatch) { controlState.playbackRate = currentRate; } } // 启动所有功能 function startAllFunctions() { // 确保定时器已清除 clearIntervals(); // 重新设置定时器 interval1 = setInterval(checkVideo, 2000); interval2 = setInterval(playNext, 2000); // 立即应用播放速度,并设置定期检查 setTimeout(applyPlaybackRate, 500); setTimeout(applyPlaybackRate, 1500); setTimeout(applyPlaybackRate, 3000); console.log('所有功能已启动'); } // 停止所有功能 function stopAllFunctions() { // 清除定时器 clearIntervals(); // 暂停视频 pauseVideo(); console.log('所有功能已停止'); } // 更新总开关状态(根据子开关状态) function updateMasterSwitchState() { const masterSwitch = document.getElementById('master-switch'); // 如果有任何子开关开启,则自动开启总开关 if (controlState.autoPlay || controlState.autoSkipTest || controlState.autoNext) { if (!controlState.masterSwitch) { controlState.masterSwitch = true; masterSwitch.checked = true; startAllFunctions(); } } else { // 所有子开关都关闭时,关闭总开关 if (controlState.masterSwitch) { controlState.masterSwitch = false; masterSwitch.checked = false; stopAllFunctions(); } } updateStatusDisplay(); } // 更新状态显示 function updateStatusDisplay() { const statusButton = document.getElementById('assistant-status'); if (controlState.masterSwitch) { statusButton.classList.add('active'); statusButton.classList.remove('inactive'); } else { statusButton.classList.remove('active'); statusButton.classList.add('inactive'); } } // 应用播放速度 function applyPlaybackRate() { const video = document.querySelector('video'); if (video) { video.playbackRate = controlState.playbackRate; console.log(`播放速度设置为: ${controlState.playbackRate}倍速`); // 更新按钮状态 updateSpeedButtonsFromVideo(); } } // 暂停视频 function pauseVideo() { const video = document.querySelector('video'); if (video && !video.paused) { video.pause(); console.log('视频已暂停'); } } // 清除定时器 function clearIntervals() { if (interval1) { clearInterval(interval1); interval1 = null; } if (interval2) { clearInterval(interval2); interval2 = null; } if (videoCheckInterval) { clearInterval(videoCheckInterval); videoCheckInterval = null; } } // 原有功能函数 function closeTest() { if (!controlState.autoSkipTest || !controlState.masterSwitch) return; const dialog = document.querySelector('.el-dialog__body'); if (dialog) { const exitBtn = dialog.querySelector('.exitBtn'); if (exitBtn){ exitBtn.click(); testShow = true; console.log('已跳过答题'); } } } function isEnd() { const currentTime = document.querySelector('.vjs-current-time-display'); const totalTime = document.querySelector('.vjs-duration-display'); if (currentTime && totalTime) { return currentTime.innerText === totalTime.innerText; } return false; } function checkVideo() { if (!controlState.autoPlay || !controlState.masterSwitch) return; if (isEnd() || testShow) { return; } if (document.querySelector('.vjs-paused')) { const videoBox = document.querySelector('.vjs-icon-placeholder'); if (videoBox) { videoBox.click(); console.log('检测到暂停,已自动播放'); // 播放后重新设置倍速,确保生效 setTimeout(applyPlaybackRate, 500); } } } function playNext() { if (!controlState.autoNext || !controlState.masterSwitch) return; if(isEnd() || testShow) { const wrap = document.querySelector('div[class$="CourceList-wrap"]'); if (!wrap) return; const list = wrap.querySelector('.course-list-warp'); if (!list) return; for (let course of list.children) { const stateEl = course.querySelector('.state-paused'); const courseNameEl = course.querySelector('.top-title'); const videoNameEl = document.querySelector('.path'); if (!stateEl || !courseNameEl || !videoNameEl) continue; const state = stateEl.innerText; const courseName = courseNameEl.innerText; const videoName = videoNameEl.innerText; if (state === '未学习' || state === '学习中') { if (courseName === videoName) { location.reload(); continue; } const playVideo = course.querySelector('.play'); if (playVideo) { playVideo.click(); console.log('自动跳转到下一节视频'); // 跳转后等待视频加载,然后设置倍速 setTimeout(() => { setTimeout(applyPlaybackRate, 1000); setTimeout(applyPlaybackRate, 3000); }, 1000); break; } } } let listOver = true; for (let course of list.children) { const stateEl = course.querySelector('.state-paused'); if (stateEl && (stateEl.innerText === '未学习' || stateEl.innerText === '学习中')) { listOver = false; } } if (listOver) { const rightButton = wrap.querySelector('.right button'); if (rightButton && rightButton.classList.contains('is-disabled')) { clearInterval(interval2); console.log('所有课程已完成'); } else if (rightButton) { rightButton.click(); console.log('切换到下一组课程'); } } } } // 初始化 window.onload = function(event) { // 创建悬浮UI createFloatingUI(); // 设置定时器(默认开启状态,所以启动所有功能) startAllFunctions(); setInterval(closeTest, 3000); console.log('学习助手已完全加载'); }; })();