// ==UserScript== // @name 智慧树全功能助手(手动搜课+播放控制+言溪题库) // @namespace zhihuishu-full-control // @version 7.0.0 // @description 智慧树全自动:手动搜课+播放/暂停控制+言溪题库自动答题+自动切课+最小化恢复+防检测 // @author 全功能适配 // @match *://*.zhihuishu.com/* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_xmlhttpRequest // @connect tk.enncy.cn // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // ===================== 基础配置区(面板可修改,无需改代码) ===================== const DEFAULT_CONFIG = { watchTime: 25, // 每门课观看时长(分钟) playbackRate: 1.25, // 播放倍速(最高1.5,防检测) autoSwitch: true, // 看完自动切换下一门 autoPlay: true, // 自动播放视频 autoClosePopup: true, // 自动关闭普通弹窗 autoAnswer: true, // 自动答题(弹题) reviewCompleted: false, // 复看已100%完成的课程(默认关闭) useOnlineBankFirst: true, // 优先使用在线言溪题库 }; // ===================== 言溪题库配置(你提供的接口) ===================== const YANXI_BANK_CONFIG = { name: "言溪题库", homepage: "https://tk.enncy.cn/", url: "https://tk.enncy.cn/query", method: "GET", token: "0abc866e094c4714936e88a84ae3cb93", // 你的题库token contentType: "json" }; // 存储键名 const CONFIG_KEY = 'zhs_full_config'; const STATE_KEY = 'zhs_full_state'; const LOCAL_BANK_KEY = 'zhs_local_question_bank'; // 本地题库存储key // 全局状态 let state = { currentCourseIndex: 0, currentTime: 0, isRunning: false, totalCourses: 0, }; let config = { ...DEFAULT_CONFIG }; let localQuestionBank = {}; // 本地题库对象 let timer = null; let popupTimer = null; let answerTimer = null; let panel = null; // ===================== 初始化 ===================== function init() { loadConfig(); loadState(); loadLocalBank(); createPanel(); bindEvents(); startPopupMonitor(); startAnswerMonitor(); // 启动弹题自动答题监控 startHumanSimulate(); // 延迟等待页面渲染完成 setTimeout(() => { autoDetectPage(); }, 1500); } // ===================== 配置/状态/题库 加载&保存 ===================== function loadConfig() { try { const saved = GM_getValue(CONFIG_KEY); if (saved) config = { ...DEFAULT_CONFIG, ...saved }; } catch (e) { console.error('加载配置失败', e); } } function saveConfig() { try { GM_setValue(CONFIG_KEY, config); } catch (e) { console.error('保存配置失败', e); } } function loadState() { try { const saved = GM_getValue(STATE_KEY); if (saved) state = { ...state, ...saved }; } catch (e) { console.error('加载状态失败', e); } } function saveState() { try { GM_setValue(STATE_KEY, state); } catch (e) { console.error('保存状态失败', e); } } // 加载本地题库 function loadLocalBank() { try { const saved = GM_getValue(LOCAL_BANK_KEY); if (saved) { localQuestionBank = typeof saved === 'string' ? JSON.parse(saved) : saved; } } catch (e) { console.error('加载本地题库失败', e); localQuestionBank = {}; } } // 保存本地题库 function saveLocalBank(newBank) { try { localQuestionBank = newBank; GM_setValue(LOCAL_BANK_KEY, JSON.stringify(newBank)); addLog('本地题库保存成功,共' + Object.keys(newBank).length + '道题', 'success'); return true; } catch (e) { addLog('本地题库保存失败:' + e.message, 'error'); return false; } } // ===================== 言溪在线题库搜题核心函数 ===================== /** * 调用言溪题库在线搜题 * @param {string} title 题干 * @param {Array} options 选项文本数组 * @param {string} type 题型:single=单选,multi=多选 * @returns {Promise} 答案数组 */ async function searchYanxiBank(title, options, type) { if (!config.useOnlineBankFirst) return []; return new Promise((resolve) => { // 拼接GET请求参数 const queryParams = new URLSearchParams({ token: YANXI_BANK_CONFIG.token, title: title.trim(), options: options.join('\n'), type: type }); const requestUrl = `${YANXI_BANK_CONFIG.url}?${queryParams.toString()}`; GM_xmlhttpRequest({ method: YANXI_BANK_CONFIG.method, url: requestUrl, timeout: 5000, // 5秒超时,避免卡住 onload: (res) => { try { const result = JSON.parse(res.responseText); // 接口返回成功 if (result.code === 0 && result.data?.answer) { let answer = result.data.answer; // 统一处理成数组格式 answer = Array.isArray(answer) ? answer : [answer.toString().trim()]; addLog(`【言溪题库】搜题成功,答案:${answer.join('、')}`, 'success'); resolve(answer); } else { addLog(`【言溪题库】搜题失败:${result.message || '无结果'}`, 'error'); resolve([]); } } catch (e) { addLog(`【言溪题库】解析返回结果失败:${e.message}`, 'error'); resolve([]); } }, onerror: (err) => { addLog(`【言溪题库】请求失败:${err.message || '网络错误'}`, 'error'); resolve([]); }, ontimeout: () => { addLog('【言溪题库】请求超时', 'error'); resolve([]); } }); }); } // ===================== 【新增核心】手动搜索课程函数 ===================== /** * 根据课程名称模糊匹配页面课程 * @param {string} courseName 输入的课程名称/关键词 * @returns {Element|null} 匹配到的课程卡片元素 */ function searchCourseByName(courseName) { if (!courseName || courseName.trim() === '') { addLog('请输入课程名称/关键词', 'error'); return null; } const keyword = courseName.trim().replace(/\s+/g, '').toLowerCase(); // 课程卡片选择器(兼容智慧树所有课程列表) const courseSelectors = [ '.course-list .course-item', '.shared-course-wrap .course-card', '.tab-content .course-item', '[class*="course"] [class*="item"]', ]; let matchCourse = null; let maxMatchRate = 0; // 遍历所有课程卡片,模糊匹配 courseSelectors.forEach(sel => { const cards = document.querySelectorAll(sel); cards.forEach(card => { const titleEl = card.querySelector('h3, .course-title, .course-name, .title'); if (!titleEl) return; const title = titleEl.textContent.trim().replace(/\s+/g, '').toLowerCase(); // 匹配度计算:包含关键词即匹配 if (title.includes(keyword)) { const matchRate = keyword.length / title.length; // 取匹配度最高的课程 if (matchRate > maxMatchRate) { maxMatchRate = matchRate; matchCourse = card; } } }); }); if (matchCourse) { const courseTitle = matchCourse.querySelector('h3, .course-title, .course-name')?.textContent?.trim(); addLog(`匹配到课程:${courseTitle}`, 'success'); return matchCourse; } else { addLog(`未找到包含「${courseName}」的课程`, 'error'); return null; } } // ===================== 【新增核心】手动播放/暂停控制函数 ===================== // 手动播放视频 function manualPlayVideo() { const video = document.querySelector('video'); const playBtn = document.querySelector('.vjs-big-play-button, .vjs-play-control.vjs-paused'); if (video && video.paused) { video.play().then(() => { addLog('视频已手动播放', 'success'); }).catch(() => { // 浏览器限制自动播放,尝试点击播放按钮 if (playBtn) playBtn.click(); addLog('已点击播放按钮', 'success'); }); } else if (playBtn) { playBtn.click(); addLog('已点击播放按钮', 'success'); } else { addLog('未找到可播放的视频', 'error'); } } // 手动暂停视频 function manualPauseVideo() { const video = document.querySelector('video'); const pauseBtn = document.querySelector('.vjs-play-control.vjs-playing'); if (video && !video.paused) { video.pause(); addLog('视频已手动暂停', 'success'); } else if (pauseBtn) { pauseBtn.click(); addLog('已点击暂停按钮', 'success'); } else { addLog('未找到正在播放的视频', 'error'); } } // ===================== 控制面板创建(新增搜课+播放控制区域) ===================== function createPanel() { const existing = document.getElementById('zhs-auto-panel'); if (existing) existing.remove(); panel = document.createElement('div'); panel.id = 'zhs-auto-panel'; panel.innerHTML = `
智慧树全功能助手
输入课程名称,自动匹配并进入课程
状态${state.isRunning ? '运行中' : '已停止'}
当前课程第${state.currentCourseIndex+1}/${state.totalCourses}门
计时${formatTime(state.currentTime)} / ${config.watchTime}分钟
单课时长(分钟)
播放倍速
优先在线搜题
自动播放
自动切课
自动关弹窗
自动答题
复看已完成课程
📚 本地兜底题库(点击展开)
脚本加载完成,已集成手动搜课+播放控制
`; document.body.appendChild(panel); // 初始化本地题库文本框 document.getElementById('zhs-bank-text').value = JSON.stringify(localQuestionBank, null, 2); addLog('脚本加载完成,已加载' + Object.keys(localQuestionBank).length + '道本地题库'); } // ===================== 最小化/恢复切换核心函数 ===================== function toggleMinimize() { panel.classList.toggle('minimized'); const minBtn = document.getElementById('zhs-min'); minBtn.textContent = panel.classList.contains('minimized') ? '+' : '-'; } // ===================== 事件绑定(新增搜课+播放控制事件) ===================== function bindEvents() { // 核心:最小化后点击整个面板恢复 panel.addEventListener('click', (e) => { if (e.target === panel && panel.classList.contains('minimized')) { toggleMinimize(); } }); // 右上角最小化按钮切换 document.getElementById('zhs-min').onclick = (e) => { e.stopPropagation(); toggleMinimize(); }; // ===================== 新增:搜索课程事件 ===================== document.getElementById('zhs-search-btn').onclick = (e) => { e.stopPropagation(); const input = document.getElementById('zhs-course-input'); const courseName = input.value; const targetCourse = searchCourseByName(courseName); if (targetCourse) { // 点击进入课程 targetCourse.click(); // 清空输入框 input.value = ''; } }; // 回车搜索课程 document.getElementById('zhs-course-input').onkeydown = (e) => { if (e.key === 'Enter') { e.stopPropagation(); document.getElementById('zhs-search-btn').click(); } }; // ===================== 新增:手动播放/暂停事件 ===================== document.getElementById('zhs-manual-play').onclick = (e) => { e.stopPropagation(); manualPlayVideo(); }; document.getElementById('zhs-manual-pause').onclick = (e) => { e.stopPropagation(); manualPauseVideo(); }; // 题库折叠 document.getElementById('zhs-bank-toggle').onclick = (e) => { e.stopPropagation(); const content = document.getElementById('zhs-bank-content'); content.classList.toggle('open'); document.querySelector('#zhs-bank-toggle span:last-child').textContent = content.classList.contains('open') ? '▲' : '▼'; }; // 保存本地题库 document.getElementById('zhs-bank-save').onclick = (e) => { e.stopPropagation(); try { const text = document.getElementById('zhs-bank-text').value; const newBank = JSON.parse(text); saveLocalBank(newBank); } catch (e) { addLog('题库格式错误,请检查JSON格式', 'error'); } }; // 自动刷课开始/暂停 document.getElementById('zhs-toggle').onclick = (e) => { e.stopPropagation(); toggleWatch(); }; // 重置进度 document.getElementById('zhs-reset').onclick = (e) => { e.stopPropagation(); if (confirm('确定重置所有进度和状态吗?')) resetWatch(); }; // 所有toggle开关通用绑定 const toggleMap = { 'zhs-use-online': 'useOnlineBankFirst', 'zhs-auto-play': 'autoPlay', 'zhs-auto-switch': 'autoSwitch', 'zhs-auto-popup': 'autoClosePopup', 'zhs-auto-answer': 'autoAnswer', 'zhs-review': 'reviewCompleted' }; Object.keys(toggleMap).forEach(id => { const key = toggleMap[id]; document.getElementById(id).onclick = (e) => { e.stopPropagation(); config[key] = !config[key]; e.target.classList.toggle('active', config[key]); saveConfig(); addLog(`${key === 'reviewCompleted' ? '复看已完成课程' : key}${config[key] ? '开启' : '关闭'}`); // 复看开关变化后重新识别课程 if (key === 'reviewCompleted') { setTimeout(() => { autoDetectPage(); }, 500); } }; }); // 阻止所有内部元素的点击冒泡,避免误触发最小化 panel.querySelectorAll('.zhs-content, .zhs-header *').forEach(el => { el.addEventListener('click', (e) => e.stopPropagation()); }); } // ===================== 页面识别&课程处理 ===================== function autoDetectPage() { const url = window.location.href; // 课程列表页(学堂页) if (url.includes('onlineweb.zhihuishu.com/onlinestuh')) { addLog('检测到课程列表页(学堂页)', 'success'); expandAllCourses(); setTimeout(() => { const courseList = getAllCourseCards(); state.totalCourses = courseList.length; saveState(); updateUI(); if (state.isRunning) { setTimeout(() => { openTargetCourse(); }, 1500 + Math.random() * 1000); } }, 1000); } // 视频播放页 else if (url.includes('studyvideoh5') || url.includes('wisdom-mooc')) { addLog('检测到视频播放页', 'success'); startVideoDetect(); if (state.isRunning) { startTimer(); } } } // 展开全部课程 function expandAllCourses() { const viewMoreBtn = document.querySelector('.view-more, a[href*="查看更多"], .course-more'); if (viewMoreBtn && viewMoreBtn.offsetParent !== null) { viewMoreBtn.click(); addLog('已点击「查看更多」,展开全部课程', 'success'); } } // 获取所有课程卡片(适配复看开关) function getAllCourseCards() { const selectors = [ '.course-list .course-item', '.shared-course-wrap .course-card', '.tab-content .course-item', '[class*="course"] [class*="item"]', ]; let allCards = []; selectors.forEach(sel => { const cards = document.querySelectorAll(sel); cards.forEach(card => { const title = card.querySelector('h3, .course-title, .course-name, .title')?.textContent?.trim(); const isVisible = card.offsetParent !== null; const progressText = card.querySelector('.progress, .progress-num')?.textContent?.trim() || ''; const isCompleted = progressText.includes('100.0%'); if (title && isVisible) { // 过滤已完成课程(复看关闭时) if (!config.reviewCompleted && isCompleted) return; if (!allCards.includes(card)) { allCards.push(card); } } }); }); addLog(`找到${allCards.length}门有效课程`); return allCards; } // 打开目标课程 function openTargetCourse() { const courseList = getAllCourseCards(); if (state.currentCourseIndex >= courseList.length) { addLog('全部课程已完成', 'success'); pauseWatch(); alert('✅ 全部课程已学习完成!'); return; } const targetCard = courseList[state.currentCourseIndex]; if (!targetCard) { addLog('未找到目标课程', 'error'); return; } targetCard.click(); const courseTitle = targetCard.querySelector('h3, .course-title, .course-name')?.textContent?.trim() || `第${state.currentCourseIndex+1}门`; addLog(`已打开课程:${courseTitle}`, 'success'); } // 视频检测&设置 function startVideoDetect() { let attempts = 0; const detectTimer = setInterval(() => { const video = document.querySelector('video'); if (video) { clearInterval(detectTimer); setupVideo(video); addLog('已找到视频,自动播放设置完成', 'success'); } else if (attempts > 30) { clearInterval(detectTimer); addLog('未找到视频元素,请手动刷新页面', 'error'); } attempts++; }, 500); } function setupVideo(video) { if (!video) return; video.playbackRate = config.playbackRate; if (config.autoPlay) { video.play().catch(() => { addLog('自动播放失败,请手动点击播放按钮', 'error'); }); } video.addEventListener('ended', () => { addLog('当前小节播放结束,自动播放下一节', 'success'); setTimeout(() => { const nextSection = document.querySelector('.next-btn, .nav-next, .catalog-item.active + .catalog-item'); if (nextSection) nextSection.click(); }, 1500); }); } function applyPlaybackRate() { document.querySelectorAll('video').forEach(v => { v.playbackRate = config.playbackRate; }); } // ===================== 核心:自动答题功能(集成在线+本地题库) ===================== function startAnswerMonitor() { if (answerTimer) clearInterval(answerTimer); // 每1秒检测一次弹题弹窗 answerTimer = setInterval(() => { if (!config.autoAnswer) return; // 智慧树弹题弹窗通用选择器 const popupSelectors = [ '.question-modal', '.test-popup', '.dialog-box:has(.question-stem)', '.el-dialog:has(.question-title)', '.popupsbox:has(.option-item)' ]; let answerPopup = null; for (const sel of popupSelectors) { const el = document.querySelector(sel); if (el && el.offsetParent !== null) { answerPopup = el; break; } } // 找到弹题弹窗,开始处理 if (answerPopup) { handleAnswerPopup(answerPopup); } }, 1000); } // 处理弹题弹窗(异步,支持在线搜题) async function handleAnswerPopup(popup) { // 防止重复处理 if (popup.dataset.processed === 'true') return; popup.dataset.processed = 'true'; // 1. 提取题干 const stemSelectors = ['.question-stem', '.question-title', '.stem', '.title h3']; let stem = ''; for (const sel of stemSelectors) { const el = popup.querySelector(sel); if (el) { stem = el.textContent.trim().replace(/\s+/g, ''); break; } } if (!stem) { addLog('未识别到题干,跳过答题', 'error'); popup.dataset.processed = 'false'; return; } addLog(`识别到题目:${stem}`); // 2. 提取所有选项 const optionSelectors = ['.option-item', '.answer-option', '.option', '.el-radio', '.el-checkbox']; const options = Array.from(popup.querySelectorAll(optionSelectors)).filter(el => el.offsetParent !== null); if (options.length === 0) { addLog('未识别到选项,跳过答题', 'error'); popup.dataset.processed = 'false'; return; } // 3. 解析选项文本和元素 const optionList = options.map(el => { const textEl = el.querySelector('.option-text, .label, span') || el; return { el: el, text: textEl.textContent.trim().replace(/\s+/g, '') }; }); const optionTextList = optionList.map(opt => opt.text); // 4. 判断题型 const isMulti = popup.querySelector('.el-checkbox') !== null; const questionType = isMulti ? 'multi' : 'single'; addLog(`题型:${isMulti ? '多选题' : '单选题'}`); // 5. 模拟真人思考延迟 await new Promise(r => setTimeout(r, 1000 + Math.random() * 1000)); // 6. 优先级1:言溪在线题库搜题 let correctAnswers = []; if (config.useOnlineBankFirst) { correctAnswers = await searchYanxiBank(stem, optionTextList, questionType); } // 7. 优先级2:在线无结果,使用本地题库兜底 if (correctAnswers.length === 0) { addLog('在线搜题无结果,使用本地题库匹配', 'info'); for (const key in localQuestionBank) { const cleanKey = key.replace(/\s+/g, ''); if (stem.includes(cleanKey) || cleanKey.includes(stem)) { correctAnswers = localQuestionBank[key]; addLog(`本地题库匹配成功,答案:${correctAnswers.join('、')}`, 'success'); break; } } } // 8. 优先级3:都无结果,随机选择 let selected = []; if (correctAnswers.length > 0) { // 匹配答案并点击 correctAnswers.forEach(answer => { const cleanAnswer = answer.replace(/\s+/g, ''); const targetOption = optionList.find(opt => opt.text.includes(cleanAnswer) || cleanAnswer.includes(opt.text)); if (targetOption) { targetOption.el.click(); selected.push(targetOption.text); } }); } else { addLog('无匹配答案,随机选择', 'info'); // 随机选择:单选1个,多选随机1~选项总数个 let randomCount = isMulti ? Math.floor(Math.random() * optionList.length) + 1 : 1; const randomOptions = [...optionList].sort(() => 0.5 - Math.random()).slice(0, randomCount); randomOptions.forEach(opt => { opt.el.click(); selected.push(opt.text); }); } addLog(`已选择选项:${selected.join('、')}`); // 9. 延迟点击提交按钮 await new Promise(r => setTimeout(r, 800 + Math.random() * 500)); const submitBtns = popup.querySelectorAll('.submit-btn, .confirm-btn, .sure-btn, .el-button--primary, button:has-text("确定"), button:has-text("提交")'); submitBtns.forEach(btn => { if (btn.offsetParent !== null) btn.click(); }); addLog('已提交答案,关闭弹窗', 'success'); // 处理完成,解锁弹窗 setTimeout(() => { popup.dataset.processed = 'false'; }, 2000); } // ===================== 切课&计时核心逻辑 ===================== function startTimer() { if (timer) clearInterval(timer); timer = setInterval(() => { if (!state.isRunning) return; state.currentTime++; saveState(); updateUI(); if (state.currentTime >= config.watchTime * 60) { clearInterval(timer); addLog(`第${state.currentCourseIndex+1}门课时长已满`, 'success'); const courseList = getAllCourseCards(); if (state.currentCourseIndex >= courseList.length - 1) { pauseWatch(); alert('✅ 全部课程已学习完成!'); addLog('全部课程学习完成', 'success'); return; } if (config.autoSwitch) { setTimeout(() => { backToSchool(); }, 1500 + Math.random() * 1000); } else { pauseWatch(); } } }, 1000); } function backToSchool() { const backBtn = document.querySelector('a:has-text("返回学堂"), .back-btn, a[href*="onlinestuh5"], .header-left a'); if (backBtn && backBtn.offsetParent !== null) { backBtn.click(); addLog('已点击「返回学堂」,回到课程列表', 'success'); state.currentCourseIndex++; state.currentTime = 0; saveState(); } else { addLog('未找到「返回学堂」按钮,手动跳转', 'error'); window.location.href = 'https://onlineweb.zhihuishu.com/onlinestuh5'; state.currentCourseIndex++; state.currentTime = 0; saveState(); } } // ===================== 普通弹窗处理 ===================== function startPopupMonitor() { if (popupTimer) clearInterval(popupTimer); popupTimer = setInterval(() => { if (!config.autoClosePopup) return; // 挂机验证弹窗 const continueBtns = document.querySelectorAll('.dialog-footer .btn, .vjs-modal-dialog .vjs-close-button, .continue-btn, .confirm-btn, button[title="继续播放"]'); continueBtns.forEach(btn => { if (btn.offsetParent !== null) { btn.click(); addLog('已自动关闭挂机验证弹窗', 'success'); } }); // 普通关闭弹窗 const closeBtns = document.querySelectorAll('.close, .btn-close, .modal-close, .dialog-close, [class*="close"]'); closeBtns.forEach(btn => { if (btn.offsetParent !== null && !btn.closest('.video-js')) { btn.click(); addLog('已自动关闭弹窗', 'success'); } }); window.onbeforeunload = null; }, 2000); } // ===================== 防检测真人模拟 ===================== function startHumanSimulate() { setInterval(() => { if (!state.isRunning) return; document.dispatchEvent(new MouseEvent('mousemove', { clientX: Math.random() * 1000 + 200, clientY: Math.random() * 600 + 100 })); window.scrollBy(0, Math.random() > 0.5 ? 10 : -10); }, 30000 + Math.random() * 20000); } // ===================== 控制函数 ===================== function toggleWatch() { state.isRunning ? pauseWatch() : startWatch(); } function startWatch() { if (state.isRunning) return; state.isRunning = true; saveState(); updateUI(); addLog('开始自动刷课', 'success'); autoDetectPage(); } function pauseWatch() { state.isRunning = false; saveState(); updateUI(); if (timer) { clearInterval(timer); timer = null; } addLog('已暂停自动刷课'); } function resetWatch() { pauseWatch(); state = { currentCourseIndex: 0, currentTime: 0, isRunning: false, totalCourses: 0 }; saveState(); updateUI(); addLog('已重置所有进度和状态'); } // ===================== 工具函数 ===================== function formatTime(seconds) { const m = Math.floor(seconds / 60).toString().padStart(2, '0'); const s = (seconds % 60).toString().padStart(2, '0'); return `${m}:${s}`; } function addLog(msg, type = 'info') { const logBox = document.getElementById('zhs-log'); if (!logBox) return; const entry = document.createElement('div'); entry.className = `zhs-log-entry ${type}`; entry.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`; logBox.appendChild(entry); logBox.scrollTop = logBox.scrollHeight; while (logBox.children.length > 50) logBox.removeChild(logBox.firstChild); } function updateUI() { const statusEl = document.getElementById('zhs-status'); const courseEl = document.getElementById('zhs-course'); const timeEl = document.getElementById('zhs-time'); const fillEl = document.getElementById('zhs-fill'); const toggleEl = document.getElementById('zhs-toggle'); if (statusEl) statusEl.textContent = state.isRunning ? '运行中' : '已停止'; if (courseEl) courseEl.textContent = `第${state.currentCourseIndex+1}/${state.totalCourses}门`; if (timeEl) timeEl.textContent = `${formatTime(state.currentTime)} / ${config.watchTime}分钟`; if (fillEl) fillEl.style.width = `${Math.min((state.currentTime/(config.watchTime*60))*100, 100)}%`; if (toggleEl) toggleEl.innerHTML = state.isRunning ? '⏸ 暂停自动刷课' : '▶ 开始自动刷课'; } // 油猴菜单 GM_registerMenuCommand('开始/暂停自动刷课', toggleWatch); GM_registerMenuCommand('播放视频', manualPlayVideo); GM_registerMenuCommand('暂停视频', manualPauseVideo); GM_registerMenuCommand('重置进度', resetWatch); // 启动脚本 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();