// ==UserScript== // @name ENAEA自动刷课助手 // @namespace https://greasyfork.org/ // @version 1.0 // @description 中国教育干部网络学院(enaea.edu.cn)自动刷课工具 - 自动连续刷课、多页检测、倍速播放、自动静音、智能跳转 // @author Liontooth // @match https://study.enaea.edu.cn/* // @match https://*.ttcdw.cn/* // @match https://*.ertcloud.net/* // @grant none // @run-at document-start // @license MIT // @homepage https://github.com/chnlion/enaea-auto-study // @supportURL https://github.com/chnlion/enaea-auto-study/issues // @downloadURL none // ==/UserScript== (function() { 'use strict'; console.log('🚀 ENAEA自动刷课助手已启动'); // ==================== 配置项 ==================== let TARGET_SPEED = parseInt(localStorage.getItem('enaea_target_speed')) || 4; let AUTO_MUTE = localStorage.getItem('enaea_auto_mute') !== 'false'; let AUTO_JUMP = true; // 播放页自动跳转到未完成课程 let AUTO_SELECT_COURSE = true; // 列表页自动选择未完成课程 let AUTO_CONTINUOUS = localStorage.getItem('enaea_auto_continuous') !== 'false'; // 自动连续刷课 let CHECK_INTERVAL = parseInt(localStorage.getItem('enaea_check_interval')) || 15; // 检测间隔(秒) let MAX_CONTINUOUS_COUNT = 50; // 最大连续刷课次数 let processedVideos = new WeakSet(); let checkTimer = null; let lastCheckTime = 0; // ==================== 核心功能:劫持播放速度 ==================== function hijackPlaybackRate() { const originalDescriptor = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'playbackRate'); Object.defineProperty(HTMLMediaElement.prototype, 'playbackRate', { get: function() { return originalDescriptor.get.call(this); }, set: function(value) { originalDescriptor.set.call(this, TARGET_SPEED); console.log(`🎯 拦截并强制设置播放速度为${TARGET_SPEED}倍速`); }, configurable: true }); } function setVideoSpeed(video) { if (!video || processedVideos.has(video)) return false; try { video.playbackRate = TARGET_SPEED; processedVideos.add(video); console.log(`✅ 视频播放速度已设置为${TARGET_SPEED}倍速`); if (AUTO_MUTE) { video.muted = true; video.volume = 0; console.log('🔇 视频已静音'); } return true; } catch (e) { console.error('❌ 设置视频速度失败:', e); return false; } } function setAllVideos() { const videos = document.querySelectorAll('video'); let count = 0; videos.forEach(video => { if (setVideoSpeed(video)) { count++; } }); if (count > 0) { console.log(`🎬 找到并设置了 ${count} 个视频`); } } // ==================== MutationObserver监控新增视频 ==================== function startObserver() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.tagName === 'VIDEO') { setVideoSpeed(node); } else if (node.querySelectorAll) { const videos = node.querySelectorAll('video'); videos.forEach(video => setVideoSpeed(video)); } }); }); }); observer.observe(document.body || document.documentElement, { childList: true, subtree: true }); console.log('👀 视频监控器已启动'); } // ==================== 播放页:自动识别并跳转到未完成课程 ==================== function findAndJumpToUnfinishedCourse() { console.log('🔍 正在查找未完成的课程...'); console.log('📍 当前URL:', window.location.href); console.log('📍 document.readyState:', document.readyState); console.log('📍 document.body存在:', !!document.body); let allCourses = []; if (!document.body) { console.log('⚠️ 页面body还未加载,延迟1秒后重试...'); setTimeout(findAndJumpToUnfinishedCourse, 1000); return false; } let courseContents = document.querySelectorAll('.cvtb-MCK-course-content, .cvtb-NCK-course-content'); console.log(`📌 方法1:找到 ${courseContents.length} 个课程元素`); if (courseContents.length === 0) { courseContents = document.querySelectorAll('[class*="course-content"]'); console.log(`📌 方法2:找到 ${courseContents.length} 个包含 course-content 的元素`); } if (courseContents.length === 0) { courseContents = document.querySelectorAll('li'); console.log(`📌 方法3:找到 ${courseContents.length} 个 li 元素`); } courseContents.forEach((item, index) => { try { const progressElement = item.querySelector('.cvtb-MCK-CsCt-studyProgress, .cvtb-NCK-CsCt-studyProgress'); const titleElement = item.querySelector('.cvtb-MCK-CsCt-title, .cvtb-NCK-CsCt-title, [class*="title"]'); if (!progressElement || !titleElement) { return; } const progressText = progressElement.textContent.trim(); const progressMatch = progressText.match(/(\d+)%/); const progress = progressMatch ? parseInt(progressMatch[1]) : 0; const title = titleElement.textContent.trim() || `课程${index + 1}`; const linkElement = item.querySelector('a, [onclick], .cvtb-MCK-CsCt-title, .cvtb-NCK-CsCt-title') || item; if (!linkElement) return; allCourses.push({ element: item, title: title, progress: progress, link: linkElement, index: allCourses.length + 1 }); } catch (e) { console.error(`❌ 解析课程 ${index + 1} 时出错:`, e); } }); if (allCourses.length === 0) { console.log('⚠️ 未找到任何课程'); return false; } console.log(`📚 共找到 ${allCourses.length} 门课程`); const unfinishedCourse = allCourses.find(course => course.progress < 100); if (!unfinishedCourse) { console.log('🎉 当前课程所有视频都已完成!'); return false; } console.log(`✅ 找到未完成视频: "${unfinishedCourse.title}" (${unfinishedCourse.progress}%)`); unfinishedCourse.element.style.outline = '3px solid rgb(74, 222, 128)'; unfinishedCourse.element.style.outlineOffset = '2px'; unfinishedCourse.element.style.transition = 'all 0.3s ease'; setTimeout(() => { console.log(`🚀 正在跳转到: ${unfinishedCourse.title}`); try { unfinishedCourse.link.click(); } catch (e) { console.error('❌ 点击失败:', e); } }, 500); return true; } function autoJumpOnLoadInVideoPage() { if (!AUTO_JUMP) { console.log('⏸️ 自动跳转功能已关闭'); return; } if (window.self !== window.top) { console.log('⏸️ 当前在iframe中,跳过自动跳转'); return; } const url = window.location.href; if (!url.includes('study.enaea.edu.cn')) { console.log('⏸️ 当前不在study.enaea.edu.cn域名,跳过自动跳转'); return; } console.log('⏳ 将在3秒、5秒、8秒后尝试自动查找未完成课程...'); let jumpSuccess = false; function tryAutoFind(attemptNum) { if (jumpSuccess) { console.log(`⏭️ 第${attemptNum}次尝试取消(已成功跳转)`); return; } console.log(`🤖 第${attemptNum}次自动执行"查找未完成课程"功能...`); const courseElements = document.querySelectorAll('.cvtb-MCK-course-content, .cvtb-NCK-course-content'); console.log(` 预检查:找到 ${courseElements.length} 个课程元素`); if (courseElements.length > 0) { console.log('✅ 找到课程列表,准备分析并跳转到未完成课程...'); } const result = findAndJumpToUnfinishedCourse(); if (result === true) { jumpSuccess = true; console.log('🎉 自动跳转成功,后续尝试已取消'); } } setTimeout(() => { console.log('⏰ 第1次尝试(页面加载后3秒)'); tryAutoFind(1); }, 3000); setTimeout(() => { console.log('⏰ 第2次尝试(页面加载后5秒)'); tryAutoFind(2); }, 5000); setTimeout(() => { console.log('⏰ 第3次尝试(页面加载后8秒)'); tryAutoFind(3); }, 8000); } // ==================== 播放页:定时检测所有视频进度 ==================== function checkAllVideosCompleted() { // 只在课程播放页执行 const url = window.location.href; if (!url.includes('viewerforccvideo.do') && !url.includes('viewerforicourse.do')) { return; } if (!AUTO_CONTINUOUS) { return; } // 避免频繁检测 const now = Date.now(); if (now - lastCheckTime < CHECK_INTERVAL * 1000 - 1000) { return; } lastCheckTime = now; console.log('═══════════════════════════════════════'); console.log(`🔍 检测课程完成状态 (间隔${CHECK_INTERVAL}秒)`); const courseContents = document.querySelectorAll('.cvtb-MCK-course-content, .cvtb-NCK-course-content'); if (courseContents.length === 0) { console.log('⚠️ 未找到课程列表元素'); return; } console.log(`📊 找到 ${courseContents.length} 个课程视频`); let allCompleted = true; let completedCount = 0; let courseDetails = []; courseContents.forEach((item, index) => { try { const progressElement = item.querySelector('.cvtb-MCK-CsCt-studyProgress, .cvtb-NCK-CsCt-studyProgress'); const titleElement = item.querySelector('.cvtb-MCK-CsCt-title, .cvtb-NCK-CsCt-title, [class*="title"]'); if (!progressElement) return; const progressText = progressElement.textContent.trim(); const progressMatch = progressText.match(/(\d+)%/); const progress = progressMatch ? parseInt(progressMatch[1]) : 0; const title = titleElement ? titleElement.textContent.trim() : `视频${index + 1}`; courseDetails.push({ title, progress }); if (progress === 100) { completedCount++; } else { allCompleted = false; } } catch (e) { console.error(`❌ 解析视频 ${index + 1} 时出错:`, e); } }); console.log(`📈 完成进度: ${completedCount}/${courseContents.length}`); courseDetails.forEach((detail, idx) => { const status = detail.progress === 100 ? '✅' : '⏳'; console.log(` ${status} ${idx + 1}. ${detail.title}: ${detail.progress}%`); }); if (allCompleted && courseContents.length > 0) { console.log('🎉🎉🎉 当前课程所有视频已完成!'); console.log('📨 准备发送完成信号到列表页...'); // 发送完成信号 const signal = { timestamp: Date.now(), courseUrl: window.location.href, totalVideos: courseContents.length }; localStorage.setItem('enaea_course_completed_signal', JSON.stringify(signal)); // 增加连续刷课计数 let count = parseInt(localStorage.getItem('enaea_continuous_count') || '0'); count++; localStorage.setItem('enaea_continuous_count', count.toString()); console.log(`✅ 完成信号已发送!这是第 ${count} 门连续完成的课程`); // 停止检测定时器 if (checkTimer) { clearInterval(checkTimer); checkTimer = null; console.log('⏸️ 已停止课程完成检测定时器'); } } else { console.log(`⏳ 课程尚未完成,将在 ${CHECK_INTERVAL} 秒后再次检测`); } } function startCourseCompletionCheck() { const url = window.location.href; if (!url.includes('viewerforccvideo.do') && !url.includes('viewerforicourse.do')) { return; } if (!AUTO_CONTINUOUS) { console.log('⏸️ 自动连续刷课功能已关闭'); return; } console.log(`🔄 启动课程完成检测 (间隔: ${CHECK_INTERVAL}秒)`); // 清除旧的定时器 if (checkTimer) { clearInterval(checkTimer); } // 启动新的定时器 checkTimer = setInterval(checkAllVideosCompleted, CHECK_INTERVAL * 1000); // 立即执行一次(延迟10秒,等页面加载) setTimeout(checkAllVideosCompleted, 10000); } // ==================== 列表页:自动选择未完成课程 ==================== function findAndClickUnfinishedCourseInList() { console.log('═══════════════════════════════════════'); console.log('📋 正在课程列表页面查找未完成的课程...'); let url = ''; try { url = window.location.href; console.log('📍 当前URL:', url); } catch (e) { console.log('⚠️ 无法获取URL'); } if (!document.body) { console.log('⚠️ 页面body还未加载,延迟1秒后重试...'); setTimeout(findAndClickUnfinishedCourseInList, 1000); return false; } const table = document.querySelector('#J_myOptionRecords'); console.log('🔍 查找表格 #J_myOptionRecords:', table ? '找到' : '未找到'); if (!table) { console.log('⚠️ 未找到课程列表表格,页面可能还在加载'); return false; } const allRows = document.querySelectorAll('#J_myOptionRecords tbody tr'); console.log(`📊 找到 ${allRows.length} 行数据`); let allCourses = []; allRows.forEach((row, index) => { try { const categoryTitle = row.querySelector('td[colspan="6"]'); if (categoryTitle) { console.log(`📂 分类: ${categoryTitle.textContent.trim()}`); return; } const progressElement = row.querySelector('.progressvalue'); if (!progressElement) { return; } const progressText = progressElement.textContent.trim(); const progressMatch = progressText.match(/(\d+)%/); const progress = progressMatch ? parseInt(progressMatch[1]) : 0; const titleElement = row.querySelector('.course-title'); const title = titleElement ? titleElement.getAttribute('title') || titleElement.textContent.trim() : `课程${index}`; const learnButton = row.querySelector('a.golearn'); if (!learnButton) { return; } allCourses.push({ row: row, title: title, progress: progress, button: learnButton, index: allCourses.length + 1 }); console.log(`✅ 课程 ${allCourses.length}: "${title}" - 进度: ${progress}%`); } catch (e) { console.error(`❌ 解析行 ${index + 1} 时出错:`, e); } }); if (allCourses.length === 0) { console.log('⚠️ 未找到任何课程'); return false; } console.log(`\n📚 共找到 ${allCourses.length} 门课程`); const unfinishedCourse = allCourses.find(course => course.progress < 100); if (!unfinishedCourse) { // 当前页全部完成,检查是否有下一页 console.log('✅ 当前页所有课程已完成'); // 获取分页信息 const nextBtn = document.querySelector('#J_myOptionRecords_next'); const isNextDisabled = nextBtn && nextBtn.classList.contains('paginate_button_disabled'); if (nextBtn && !isNextDisabled) { // 有下一页,获取当前页码信息 const activePageBtn = document.querySelector('.paginate_active'); const currentPage = activePageBtn ? activePageBtn.textContent.trim() : '?'; console.log(`📄 当前第 ${currentPage} 页已完成,准备翻到下一页...`); // 点击下一页按钮 nextBtn.click(); console.log('⏳ 等待页面加载(2秒)...'); // 等待页面加载后继续检测 setTimeout(() => { console.log('🔄 页面加载完成,继续检测下一页...'); findAndClickUnfinishedCourseInList(); }, 2000); return true; // 返回true表示正在处理 } else { // 没有下一页了,真的全部完成 console.log('🎉🎉🎉 太棒了!所有页面的课程都已完成 100%!'); console.log('🏆 学习任务全部完成!'); // 清除连续刷课计数 localStorage.removeItem('enaea_continuous_count'); // 弹窗提示 alert('🎉 恭喜!所有课程已完成!\n\n所有页面的课程已全部学习完毕。'); return false; } } console.log(`\n✅ 找到未完成课程: "${unfinishedCourse.title}" (${unfinishedCourse.progress}%)`); console.log(`🎯 这是第 ${unfinishedCourse.index} 门课程,即将打开...`); unfinishedCourse.row.style.backgroundColor = 'rgba(74, 222, 128, 0.2)'; unfinishedCourse.row.style.transition = 'all 0.3s ease'; setTimeout(() => { console.log(`🚀 正在打开课程: ${unfinishedCourse.title}`); try { unfinishedCourse.button.click(); return true; } catch (e) { console.error('❌ 点击失败:', e); const vurl = unfinishedCourse.button.getAttribute('data-vurl'); if (vurl) { console.log('🔄 尝试直接跳转到:', vurl); window.location.href = vurl; return true; } } return false; }, 1000); return true; } function autoSelectCourseInList() { if (!AUTO_SELECT_COURSE) { console.log('⏸️ 列表页自动选课功能已关闭'); return; } let isInIframe = false; try { isInIframe = (window.self !== window.top); } catch (e) { isInIframe = true; } if (isInIframe) { console.log('⏸️ 当前在iframe中,跳过列表页自动选课'); return; } let url = ''; try { url = window.location.href; } catch (e) { console.log('⚠️ 无法获取当前URL'); return; } console.log('🔍 列表页自动选课检测:'); console.log(' 当前URL:', url); if (url.includes('viewerforccvideo.do') || url.includes('viewerforicourse.do')) { console.log('⏸️ 当前在视频播放页面,跳过列表页自动选课'); return; } if (!url.includes('study.enaea.edu.cn')) { console.log('⏸️ 当前不在study.enaea.edu.cn域名,跳过列表页自动选课'); return; } console.log('✅ 页面检测通过,将在3秒、5秒、8秒后尝试在列表页自动选择未完成课程...'); let selectSuccess = false; function tryAutoSelect(attemptNum) { if (selectSuccess) { console.log(`⏭️ 第${attemptNum}次尝试取消(已成功选择)`); return; } console.log(`🤖 第${attemptNum}次自动执行"列表页选课"功能...`); const table = document.querySelector('#J_myOptionRecords'); if (!table) { console.log('⚠️ 未找到课程列表表格'); return; } console.log('✅ 找到课程列表表格,准备分析...'); const result = findAndClickUnfinishedCourseInList(); if (result === true) { selectSuccess = true; console.log('🎉 列表页自动选课成功,后续尝试已取消'); } } setTimeout(() => { console.log('⏰ 第1次尝试(页面加载后3秒)'); tryAutoSelect(1); }, 3000); setTimeout(() => { console.log('⏰ 第2次尝试(页面加载后5秒)'); tryAutoSelect(2); }, 5000); setTimeout(() => { console.log('⏰ 第3次尝试(页面加载后8秒)'); tryAutoSelect(3); }, 8000); } // ==================== 列表页:监听课程完成信号 ==================== function setupStorageListener() { const url = window.location.href; // 只在列表页监听 if (url.includes('viewerforccvideo.do') || url.includes('viewerforicourse.do')) { return; } if (!AUTO_CONTINUOUS) { console.log('⏸️ 自动连续刷课功能已关闭,不监听完成信号'); return; } console.log('👂 开始监听课程完成信号...'); // 监听 storage 事件 window.addEventListener('storage', (e) => { if (e.key === 'enaea_course_completed_signal') { console.log('═══════════════════════════════════════'); console.log('📨 收到课程完成信号!'); try { const signal = JSON.parse(e.newValue); console.log('📊 信号详情:', signal); handleCourseCompleted(); } catch (err) { console.error('❌ 解析信号失败:', err); } } }); // 兜底:定时检查信号(每5秒) setInterval(() => { const signal = localStorage.getItem('enaea_course_completed_signal'); if (signal) { try { const data = JSON.parse(signal); // 检查信号是否是最近10秒内的(避免处理旧信号) if (Date.now() - data.timestamp < 10000) { console.log('📨 定时检查到课程完成信号'); handleCourseCompleted(); } } catch (e) { // 忽略解析错误 } } }, 5000); } function handleCourseCompleted() { if (!AUTO_CONTINUOUS) { console.log('⏸️ 自动连续刷课功能已关闭'); return; } // 检查连续刷课次数 let count = parseInt(localStorage.getItem('enaea_continuous_count') || '0'); console.log(`📊 当前连续刷课计数: ${count}`); if (count >= MAX_CONTINUOUS_COUNT) { console.log(`⚠️ 已连续刷课 ${count} 门课程,达到上限 ${MAX_CONTINUOUS_COUNT}`); alert(`已连续自动刷课 ${count} 门课程!\n\n为了安全,自动刷课已暂停。\n请检查学习进度,如需继续请手动开启。`); AUTO_CONTINUOUS = false; localStorage.setItem('enaea_auto_continuous', 'false'); // 更新控制面板 const checkbox = document.getElementById('auto-continuous'); if (checkbox) checkbox.checked = false; return; } console.log('⏳ 等待2秒后刷新列表页...'); console.log('💡 刷新后将自动选择下一门未完成的课程'); // 清除完成信号(避免重复处理) localStorage.removeItem('enaea_course_completed_signal'); // 延迟2秒后刷新页面 setTimeout(() => { console.log('🔄 正在刷新页面...'); location.reload(); }, 2000); } // ==================== 自动点击继续学习 ==================== function autoClickContinue() { setInterval(() => { const continueBtn = document.querySelector('.el-dialog__footer button.el-button--primary'); if (continueBtn && continueBtn.textContent.includes('继续')) { console.log('🔄 检测到"继续学习"按钮,自动点击'); continueBtn.click(); } }, 2000); } // ==================== 监听事件 ==================== function setupEventListeners() { document.addEventListener('play', function(e) { if (e.target.tagName === 'VIDEO') { setVideoSpeed(e.target); } }, true); document.addEventListener('loadedmetadata', function(e) { if (e.target.tagName === 'VIDEO') { setVideoSpeed(e.target); } }, true); } function checkIframes() { const iframes = document.querySelectorAll('iframe'); if (iframes.length === 0) return; iframes.forEach((iframe, index) => { try { const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; if (iframeDoc) { const videos = iframeDoc.querySelectorAll('video'); videos.forEach(video => setVideoSpeed(video)); } } catch (e) { // 静默处理跨域错误 } }); } // ==================== 浮动控制面板 ==================== function createPanel() { // 判断当前页面类型 const url = window.location.href; const isVideoPage = url.includes('viewerforccvideo.do') || url.includes('viewerforicourse.do'); const pageType = isVideoPage ? '播放页' : '列表页'; const panel = document.createElement('div'); panel.id = 'enaea-control-panel'; // 根据页面类型生成不同的面板内容 let panelContent = ''; if (isVideoPage) { // ========== 播放页面板 ========== panelContent = `
🎓 ENAEA自动刷课助手 v1.0
📺 当前:播放页
下次检测: --
在 GitHub 上查看此项目
`; } else { // ========== 列表页面板 ========== panelContent = `
🎓 ENAEA自动刷课助手 v1.0
📋 当前:列表页
已连续完成: 0 门 (上限: ${MAX_CONTINUOUS_COUNT})
在 GitHub 上查看此项目
`; } panel.innerHTML = panelContent; const style = document.createElement('style'); style.textContent = ` #enaea-control-panel { position: fixed; top: 20px; left: 20px; width: 240px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 12px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); z-index: 999999; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; color: white; backdrop-filter: blur(10px); cursor: move; } .panel-header { padding: 12px 15px; background: rgba(0, 0, 0, 0.2); border-radius: 12px 12px 0 0; display: flex; justify-content: space-between; align-items: center; cursor: move; } .panel-content { padding: 15px; } .control-group { margin-bottom: 12px; } .control-group label { display: flex; align-items: center; font-size: 13px; cursor: pointer; } .control-group input[type="checkbox"] { margin-right: 8px; cursor: pointer; } .control-group select { margin-left: 8px; padding: 4px 8px; border-radius: 4px; border: none; background: rgba(255, 255, 255, 0.9); cursor: pointer; flex: 1; font-size: 12px; } #panel-minimize:hover { opacity: 0.7; } .control-group button:hover { opacity: 0.9; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } .control-group button:active { transform: translateY(0); } #continuous-count { font-weight: bold; color: #4ade80; } `; document.documentElement.appendChild(style); document.body.appendChild(panel); // 更新连续计数显示 function updateCountDisplay() { const countSpan = document.getElementById('continuous-count'); if (countSpan) { const count = localStorage.getItem('enaea_continuous_count') || '0'; countSpan.textContent = count; } } updateCountDisplay(); setInterval(updateCountDisplay, 5000); // 拖拽功能 let isDragging = false; let currentX, currentY, initialX, initialY; const header = document.getElementById('panel-header'); header.addEventListener('mousedown', (e) => { if (e.target.id === 'panel-minimize') return; initialX = e.clientX - panel.offsetLeft; initialY = e.clientY - panel.offsetTop; isDragging = true; }); document.addEventListener('mousemove', (e) => { if (isDragging) { e.preventDefault(); currentX = e.clientX - initialX; currentY = e.clientY - initialY; panel.style.left = currentX + 'px'; panel.style.top = currentY + 'px'; panel.style.right = 'auto'; } }); document.addEventListener('mouseup', () => { isDragging = false; }); // 最小化功能 const minimizeBtn = document.getElementById('panel-minimize'); const content = document.getElementById('panel-content'); let isMinimized = false; minimizeBtn.addEventListener('click', () => { isMinimized = !isMinimized; content.style.display = isMinimized ? 'none' : 'block'; minimizeBtn.textContent = isMinimized ? '+' : '−'; }); // 控件事件监听 document.getElementById('auto-mute').addEventListener('change', (e) => { AUTO_MUTE = e.target.checked; localStorage.setItem('enaea_auto_mute', AUTO_MUTE); console.log(`🔇 自动静音: ${AUTO_MUTE ? '开启' : '关闭'}`); setAllVideos(); }); document.getElementById('speed-select').addEventListener('change', (e) => { TARGET_SPEED = parseFloat(e.target.value); localStorage.setItem('enaea_target_speed', TARGET_SPEED); console.log(`⚡ 播放速度已调整为: ${TARGET_SPEED}x`); processedVideos = new WeakSet(); setAllVideos(); }); document.getElementById('auto-jump').addEventListener('change', (e) => { AUTO_JUMP = e.target.checked; console.log(`🚀 播放页自动跳转: ${AUTO_JUMP ? '开启' : '关闭'}`); }); document.getElementById('auto-select').addEventListener('change', (e) => { AUTO_SELECT_COURSE = e.target.checked; console.log(`📋 列表页自动选课: ${AUTO_SELECT_COURSE ? '开启' : '关闭'}`); }); document.getElementById('auto-continuous').addEventListener('change', (e) => { AUTO_CONTINUOUS = e.target.checked; localStorage.setItem('enaea_auto_continuous', AUTO_CONTINUOUS); console.log(`🔥 自动连续刷课: ${AUTO_CONTINUOUS ? '开启' : '关闭'}`); if (AUTO_CONTINUOUS) { // 如果在课程页,启动检测 const url = window.location.href; if (url.includes('viewerforccvideo.do') || url.includes('viewerforicourse.do')) { startCourseCompletionCheck(); } } else { // 停止检测 if (checkTimer) { clearInterval(checkTimer); checkTimer = null; console.log('⏸️ 已停止课程完成检测'); } } }); document.getElementById('check-interval').addEventListener('change', (e) => { CHECK_INTERVAL = parseInt(e.target.value); localStorage.setItem('enaea_check_interval', CHECK_INTERVAL); console.log(`⏱️ 检测间隔已调整为: ${CHECK_INTERVAL}秒`); // 如果正在检测,重启定时器 const url = window.location.href; if ((url.includes('viewerforccvideo.do') || url.includes('viewerforicourse.do')) && AUTO_CONTINUOUS) { if (checkTimer) { clearInterval(checkTimer); } checkTimer = setInterval(checkAllVideosCompleted, CHECK_INTERVAL * 1000); console.log('🔄 已重启课程完成检测定时器'); } }); // 播放页按钮事件 const findCourseBtn = document.getElementById('find-course-btn'); if (findCourseBtn) { findCourseBtn.addEventListener('click', () => { console.log('🔍 手动触发检测未完成视频...'); findAndJumpToUnfinishedCourse(); }); } const pauseCheckBtn = document.getElementById('pause-check-btn'); if (pauseCheckBtn) { let isPaused = false; pauseCheckBtn.addEventListener('click', () => { isPaused = !isPaused; if (isPaused) { // 暂停检测 if (checkTimer) { clearInterval(checkTimer); checkTimer = null; } pauseCheckBtn.textContent = '▶️ 恢复检测'; pauseCheckBtn.style.background = 'rgba(74, 222, 128, 0.3)'; console.log('⏸️ 已暂停自动检测'); } else { // 恢复检测 checkTimer = setInterval(checkAllVideosCompleted, CHECK_INTERVAL * 1000); pauseCheckBtn.textContent = '⏸️ 暂停检测'; pauseCheckBtn.style.background = 'rgba(255,255,255,0.2)'; console.log('▶️ 已恢复自动检测'); } }); } const manualCheckBtn = document.getElementById('manual-check-btn'); if (manualCheckBtn) { manualCheckBtn.addEventListener('click', () => { console.log('🔄 手动触发立即检测完成度...'); checkAllVideosCompleted(); }); } // 列表页按钮事件 const selectCourseBtn = document.getElementById('select-course-btn'); if (selectCourseBtn) { selectCourseBtn.addEventListener('click', () => { console.log('📋 手动触发列表页选课...'); findAndClickUnfinishedCourseInList(); }); } const refreshPageBtn = document.getElementById('refresh-page-btn'); if (refreshPageBtn) { refreshPageBtn.addEventListener('click', () => { console.log('🔄 刷新页面...'); location.reload(); }); } const clearSignalBtn = document.getElementById('clear-signal-btn'); if (clearSignalBtn) { clearSignalBtn.addEventListener('click', () => { localStorage.removeItem('enaea_course_completed_signal'); localStorage.removeItem('enaea_continuous_count'); console.log('🧹 已清除完成信号和连续计数'); updateCountDisplay(); alert('已清除完成信号和连续计数!'); }); } console.log('✅ 控制面板已创建'); } // ==================== 初始化 ==================== function init() { console.log('═══════════════════════════════════════'); console.log('📚 ENAEA自动刷课助手 v1.0'); console.log('✨ 自动连续刷课 + 列表页自动选课 + 播放页自动刷课'); console.log('👤 作者: Liontooth'); console.log('═══════════════════════════════════════'); // 诊断信息 console.log('🔍 环境诊断:'); try { console.log(' - 当前URL:', window.location.href); console.log(' - 是否在iframe:', window.self !== window.top); console.log(' - document.readyState:', document.readyState); console.log(' - 自动连续刷课:', AUTO_CONTINUOUS ? '✅ 开启' : '⏸️ 关闭'); console.log(' - 检测间隔:', CHECK_INTERVAL + '秒'); } catch (e) { console.log(' - 诊断出错:', e.message); } // 视频控制初始化 setTimeout(setAllVideos, 100); setTimeout(setAllVideos, 500); setTimeout(setAllVideos, 1000); setTimeout(setAllVideos, 2000); hijackPlaybackRate(); startObserver(); setInterval(setAllVideos, 2000); setupEventListeners(); // 判断当前页面类型并执行相应的自动化功能 const currentUrl = window.location.href; console.log('📍 检测到当前页面类型...'); if (currentUrl.includes('viewerforccvideo.do') || currentUrl.includes('viewerforicourse.do')) { console.log('📺 识别为:视频播放页面'); } else if (currentUrl.includes('study.enaea.edu.cn')) { console.log('📋 识别为:课程列表页面'); } window.addEventListener('load', function() { setTimeout(setAllVideos, 500); setTimeout(setAllVideos, 1500); // 判断当前页面类型并执行相应的自动化功能 const url = window.location.href; if (url.includes('viewerforccvideo.do') || url.includes('viewerforicourse.do')) { // 视频播放页面 console.log('🎬 启动视频播放页功能...'); autoJumpOnLoadInVideoPage(); // 启动课程完成检测 if (AUTO_CONTINUOUS) { startCourseCompletionCheck(); } } else if (url.includes('study.enaea.edu.cn')) { // 课程列表页面 console.log('📋 启动课程列表页功能...'); autoSelectCourseInList(); // 监听课程完成信号 setupStorageListener(); } }); setTimeout(checkIframes, 3000); setInterval(checkIframes, 5000); autoClickContinue(); if (document.body) { createPanel(); } else { setTimeout(() => { if (document.body) createPanel(); }, 1000); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();