// ==UserScript== // @name WUT网上党校 全能助手 // @namespace https://gitee.com/fieldlu/party-member-treasury // @version 1.1.1 // @description 全自动学习+云端题库:视频断点续播/智能跳课、云端查答案/自动答题/贡献答案/全网采集 // @author FieldLu // @license MIT // @match *://wsdx.whut.edu.cn/* // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @grant GM_addStyle // @run-at document-idle // @connect gitee.com // @connect giteeusercontent.com // @connect whut-qbank-worker.tianye0126.workers.dev // @icon data:image/jpeg;base64,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abRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMaBtib9559e8wrPZXegsM+5FUoZe2XAQdsdPmTxptExptExptExptExptExptExptExptExptExptExptExptExpsEE3k+9uxrmWsQh32RqrJ+67kxptExptExptExptExptExptExptExptExptExptExptExptExptExkLWOdEXJxGdqEdsTY1+XJL7aMfMnjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTXInwLLBixYMqEppoIoXak4gESY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY04JtOXgMtlTwyFcmcyjLomNNomNNomNNomNNomNNomNNomNNomNNomNNomNNomNNomNNod0z2gybKdT6PwqFCpYDIIkcqcOOO0GTxptExptExptExptExptExptExptExptExptExptExpqzdqj+3bGdgqlzjdRS0S8+VyGfTcc1KYr7iY4xp20Y+ZPGm0TGm0TGm0TGm0TGm0TGm0TGm0TGm0TGm0So0DCMP+MUX5YY8gpG5n9y77bv1mRbcQdtn5DRl9tD/RJJDLvjPK9Bf4V5jIabRMabRMabRMabRMabRMabRMabRMabRMabRMabRMaVQ9VrmvB8yeM/odtQsjqn5OYcwk7tSo47Ff+l1utsAx8yeNNomNNomNNomNNomNNomNNomNNomNNomNNomHvIHdwH8Y+ZPGeUtcOq9/Bo011twrzgRAyd2kwl9djwEGTxptExptExptExptExptExptExptExptExptEw95A7uA/jHzJ4zLajg9c5Za9OBRXYu7tog14VlcZOcPLXp8yeNNomNNomNNomNNomNNomNNomNNomNKoeq1zXg+ZPGms3Hm/SDR84eWgqqjm9gCG72W7nDfvy16fMnjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTaHG0wVY7ntGPmTrjZEHhj/7DgydhgX9QnbLCz8t3+cPLXp8yeNNomNNomNNomNNomNNomNNomNNolSlLqwEf8abRMZltRzxu6w4MnjTGzpQhS0FGrEigW/2HBk8abRMabRMabRMabRMabRMabRMabRMabN5WHP2joxptExmXZFlh2v20Y+ZPGi3ZoN8ybRh+STnDy16fMnjTaJjTaJjTaJjTaJjTaJjTaJjTVsSoRSkktExptEQ5PMAdpP+qeNNomNMPSlsToMlpvZ85MptExptExptExptExptExptExptExptExptDjaYKsdz2jHzJ40u1n/NF4eUQ/T5k8aV4i/jPrgyEXu0Hzh5a9PmTxptExptExptExptExptExptExlrYJ9ULwuDJ402iYokHcW73E2JtExptEAkfPmvtlY3RjVuDJ402iY02iY02iY02iY02iY02iY02iY02NmCgMAXPaJjTaJjTZ9Nw89vChq4Y+ZPGmmI6+y15oVsND402iY02iY02iY02iY02iY02iY02iY02iYzyvQXWvg6fWWvT5k8aa8iiRFKZQIZk8abQOE0ux/YZVUD1pFINox8yeNNomNNomNNomNNomNNomNNomNNolpyS13H9o1nOHexKnJWfF9tGNwWv+hIVIjgvtoxu4f2pvMnctO5TxptExptExptExptExptExptExptExptExnlegulG/jYO9f+aOFqSZmx6zKLY2jHzG1FQxl6SevDgydsIx3BkvoCH6fMnjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTXyuiucBfSf8wqQrNk9DGLCvpo91UeNNohosGGxeTLHHaDGLVODy03gHOHlr0+ZPGm0TGm0TGm0TGm0TGm0TGm0TGm0P/M36Y5LaEjV0bC1YaGqj3BS7vr7BtGPbcKmQiOJhA2jGtcI5FxPGfkL4vtox8yeNNomNNomNNomNNomNNomNNomNNomM6Es/Chqe6vLA7WDytzXEdQUaS05w8tNXu4t3uNMKmzz8ersc4eBBntPmTxptExptExptExptExptExptExptExptExptExpswtdoojMElmTxps+qTLiXEdls7ZhmNWp/YYsTwkrtox8yeNNomNNomNNomNNomNNomNNomNNomNNomNNomLbc82WjIjwfp8yYycRNsLhpau9NWN6GTxW2vwwqeNNomNNomNNomNNomNNomNNomNNomNNomNNomNNomNMo02BXckU1s2iY0w5QqIpXIAJQDGKpFqgybLM2R7hExptExptExptExptExptExptExptExptExptExptExptAf4LMHughIdtGPY1MTmGJC0C0AaUYcGO97JOaX6fMnjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTaJejT/MRlKjcsODJ3G68xMr/LNosbnDy1Ps43DZa9PmTxptExptExptExptExptExptExptErjSWFSuGPmTxptExpI7nAxWmsImTxptZSMfLCMNichEmNNomNNomNNomNNomNNomNNomNNomNNoeDWhYdrS1uFhe9xrRMabRMabQH+CzEonma22jHzJ402Ij9NTaJjTaJjTaJjTaJjTaJjTaJjTaJjTaJjTWa8uihazN/6QR36U5MabRMabRL1M7RwYVfMAF9tGPmTDFuoOvsuHlr0+ZPGm0TGm0TGm0TGm0TGm0TGm0TGZbUgXJtd8xM3QW+uUG5UBtGPmTxptAf4LMHufmo8abRMaZlt2zQUMgiTGm0TGm0TGm0TGm0TGm0TGm0TGm0TGmwc9D2Wxx37DYWOXt6HCdsFlr0+ZPGmzC12iiMwSWZPGm0S1EKgZUiTGm0TGm0TGm0TGm0TGm0TGm0TGm0TGm0TFgEyG8UiqbO/QzVtbDWT5OsCDJ402iYttzztK/dPbRj5k4c1jlbzfl6fMnjTaJjTaJjTaJjTaJjTaJjTaJjTaJjS4iXwk8BXLXp9NGvpP3mUTddAUQKDJ4yyd//ob4w5saRfbRj5UciokCZ+JDnbRj5k8abRMabRMabRMabRMabRMabRMabRLB1LaJ6gNox8yse88kBcKyY+Vrlnxj6XRmrqBxPTbj/AWB54fGTbx/v4HGm0TGmz0g9gJlKOXZPGm0TGm0TGm0TGm0TGm0TGm0TGm0TGmznfgV/+5+k2clLO5stExptExptExptExptExpsBpJR+Z+UCztox8yeNNomNNomNNomNNomNNomNNomM2nXTw1LjTaJjTaJjTaJjTaJjTaJjTZ9UVFx3CcTDDgyeNNomNNomNNomNNomNNomNNomNNlADk2r3uTmUXKOWGtIAmgF9tGPmTxptExptExps3lVYdIRVg8tenzJ402iY02iY02iY02iY02iY02iGfTZ20SRbzY3uxcFn7v1iY02iY02iY01nHW3ej+irhZelzm8U5dG5vrh5a9PmTxptExptExptExptExptExptExWUFNl4zIvHOVU4i3juyE6riARJjTaJjTZzLA/v2CR2cKkY9frQAoaNLWwT6oXhcGTxptExptExptExptExptExptExptExmtYhCoqXpw0fqYObSt4DSGMd8Hh1C7QZPGm0PISCd//GzP37lrK1/4xGYJLIMSoRSkktExptExptExptExptExptExptExptExps6eMfQsQVuX7VKwRZXkcaa9jibHAtIuUMzB/iWRKNoxiUzZBFeBbG5//X8Fv+w39brTOwq+XVsFWO57Rj5k8abRMabRMabRMabRMabRMabRMabRMakatibp+jXpDO9FwZPGnBorZGesDiae3CIwuBjeF9u8jekip4IbErKRj5k8W4B3xbE5w8tenzJ402iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY02iY01YAAD+//7254AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/GoRm3O51fCnRquTCDpvFU1QJElvdla18wORhLiHZLmwtDelQ5Rk3piR/ttYXPHhpYzk3DZAUfevJ3uWlXbQcXE2pfusUQPmLkB7q569YRVpv5tqVyySXOCWisPR+ilEAYXRe0tOSnob1VZ5qmv1I++68hhEfOBIn2N1DgC8L4XSyv9QRstgt7E1PE2n7bffEfGaNKjD9cYWo3hdD8yE93pjyAmrlIecRASYWa50IKMUXQ4lK8P+S2L1bSMM1WK5kKZOIphqxZU7YHlw+TdbZyBGT9WQ2PvPfPuwrbXaVYpB9C8Yjzile9Z+p0Mh4UJYhXcxWfNUyvCLFt/cgyJOu+4kd0vbDekELXcwOXgWqUlk9uMVMQnEOet2DEjEL2T9MbbOcaDjNHAJwfwZQGlA7csXjXivK3Eo0hsKXsPaFH4gTloYE0L1VREoUfc15M0FIlUqL64D4OapuK3dZZuYivLv0ASInn/zDGfU++Oka+3dI7jM4rpGEAk6uhXje39EGeqnkQI+ri9rh3HPqtJ76RmY8G+br7OhoDnrIYgeza3zNS7eG3hOv4jKpY5kGF5YxgJ9h/elBARR11ml1Aixch2LFMEq3FMmetUUIAT6x+BLji3AAAAA2tuG8ZDd9fwMByVpzzVoPe+LV34ZFm6w3LzKqN1Xs0EoFCREK/Wuta/XSx2v7usMGePp2kSLS96v1aM9ADHmj8fW5KgQlY4rSPQwpP95yOXnVMGiw/svv1HZSl0aD/UoVo6JgJduPgaqh/imN1VI8jWP9SrJk8+mFujqwQ6FmMgmsRp6dVg+3hLL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 // ==/UserScript== (function () { 'use strict'; // ==================== 云端题库配置 ==================== const CLOUD = { rawBase: 'https://gitee.com/fieldlu/party-member-treasury/raw/master/qbank', apiBase: 'https://gitee.com/api/v5/repos/fieldlu/party-member-treasury/contents', workerBase: 'https://whut-qbank-worker.tianye0126.workers.dev', autoAnswerEnabled: true }; let cloudIndex = null; let autoAnswerTimer = null; const SCRIPT_VERSION = typeof GM_info !== 'undefined' ? GM_info.script.version : '1.0.0'; const CFG = { checkInterval: 2000, coursePageTimeout: 900 }; const hacked = new WeakSet(); let stats = { completed: 0, total: 0, startTime: 0, scriptDone: 0 }; let timers = []; let stopped = false; let navigating = false; let courseList = []; let currentCourse = null; let xmId = ''; let videoDuration = 0; let finishedDuration = 0; let lastVidUpdate = 0; let currentVidTime = 0; let courseRecoveryTimer = null; let watchdogProgressTime = Date.now(); let watchdogLastCurrentTime = -1; const WATCHDOG_STUCK_LIMIT = 180000; // 3分钟无进展则强刷 // ==================== 持久化存储(断点续播 + 后台重载恢复) ==================== function saveState() { try { GM_setValue('whut_xmId', xmId); GM_setValue('whut_stopped', stopped); GM_setValue('whut_completed', stats.completed); GM_setValue('whut_total', stats.total); GM_setValue('whut_scriptDone', stats.scriptDone); } catch(e) {} } // 重载前完整保存(含 courseList、进度、当前课程) function saveStateForReload() { try { saveState(); if (courseList.length > 0) { sessionStorage.setItem('whut_courseList', JSON.stringify(courseList)); } if (currentCourse) { sessionStorage.setItem('whut_currentCourse', JSON.stringify(currentCourse)); } if (finishedDuration > 0) { sessionStorage.setItem('whut_finishedDuration', finishedDuration); } // 保存完整课程状态用于跨重载渲染 const fullInfo = { total: stats.total, completed: stats.completed, scriptDone: stats.scriptDone }; sessionStorage.setItem('whut_courseInfo', JSON.stringify(fullInfo)); sessionStorage.setItem('whut_reload_reason', 'auto_recovery'); } catch(e) {} } function renderCourseList() { if (!listEl) return; let html = ''; const full = sessionStorage.getItem('whut_fullList'); if (full) { try { JSON.parse(full).forEach(c => { const mode = c.studyMode || ''; const prog = c.progress != null ? parseFloat(c.progress) : (c.finishedDuration >= c.duration ? 1 : 0); const cls = prog >= 1 ? 'done' : (prog > 0 ? 'half' : (mode !== 'WLXX' && mode !== '' ? 'skip' : 'todo')); html += '' + (prog >= 1 ? '✔' : (prog > 0 ? '◐' : '○')) + ' ' + (c.courseName || c.name || '') + ' ' + Math.round(prog * 100) + '%\n'; }); } catch(e) {} } if (!html && courseList.length > 0) { courseList.forEach(c => { html += '○ ' + (c.courseName || c.name) + ' 0%\n'; }); } if (html) listEl.innerHTML = html; } function loadState() { try { xmId = GM_getValue('whut_xmId', ''); const wasStopped = GM_getValue('whut_stopped', true); stats.completed = GM_getValue('whut_completed', 0) | 0; stats.total = GM_getValue('whut_total', 0) | 0; stats.scriptDone = GM_getValue('whut_scriptDone', 0) | 0; // 尝试恢复课程列表 const saved = sessionStorage.getItem('whut_courseList'); if (saved) { try { courseList = JSON.parse(saved); } catch(e) {} } const savedCourse = sessionStorage.getItem('whut_currentCourse'); if (savedCourse) { try { currentCourse = JSON.parse(savedCourse); } catch(e) {} } const savedFd = sessionStorage.getItem('whut_finishedDuration'); if (savedFd) finishedDuration = parseFloat(savedFd) || 0; // 检查是否从重载中恢复 const reloadReason = sessionStorage.getItem('whut_reload_reason'); if (reloadReason) { sessionStorage.removeItem('whut_reload_reason'); // 清理一次性恢复标记 sessionStorage.removeItem('whut_finishedDuration'); return 'reload_recovery'; } if (xmId && wasStopped === false) { stopped = false; return 'session_restore'; } } catch(e) {} return false; } const $ = (s, p) => (p || document).querySelector(s); const $$ = (s, p) => [...(p || document).querySelectorAll(s)]; function isDetailPage() { return location.href.includes('/myTrain/detail'); } function isCoursePage() { return location.href.includes('/myTrain/course'); } // ==================== ID ==================== function getXmId() { const qs = (location.hash || '').split('?')[1] || ''; if (!qs) return ''; const p = new URLSearchParams(qs); if (isCoursePage()) return p.get('xmId') || ''; if (isDetailPage()) return p.get('id') || ''; return p.get('xmId') || p.get('id') || ''; } function getResourceId() { const qs = (location.hash || '').split('?')[1] || ''; if (!qs || !isCoursePage()) return ''; return new URLSearchParams(qs).get('id') || ''; } // ==================== API ==================== const API = { getXm: () => fetch('/api/student/xm/getById', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, body: 'id=' + xmId, }).then(r => r.json()), getCourse: (rid) => fetch('/api/student/recommendCourse/getById?id=' + rid + '&xmId=' + xmId).then(r => r.json()), }; // ==================== Toast 通知 ==================== function toast(msg, duration) { const el = document.createElement('div'); el.style.cssText = 'position:fixed;top:16px;left:50%;transform:translateX(-50%);z-index:999999;' + 'background:#1e1e2e;color:#a6e3a1;padding:10px 24px;border-radius:20px;' + 'font:13px "Microsoft YaHei",sans-serif;box-shadow:0 4px 20px rgba(0,0,0,.5);' + 'animation:fadeInOut ' + (duration || 3) + 's ease both;pointer-events:none;border:1px solid rgba(166,227,161,.3)'; el.textContent = msg; document.body.appendChild(el); setTimeout(() => el.remove(), (duration || 3) * 1000); } // ==================== UI 面板 ==================== let logEl, statusEl, progressEl, courseNameEl, listEl; let vidBarEl, vidTimeEl, vidTotalEl, vidEtaEl, bannerEl, trainNameEl; function createPanel() { if (document.getElementById('__whut_panel')) return; // 注入动画 const style = document.createElement('style'); style.textContent = '@keyframes fadeInOut{0%{opacity:0;transform:translateX(-50%) translateY(-10px)}15%{opacity:1;transform:translateX(-50%) translateY(0)}85%{opacity:1}100%{opacity:0}}'; document.head.appendChild(style); const d = document.createElement('div'); d.id = '__whut_panel'; d.innerHTML = '' // HTML + '
' + '
📖党校学习
' + '
' + '
' + '' + '
' // 状态块 + '
' + '
待命中
等待操作
' // 视频进度 + '
' + '
0:000:00
' + '
' // 课程进度 + '
课程进度0 / 0
' + '
' // 课程列表 + '
课程状态
' // 日志 + '
运行日志
' // 按钮 + '
' + '' + '' + '' + '
'; document.body.appendChild(d); // 绑定引用 logEl = $('#__whut_log'); statusEl = $('#__whut_status'); progressEl = $('#__whut_progress'); courseNameEl = $('#__whut_substatus'); listEl = $('#__whut_courselist'); vidBarEl = $('#__whut_vidBar'); vidTimeEl = $('#__whut_vidCur'); vidTotalEl = $('#__whut_vidTot'); vidEtaEl = $('#__whut_vidEta'); bannerEl = $('#__whut_banner'); trainNameEl = $('#__whut_banner'); // 事件 $('#__whut_start').addEventListener('click', start); $('#__whut_stop').addEventListener('click', stop); $('#__whut_scan').addEventListener('click', () => scanAndStart()); $('#__whut_hide').addEventListener('click', () => d.classList.toggle('collapsed')); $('#__whut_cls').addEventListener('click', () => { stop(); d.remove(); }); makeDraggable(d, $('#__whut_hd')); } function makeDraggable(el, hd) { let ox, oy, dx, dy; hd.addEventListener('mousedown', e => { ox = e.clientX; oy = e.clientY; const r = el.getBoundingClientRect(); dx = r.left; dy = r.top; const mv = ev => { el.style.left = (dx + ev.clientX - ox) + 'px'; el.style.top = (dy + ev.clientY - oy) + 'px'; el.style.right = 'auto'; }; const up = () => { document.removeEventListener('mousemove', mv); document.removeEventListener('mouseup', up); }; document.addEventListener('mousemove', mv); document.addEventListener('mouseup', up); }); } // ==================== UI 更新 ==================== function setState(st) { const dot = $('#__whut_dot'); if (dot) dot.className = 'stat-dot ' + st; } function setStatus(s, sub) { if (statusEl) statusEl.textContent = s; if (courseNameEl && sub !== undefined) courseNameEl.textContent = sub; } function setBanner(msg) { if (bannerEl) { bannerEl.textContent = msg; bannerEl.style.display = msg ? 'block' : 'none'; } } function updateCourseProgress() { const actual = (stats.completed|0) + (stats.scriptDone|0); if (progressEl) progressEl.textContent = actual + ' / ' + (stats.total|0); const bar = $('#__whut_crsBar'); if (bar && stats.total > 0) bar.style.width = Math.min(100, (actual / (stats.total|0)) * 100) + '%'; } function updateVidProgress() { const v = $('video'); if (v && v.duration && !v.ended) { currentVidTime = v.currentTime; const total = v.duration; // 使用真实 video.duration,不依赖 API 推算 const blk = $('#__whut_vidBlk'); if (blk) blk.style.display = 'block'; const pct = Math.min(100, (currentVidTime / total) * 100); if (vidBarEl) vidBarEl.style.width = pct + '%'; if (vidTimeEl) vidTimeEl.textContent = fmtTime(currentVidTime); if (vidTotalEl) vidTotalEl.textContent = fmtTime(total); if (vidEtaEl) { const rem = total - currentVidTime; vidEtaEl.textContent = rem > 0 ? '剩余 ' + fmtTime(rem) : ''; } } } function fmtTime(s) { const m = Math.floor(s / 60); const sec = Math.floor(s % 60); return m + ':' + (sec < 10 ? '0' : '') + sec; } function log(msg, type) { const t = new Date().toLocaleTimeString(); const el = document.createElement('div'); el.className = 'l' + (type ? ' ' + type : ''); el.textContent = t + ' ' + msg; if (logEl) { logEl.appendChild(el); logEl.scrollTop = logEl.scrollHeight; } console.log('%c[学习]', 'color:#cba6f7', msg); // 重要事件 toast if (type === 'ok' && (msg.includes('完成') || msg.includes('进入'))) toast(msg, 2); if (type === 'err') toast(msg, 4); } function showXmIdInput() { let box = $('#__whut_xmIdBox'); if (!box) { box = document.createElement('div'); box.id = '__whut_xmIdBox'; box.style.cssText = 'margin-top:8px;display:flex;gap:4px'; box.innerHTML = ''; const body = $('#__whut_body'); if (body) { const acts = body.querySelector('.acts'); if (acts) body.insertBefore(box, acts); else body.appendChild(box); } $('#__whut_xmIdBtn').addEventListener('click', () => { const v = $('#__whut_xmIdInput').value.trim(); if (v) { xmId = v; log('手动ID: ' + v, 'ok'); box.remove(); scanAndStart(); } }); } box.style.display = 'flex'; } // ==================== 视频劫持 ==================== function hackVideo(video) { if (hacked.has(video)) return; hacked.add(video); video.muted = true; video.playbackRate = 1; // 智能计算跳播时长:处理 API 返回秒/分钟单位不一致 let seekTo = finishedDuration; let seekDone = false; let seekRetries = 0; const MAX_SEEK_RETRIES = 20; // 10秒内每500ms重试 const doSeek = () => { if (seekDone || seekRetries >= MAX_SEEK_RETRIES) return; if (!video.duration || video.duration <= 0) return; seekRetries++; // 单位修正:如果 finishedDuration 远大于实际时长,可能是重复乘了60 if (seekTo > video.duration * 1.5) { const fixed = seekTo / 60; if (fixed > 0 && fixed < video.duration - 5) { log('单位修正: ' + fmtTime(seekTo) + ' → ' + fmtTime(fixed), 'warn'); seekTo = fixed; } } if (seekTo > 0 && seekTo < video.duration - 5) { seekDone = true; video.currentTime = seekTo; watchdogLastCurrentTime = seekTo; watchdogProgressTime = Date.now(); log('跳过已看 ' + fmtTime(seekTo) + ',继续播放', 'info'); } }; // 事件驱动 + 定时兜底,防 SPA 不触发原生事件 video.addEventListener('loadedmetadata', doSeek); video.addEventListener('canplay', () => { doSeek(); }, { once: false }); if (video.readyState >= 2 && video.duration) doSeek(); const forceTimer = setInterval(() => { if (video.ended) { clearInterval(forceTimer); return; } if (!seekDone) doSeek(); // 定时重试跳播 if (video.paused) { video.play().catch(() => { }); } else { // 看门狗:视频在播放但 currentTime 变了才算有进展 if (Math.abs(video.currentTime - watchdogLastCurrentTime) > 0.2) { watchdogLastCurrentTime = video.currentTime; watchdogProgressTime = Date.now(); } } updateVidProgress(); }, 500); video.play().catch(() => { }); video.addEventListener('ended', () => { clearInterval(forceTimer); updateVidProgress(); log('视频播放完毕 ✔', 'ok'); toast('本视频播放完毕,自动进入下一节', 2); onVideoEnded(); }); video.addEventListener('emptied', () => { clearInterval(forceTimer); hacked.delete(video); }); video.addEventListener('abort', () => { clearInterval(forceTimer); hacked.delete(video); }); const vShow = fmtTime(video.duration || videoDuration); log('已接管 · 总长 ' + vShow, 'info'); updateVidProgress(); } function hackAllVideos() { $$('video').forEach(hackVideo); return $$('video').length; } // ==================== 结束处理 ==================== function onVideoEnded() { if (stopped) return; setTimeout(() => tryGoNextOrBack(), 1500); } function tryGoNextOrBack() { if (stopped || navigating) return; const kws = ['下一节', '下一章', '下一个', '继续学习', '继续']; for (const kw of kws) { for (const el of $$('button, a, span, div[class*=btn]')) { if (!el.offsetParent) continue; if ((el.textContent || '').trim().includes(kw)) { log('→ ' + kw, 'ok'); navigating = true; el.click(); setTimeout(() => { navigating = false; }, 2500); return; } } } const items = $$('.el-menu-item,[class*=chapter] [class*=item],[class*=lesson],[class*=catalog] li,[role=treeitem]').filter(e => e.offsetParent); for (let i = 0; i < items.length - 1; i++) { if ((items[i].className || '').match(/active|is-active|current/)) { log('→ 目录下一项', 'ok'); navigating = true; items[i + 1].click(); setTimeout(() => { navigating = false; }, 2500); return; } } if (courseList.length > 1) { log('本节完成 → 返回列表重扫', 'ok'); stats.scriptDone = (stats.scriptDone | 0) + 1; updateCourseProgress(); goBackAndContinue(); } else { log('全部完成 → 返回列表', 'ok'); stats.scriptDone = 0; stats.completed = stats.total | 0; updateCourseProgress(); goBackAndContinue(); } } function goBackAndContinue() { cancelCourseRecovery(); sessionStorage.setItem('whut_goto_detail', xmId); saveStateForReload(); location.reload(); } // ==================== 扫描 ==================== // 静默拉取课程列表和进度(不导航,只填充数据供课程页初始化用) async function fetchCourseStats() { try { const resp = await API.getXm(); if (resp.code !== 0 || !resp.data) return; const list = resp.data.xmCourseSetting.chooseCourseList; setBanner(resp.data.name); courseList = list .filter(c => { const mode = c.studyMode || ''; if (mode !== 'WLXX' && mode !== '') return false; if (!c.resourceId) return false; const prog = c.progress != null ? parseFloat(c.progress) : 0; return prog < 1; }) .sort((a, b) => (a.sort || 0) - (b.sort || 0)); // 过滤掉当前正在播放的课程,避免重复进入 const resId = getResourceId(); if (resId) courseList = courseList.filter(c => String(c.resourceId) !== resId); const totalOnline = list.filter(c => c.resourceId).length; stats.total = totalOnline | 0; stats.completed = (totalOnline - list.filter(c => { const mode = c.studyMode || ''; if (mode !== 'WLXX' && mode !== '') return false; const prog = c.progress != null ? parseFloat(c.progress) : 0; return prog < 1; }).length) | 0; updateCourseProgress(); // 渲染课程列表 let html = ''; const clsMap = ['todo','half','done','skip']; list.forEach(c => { const mode = c.studyMode || ''; const prog = c.progress != null ? parseFloat(c.progress) : (c.finishedDuration >= c.duration ? 1 : 0); const cls = prog >= 1 ? 'done' : (prog > 0 ? 'half' : (mode !== 'WLXX' && mode !== '' ? 'skip' : 'todo')); html += '' + (prog >= 1 ? '✔' : (prog > 0 ? '◐' : '○')) + ' ' + (c.courseName || c.name) + ' ' + Math.round(prog * 100) + '%\n'; }); if (listEl) listEl.innerHTML = html; } catch(e) {} } // 静默扫描:只拉API渲染课程状态,不启动自动学习 async function scanAndRender() { try { const resp = await API.getXm(); if (resp.code !== 0 || !resp.data) return; const list = resp.data.xmCourseSetting.chooseCourseList; sessionStorage.setItem('whut_fullList', JSON.stringify(list)); setBanner(resp.data.name); // 渲染全部课程状态 let html = ''; list.forEach(c => { const mode = c.studyMode || ''; const prog = c.progress != null ? parseFloat(c.progress) : (c.finishedDuration >= c.duration ? 1 : 0); const cls = prog >= 1 ? 'done' : (prog > 0 ? 'half' : (mode !== 'WLXX' && mode !== '' ? 'skip' : 'todo')); html += '' + (prog >= 1 ? '✔' : (prog > 0 ? '◐' : '○')) + ' ' + (c.courseName || c.name) + ' ' + Math.round(prog * 100) + '%\n'; }); if (listEl) listEl.innerHTML = html; // 填充 courseList 和 stats courseList = list .filter(c => c.resourceId && (c.progress != null ? parseFloat(c.progress) : 0) < 1) .sort((a, b) => (a.sort || 0) - (b.sort || 0)); const resId = getResourceId(); if (resId) courseList = courseList.filter(c => String(c.resourceId) !== resId); stats.total = list.filter(c => c.resourceId).length | 0; stats.completed = (stats.total - courseList.length + (resId ? 1 : 0)) | 0; updateCourseProgress(); } catch(e) {} } async function scanAndStart() { xmId = getXmId(); if (!xmId) { setStatus('请先进入培训班详情页', '路径: 我的培训 → 选择培训班 → 点击进入'); setState('err'); log('未检测到培训班ID,请进入培训班详情页', 'err'); log('当前页面: ' + location.href, 'warn'); log('正确地址示例: /#/myTrain/detail?id=培训班ID', 'warn'); showXmIdInput(); return; } setStatus('正在获取课程列表...', '请稍候'); setState('scan'); setBanner(''); let data; try { const resp = await API.getXm(); if (resp.code !== 0) throw new Error('服务器返回 code=' + resp.code); data = resp.data; } catch (e) { setStatus('获取失败', e.message); setState('err'); log('API 请求失败: ' + e.message, 'err'); showXmIdInput(); return; } setBanner(data.name); log('培训班: ' + data.name, 'ok'); const list = data.xmCourseSetting.chooseCourseList; sessionStorage.setItem('whut_fullList', JSON.stringify(list)); // 筛选 WLXX 未完成 courseList = list .filter(c => { const mode = c.studyMode || ''; if (!c.resourceId) return false; const prog = c.progress != null ? parseFloat(c.progress) : 0; return prog < 1; }) .sort((a, b) => (a.sort || 0) - (b.sort || 0)); // 渲染课程列表(带颜色) let html = ''; list.forEach(c => { const mode = c.studyMode || ''; const prog = c.progress != null ? parseFloat(c.progress) : (c.finishedDuration >= c.duration ? 1 : 0); const cls = prog >= 1 ? 'done' : (prog > 0 ? 'half' : (mode !== 'WLXX' && mode !== '' ? 'skip' : 'todo')); const icon = prog >= 1 ? '✔' : (prog > 0 ? '◐' : '○'); const pct = Math.round(prog * 100) + '%'; html += '' + icon + ' ' + (c.courseName || c.name) + ' ' + pct + '\n'; }); if (listEl) listEl.innerHTML = html; const totalOnline = list.filter(c => c.resourceId).length; stats.total = totalOnline | 0; stats.completed = (totalOnline - courseList.length) | 0; updateCourseProgress(); if (courseList.length === 0) { setStatus('全部完成!', totalOnline + ' 门课程已全部通过'); setState('done'); toast('所有课程已完成!', 3); navigating = false; return; } setStatus('准备开始', '共 ' + totalOnline + ' 门,剩 ' + courseList.length + ' 门待完成'); setState('play'); toast('开始自动学习 · 剩余 ' + courseList.length + ' 门', 2); enterNextCourse(); } async function enterNextCourse() { if (stopped || courseList.length === 0) { setStatus('全部完成!', stats.total + ' 门课程已全部通过'); setState('done'); toast('全部课程已完成!', 3); navigating = false; return; } navigating = true; currentCourse = courseList.shift(); const name = currentCourse.courseName || currentCourse.name; setStatus('进入课程', name); setState('play'); updateCourseProgress(); videoDuration = 0; finishedDuration = 0; try { const resp = await API.getCourse(currentCourse.resourceId); if (resp.code === 0 && resp.data) { videoDuration = (resp.data.duration || 0) * 60; const fd = resp.data.finishDruation != null ? resp.data.finishDruation : (resp.data.finishedDuration != null ? resp.data.finishedDuration : 0); finishedDuration = (fd || 0) * 60; if (finishedDuration > 0) { log('已看 ' + fmtTime(finishedDuration) + ',将跳过', 'info'); } } } catch (e) { /* 静默 */ } // 真刷新进课:保存已完成进度 + 跳播位置 + 目标课程 saveStateForReload(); sessionStorage.setItem('whut_finishedDuration', finishedDuration); sessionStorage.setItem('whut_goto_course', JSON.stringify({ resourceId: currentCourse.resourceId, xmId: xmId })); location.reload(); } // ==================== 重载恢复 ==================== function scheduleCourseRecovery() { cancelCourseRecovery(); courseRecoveryTimer = setTimeout(() => { if (!stopped && isCoursePage() && $$('video').length === 0 && !navigating) { log('超时无视频,强制刷新恢复...', 'warn'); saveStateForReload(); location.reload(); } }, 45000); } function cancelCourseRecovery() { if (courseRecoveryTimer) { clearTimeout(courseRecoveryTimer); courseRecoveryTimer = null; } } // ==================== 课程循环 ==================== function startCourseLoop() { stats.startTime = Date.now(); navigating = false; watchdogProgressTime = Date.now(); watchdogLastCurrentTime = -1; const timer = setInterval(() => { if (stopped) { clearInterval(timer); return; } if (!isCoursePage()) { clearInterval(timer); return; } const vids = $$('video'); if (vids.length > 0) { cancelCourseRecovery(); } if (vids.length === 0) { window.scrollTo(0, document.body.scrollHeight); if (Date.now() - stats.startTime > CFG.coursePageTimeout * 1000) { log('超时无视频,返回列表', 'warn'); clearInterval(timer); goBackAndContinue(); } } else { hackAllVideos(); // 🐕 看门狗:3分钟无播放进展则强刷 if (Date.now() - watchdogProgressTime > WATCHDOG_STUCK_LIMIT) { log('看门狗:视频卡死超过3分钟,强制刷新恢复', 'err'); setTimeout(() => { saveStateForReload(); location.reload(); }, 500); clearInterval(timer); return; } // 🐕 子检测:30秒持续暂停无播放则强刷 const allPaused = vids.every(v => v.paused && !v.ended); if (allPaused && vids.some(v => v.currentTime < 0.5) && (Date.now() - stats.startTime > 30000)) { log('视频卡死在0:00,强制刷新恢复', 'err'); setTimeout(() => { saveStateForReload(); location.reload(); }, 500); clearInterval(timer); return; } const allDone = vids.every(v => v.ended || (v.duration && v.currentTime >= v.duration - 1)); if (allDone && !navigating) { clearInterval(timer); setTimeout(() => tryGoNextOrBack(), 1500); } } }, CFG.checkInterval); timers.push(timer); } // ==================== 启动/停止 ==================== function start() { stopped = false; navigating = false; stats = { completed: 0, total: 0, startTime: 0, scriptDone: 0 }; courseList = []; currentCourse = null; timers.forEach(clearInterval); timers = []; cancelCourseRecovery(); updateCourseProgress(); log('▶ 全自动学习启动', 'ok'); saveState(); scanAndStart(); } function stop() { stopped = true; navigating = false; timers.forEach(clearInterval); timers = []; cancelCourseRecovery(); // 清理 sessionStorage,防止手动刷新后误恢复 sessionStorage.removeItem('whut_reload_reason'); sessionStorage.removeItem('whut_courseList'); sessionStorage.removeItem('whut_currentCourse'); sessionStorage.removeItem('whut_finishedDuration'); courseList = []; setStatus('已停止', '点击"开始学习"继续'); setState('idle'); const vBlk = $('#__whut_vidBlk'); if (vBlk) vBlk.style.display = 'none'; log('已停止 · 状态已保存,下次打开可继续', 'warn'); saveState(); } // ==================== URL 监听 ==================== let lastUrl = location.href; setInterval(() => { if (location.href !== lastUrl) { lastUrl = location.href; if (!stopped) { if (isCoursePage()) { navigating = false; // 从 loadState 恢复的数据渲染课程状态(不调 API,避免覆盖 scriptDone) renderCourseList(); updateCourseProgress(); setStatus('播放中...', currentCourse ? (currentCourse.courseName || currentCourse.name) : ''); setState('play'); let waited = 0; const w = setInterval(() => { waited++; if ($$('video').length > 0 || waited > 15) { clearInterval(w); startCourseLoop(); hackAllVideos(); } }, 1000); } else if (isDetailPage()) { navigating = false; setTimeout(() => { if (!stopped && isDetailPage()) scanAndStart(); }, 1500); } } } }, 1000); // ==================== 视频进度轮询 ==================== setInterval(() => { if (!stopped && isCoursePage()) updateVidProgress(); }, 2000); // ==================== 初始化 ==================== function init() { createPanel(); new MutationObserver(mutations => { for (const m of mutations) for (const node of m.addedNodes) { if (node.nodeName === 'VIDEO') hackVideo(node); if (node.querySelectorAll) node.querySelectorAll('video').forEach(hackVideo); } }).observe(document.body || document.documentElement, { childList: true, subtree: true }); // 从课程页回详情页的真刷新标记 const gotoDetail = sessionStorage.getItem('whut_goto_detail'); if (gotoDetail) { sessionStorage.removeItem('whut_goto_detail'); stopped = false; xmId = gotoDetail; loadState(); // 恢复进度/课程列表等 location.href = '#/myTrain/detail?id=' + xmId; return; } const gotoCourse = sessionStorage.getItem('whut_goto_course'); if (gotoCourse) { sessionStorage.removeItem('whut_goto_course'); try { const c = JSON.parse(gotoCourse); stopped = false; xmId = c.xmId; loadState(); // 恢复 finishedDuration、进度、currentCourse、courseList location.href = '#/myTrain/course?id=' + c.resourceId + '&xmId=' + c.xmId; } catch(e) {} return; } // 尝试恢复上次状态 const restored = loadState(); if (restored === 'reload_recovery') { log('后台重载恢复 · 培训班: ' + xmId, 'ok'); log('恢复进度: ' + stats.completed + '/' + stats.total, 'info'); if (courseList.length > 0) log('待完成: ' + courseList.length + ' 门', 'info'); stopped = false; } else if (restored === 'session_restore') { log('已恢复上次会话 · 培训班ID: ' + xmId, 'ok'); log('上次进度: ' + stats.completed + '/' + stats.total, 'info'); } if (isCoursePage() && !stopped) { xmId = getXmId() || xmId; if (xmId) { const v = $('video'); if (v && v.currentTime > 0) finishedDuration = v.currentTime; // 如果是重载恢复且已有 courseList,直接接管;否则异步拉取 if (restored !== 'reload_recovery' || courseList.length === 0) { fetchCourseStats(); } else { updateCourseProgress(); } log('已检测到课程页面,自动接管', 'ok'); setStatus('后台运行中', currentCourse ? (currentCourse.courseName || currentCourse.name) : ''); setState('play'); startCourseLoop(); } } else if (isDetailPage()) { xmId = getXmId() || xmId; if (!xmId) { setStatus('请进入培训班', '点击左侧「我的培训」→ 选择培训班'); setState('idle'); return; } // 始终拉取并渲染全部课程状态 scanAndRender(); if (restored === 'reload_recovery' && !stopped && courseList.length > 0) { log('重载恢复:自动进入下一门课...', 'ok'); setTimeout(() => { navigating = true; enterNextCourse(); }, 800); } else if (restored === 'session_restore' && !stopped) { log('检测到未完成任务,自动恢复...', 'ok'); setTimeout(() => { if (isDetailPage()) startAutoLearning(); }, 1000); } else { setStatus('准备就绪', '点击「全自动学习」开始'); setState('idle'); } } else { setStatus('请进入培训班', '点击左侧「我的培训」→ 选择培训班'); setState('idle'); log('请进入培训班详情页后使用', 'warn'); } } if (document.readyState === 'complete') init(); else window.addEventListener('load', init); // ==================== 题库模块 ==================== // ========================================== // ☁️ 云端题库配置 // ========================================== // ========================================== // 1. 本地数据库模块 // ========================================== const DB_KEY = 'whut_qbank_db_v1'; function getDB() { try { return JSON.parse(GM_getValue(DB_KEY, '[]')); } catch (e) { return []; } } function saveToDB(newQuestions) { let db = getDB(); let addedCount = 0; let existingIds = new Set(db.map(q => q.content)); for (let raw of newQuestions) { let q = normalizeQuestion(raw); if (!q || !q.content) continue; if (!existingIds.has(q.content)) { db.push(q); existingIds.add(q.content); addedCount++; } } if (addedCount > 0) { GM_setValue(DB_KEY, JSON.stringify(db)); updateStats(db.length); } return addedCount; } function clearDB() { if(confirm("确定清空本地题库吗?清空后无法恢复!(云端题库不受影响)")) { GM_deleteValue(DB_KEY); updateStats(0); qlog("本地数据库已清空。"); } } // ========================================== // 2. 数据清洗与规范化 // ========================================== function normalizeQuestion(raw) { let q = raw.dataJson || raw; let typeStr = q.type || raw.type || raw.realType || ''; let content = q.content || raw.content || ''; let answer = q.answer || raw.answer || ''; let options = q.options || raw.options || []; if (!content) return null; let realType = "未知题型"; if (typeStr.includes('SINGLE')) realType = "单选题"; else if (typeStr.includes('MULTIPLE')) realType = "多选题"; else if (typeStr.includes('JUDGMENT')) realType = "判断题"; else if (typeStr.includes('BLANKFILL')) realType = "填空题"; else if (raw.realType) realType = raw.realType; content = content.replace(/<[^>]+>/g, '').trim(); content = content.replace(/\[BlankArea\d*\]/gi, '______'); let normOptions = []; if (Array.isArray(options)) { normOptions = options.map(opt => ({ alias: opt.alisa || opt.alias || '', text: (opt.text || '').replace(/<[^>]+>/g, '').trim() })); } if (realType === "判断题") { if (answer === 'Y' || answer === 'true') answer = "正确"; else if (answer === 'N' || answer === 'false') answer = "错误"; } else if (realType === "填空题" && raw.blanks && Array.isArray(raw.blanks)) { answer = raw.blanks.map(b => b.value).join(" ; "); } return { type: realType, content, options: normOptions, answer }; } function extractQuestionsFromData(obj) { let questions = []; let cache = new Set(); function search(item) { if (!item || typeof item !== 'object' || cache.has(item)) return; cache.add(item); if ((item.type || item.realType) && item.content) { if(item.type && ['SINGLE', 'MULTIPLE', 'JUDGMENT', 'BLANKFILL', 'ESSAY'].some(t => item.type.includes(t) || (item.realType && item.realType.includes(t)))){ questions.push(item); } } for (let key in item) { if (Object.prototype.hasOwnProperty.call(item, key)) search(item[key]); } } search(obj); return questions; } // ========================================== // ☁️ 云端题库引擎 (GM_xmlhttpRequest 跨域) // ========================================== function gmGet(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method:'GET', url, timeout:10000, onload: r => { try { resolve(JSON.parse(r.responseText)); } catch(e) { resolve(null); } }, onerror: () => resolve(null), ontimeout: () => resolve(null) }); }); } function gmPost(url, data) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method:'POST', url, data:JSON.stringify(data), headers:{'Content-Type':'application/json'}, timeout:10000, onload: r => { try { resolve(JSON.parse(r.responseText)); } catch(e) { resolve(null); } }, onerror: () => resolve(null), ontimeout: () => resolve(null) }); }); } // 从 Gitee API 读取文件(绕过 Raw CDN 重定向) async function gmGetGiteeFile(filePath) { try { const apiRes = await new Promise((resolve) => { GM_xmlhttpRequest({ method: 'GET', url: `${CLOUD.apiBase}/${filePath}`, timeout: 10000, onload: r => { try { resolve(JSON.parse(r.responseText)); } catch(e) { resolve(null); } }, onerror: () => resolve(null), ontimeout: () => resolve(null) }); }); if (apiRes && apiRes.content) { return JSON.parse(atob(apiRes.content)); } return null; } catch(e) { return null; } } // 查询云端题库索引 async function fetchCloudIndex(forceRefresh = false) { if (cloudIndex && !forceRefresh) return cloudIndex; try { const data = await gmGet(`${CLOUD.workerBase}/index`); if (data) { cloudIndex = data; qlog(`☁️ 云端索引: ${cloudIndex.courses?.length||0}门课`,'ok'); return cloudIndex; } qlog('⚠️ 云端索引加载失败','err'); return { courses:[], count:{} }; } catch(e) { qlog('⚠️ 云端索引异常','err'); return { courses:[], count:{} }; } } // 从云端查询单个答案 async function queryCloudAnswer(course, questionContent) { const nq = questionContent.replace(/<[^>]+>/g,'').trim(); const qk = extractKeywords(nq); if (!qk.length) return null; try { const bank = await gmGet(`${CLOUD.workerBase}/course/${encodeURIComponent(course)}`); if (!bank || !Array.isArray(bank)) return null; return bank.find(q => { let dbc = (q.content||'').replace(/<[^>]+>/g,'').trim(); let dbk = extractKeywords(dbc); return dbk.length > 0 && qk.filter(k=>dbk.includes(k)).length >= Math.min(qk.length,3); }) || null; } catch(e) { return null; } } // 从云端批量查询答案 async function queryCloudBatch(course, questions) { try { const bank = await gmGet(`${CLOUD.workerBase}/course/${encodeURIComponent(course)}`); if (!bank || !Array.isArray(bank)) return []; return questions.map(q => { const nq = (q.content||'').replace(/<[^>]+>/g,'').trim(); const qk = extractKeywords(nq); if (!qk.length) return null; const found = bank.find(bq => { let dbc = (bq.content||'').replace(/<[^>]+>/g,'').trim(); let dbk = extractKeywords(dbc); return dbk.length > 0 && qk.filter(k=>dbk.includes(k)).length >= Math.min(qk.length,3); }); return found || null; }); } catch(e) { return questions.map(()=>null); } } // 提取关键词(去标点 + 停用词 + 中文双字词fallback) function extractKeywords(text) { if (!text) return []; let cleaned = text.replace(/<[^>]+>/g, '') .replace(/[,。、;:?!""''()()《》【】\[\]{}.,;:!?"'()\[\]{}<>\/\|@#$%^&*+=~`_\-]/g, ' '); let tokens = cleaned.split(/\s+/).filter(w => w.length >= 2); let stopwords = new Set(['以下','选项','的是','正确','错误','关于','下列','不是','属于','哪个','一项','什么','可以','没有','不属于','包括']); tokens = tokens.filter(w => !stopwords.has(w)); // 中文长token拆双字词,提高无标点文本的匹配率 let keywords = [...tokens]; for (let token of tokens) { if (token.length >= 4) { for (let i = 0; i < token.length - 1; i++) { let bigram = token.substring(i, i + 2); if (!stopwords.has(bigram)) keywords.push(bigram); } } } return [...new Set(keywords)]; } // 贡献到云端(通过 Worker,用 GM_xmlhttpRequest 跨域) async function contributeToCloud(course, questions) { if (!course || !questions || !questions.length) return false; const clean = questions.map(q=>({type:q.type,content:q.content,options:q.options,answer:q.answer})); try { const result = await gmPost(`${CLOUD.workerBase}/contribute`, {course,questions:clean}); return !!(result && result.success); } catch(e) { return false; } } // 一键上传本地全部题库到云端 async function uploadAllToCloud(course) { if (!course) return; const db = getDB(); if (db.length === 0) return; await contributeToCloud(course, db); } // 从云端下载题库到本地 async function downloadCloudToLocal(course) { if (!course) { qlog('❌ 请输入课程标识','err'); return; } try { const bank = await gmGet(`${CLOUD.workerBase}/course/${encodeURIComponent(course)}`); if (!bank || !Array.isArray(bank)) { qlog('❌ 云端未找到该课程','err'); return; } const added = saveToDB(bank); qlog(`☁️ 下载完成: +${added}题 (云端${bank.length}题)`,'ok'); updateStats(getDB().length); } catch(e) { qlog('❌ 下载失败','err'); } } // ========================================== // 🎯 自动答题引擎 // ========================================== function parseCurrentPageQuestions(course) { let found = []; // 方法1:从 Vue 实例提取 const allElements = document.querySelectorAll('*'); for (let el of allElements) { if (el.__vue__) { try { let vueData = JSON.parse(JSON.stringify(el.__vue__.$data || {})); let extracted = extractQuestionsFromData(vueData); found = found.concat(extracted); } catch(e) {} } } // 方法2:DOM 选择器找题目文本 if (found.length === 0) { const questionEls = document.querySelectorAll('[class*="question"], [class*="topic"], [class*="subject"], .q-title, .q-content'); questionEls.forEach(el => { const text = el.textContent.trim(); if (text.length > 10) { found.push({ content: text, type: '未知题型', options: [], answer: '' }); } }); } return found; } // 执行自动答题 async function doAutoAnswer(course) { if (!CLOUD.autoAnswerEnabled) return; qlog('🎯 自动答题引擎启动,正在识别页面题目...'); const pageQuestions = parseCurrentPageQuestions(course); if (pageQuestions.length === 0) { qlog('⚠️ 未在页面检测到题目'); return; } qlog(`📋 检测到 ${pageQuestions.length} 道题目,正在查询答案...`); // 1. 先查本地 const db = getDB(); let answeredCount = 0; for (const pq of pageQuestions) { const cleanContent = pq.content.replace(/<[^>]+>/g, '').trim(); const queryKeywords = extractKeywords(cleanContent); // 本地查找 let match = db.find(q => { let dbc = (q.content || '').replace(/<[^>]+>/g, '').trim(); const dbk = extractKeywords(dbc); return queryKeywords.length > 0 && dbk.length > 0 && queryKeywords.filter(k => dbk.includes(k)).length >= Math.min(queryKeywords.length, 3); }); // 云端查找 if (!match) { match = await queryCloudAnswer(course, cleanContent); } if (match && match.answer) { fillAnswerToPage(pq, match); answeredCount++; qlog(`✅ [${pq.type || '?'}] ${cleanContent.substring(0, 30)}... → 答案:${match.answer}`); } else { qlog(`❓ [${pq.type || '?'}] ${cleanContent.substring(0, 30)}... → 未找到答案`); } } qlog(`🎯 自动答题完成:${answeredCount}/${pageQuestions.length} 题已填入答案`); } // 将答案填入页面控件 function fillAnswerToPage(question, match) { const answer = match.answer; const type = match.type || question.type; if (type === '判断题' || type === 'JUDGMENT') { const correctVal = (answer === '正确' || answer === 'Y' || answer === 'true') ? 'Y' : 'N'; // 尝试点击正确/错误按钮 const allBtns = document.querySelectorAll('button, label, .option, .choice, [class*="option"]'); allBtns.forEach(btn => { const txt = (btn.textContent || '').trim(); if ((correctVal === 'Y' && txt.includes('正确')) || (correctVal === 'N' && txt.includes('错误'))) { btn.click(); } }); // 尝试 radio const radios = document.querySelectorAll('input[type="radio"]'); radios.forEach(r => { const label = r.closest('label')?.textContent?.trim() || ''; if ((correctVal === 'Y' && label.includes('正确')) || (correctVal === 'N' && label.includes('错误'))) { r.click(); } }); } else if (type === '单选题' || type === 'SINGLE') { // 匹配选项 const options = match.options || []; let targetAlias = answer; if (options.length > 0) { const matchedOpt = options.find(o => o.alias === answer); if (matchedOpt) targetAlias = matchedOpt.alias; } // 点击对应选项 const allOptions = document.querySelectorAll('label, .option, [class*="option"], [class*="choice"]'); allOptions.forEach(opt => { const txt = (opt.textContent || '').trim(); if (txt.startsWith(targetAlias + '.') || txt.startsWith(targetAlias + '、') || txt === targetAlias) { opt.click(); } }); // radio const radios = document.querySelectorAll('input[type="radio"]'); radios.forEach(r => { const val = r.value || ''; const label = r.closest('label')?.textContent?.trim() || ''; if (val === targetAlias || label.startsWith(targetAlias + '.') || label.startsWith(targetAlias + '、')) { r.click(); } }); } else if (type === '多选题' || type === 'MULTIPLE') { const answers = answer.split(/[,,\s]+/).filter(Boolean); const checkboxes = document.querySelectorAll('input[type="checkbox"]'); checkboxes.forEach(cb => { const val = cb.value || ''; const label = cb.closest('label')?.textContent?.trim() || ''; if (answers.some(a => val === a || label.startsWith(a + '.') || label.startsWith(a + '、'))) { cb.checked = true; cb.dispatchEvent(new Event('change', { bubbles: true })); } }); } else if (type === '填空题' || type === 'BLANKFILL') { const inputs = document.querySelectorAll('input[type="text"], textarea, [contenteditable="true"]'); const answers = answer.split(/\s*;\s*/); inputs.forEach((inp, i) => { if (i < answers.length) { if (inp.contentEditable === 'true') { inp.textContent = answers[i]; } else { inp.value = answers[i]; inp.dispatchEvent(new Event('input', { bubbles: true })); } } }); } } // 页面监控:检测到题目页面时自动触发答题 function watchForQuestions(course) { if (autoAnswerTimer) clearInterval(autoAnswerTimer); autoAnswerTimer = setInterval(() => { if (!CLOUD.autoAnswerEnabled) return; const questions = parseCurrentPageQuestions(course); if (questions.length > 0) { clearInterval(autoAnswerTimer); doAutoAnswer(course); } }, 2000); // 30秒后停止扫描 setTimeout(() => { if (autoAnswerTimer) clearInterval(autoAnswerTimer); }, 30000); } // ========================================== // 3. UI 界面构建 // ========================================== let logArea, countSpan, cloudCountSpan; function initPanel() { const panel = document.createElement('div'); panel.id = '__whut_qbank'; panel.style.cssText = ` position:fixed;top:80px;left:10px;width:248px;max-height:88vh;overflow-y:auto; background:rgba(22,22,30,.88);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px); color:#cdd6f4;border-radius:16px;box-shadow:0 8px 32px rgba(0,0,0,.5),0 0 0 1px rgba(255,255,255,.05); z-index:99998;font:12px/1.5 'Microsoft YaHei',sans-serif;user-select:none;transition:opacity .25s; `; panel.innerHTML = `
🎯题库 0题
☁️ 云端 · Gitee
加载中...
🎯 自动答题
⚙ 高级
`; document.body.appendChild(panel); logArea = document.getElementById('tk-log'); countSpan = document.getElementById('tk-count'); // 高级面板折叠 document.getElementById('tk-api-toggle').onclick = () => { const p = document.getElementById('tk-api-panel'); p.style.display = p.style.display === 'none' ? 'block' : 'none'; }; // 事件绑定 - 原有功能 document.getElementById('btn-export-txt').onclick = exportTXT; document.getElementById('btn-export-csv').onclick = exportCSV; document.getElementById('btn-export-json').onclick = exportJSON; document.getElementById('btn-clear').onclick = clearDB; document.getElementById('btn-pull-errors').onclick = autoPullErrors; document.getElementById('btn-scan-dom').onclick = scanDOMForQuestions; document.getElementById('btn-api-send').onclick = sendCustomApiRequest; // 事件绑定 - 云端功能 document.getElementById('btn-cloud-upload').onclick = () => { const course = document.getElementById('tk-course').value.trim(); uploadAllToCloud(course); }; document.getElementById('btn-cloud-download').onclick = () => { const course = document.getElementById('tk-course').value.trim(); downloadCloudToLocal(course); }; document.getElementById('btn-cloud-refresh').onclick = () => fetchCloudIndex(true); document.getElementById('btn-auto-answer-now').onclick = () => { const course = document.getElementById('tk-course').value.trim(); doAutoAnswer(course); }; document.getElementById('tk-auto-answer').onchange = (e) => { CLOUD.autoAnswerEnabled = e.target.checked; qlog(`🎯 自动答题已${CLOUD.autoAnswerEnabled ? '开启' : '关闭'}`); }; document.getElementById('btn-minimize').onclick = (e) => { e.stopPropagation(); panel.classList.toggle('collapsed'); const btn = document.getElementById('btn-minimize'); btn.textContent = panel.classList.contains('collapsed') ? '+' : '−'; }; updateStats(getDB().length); fetchCloudIndex().then(() => updateCloudUI()); // 拖拽 const header = document.getElementById('tk-header'); let isDragging = false, startX, startY, initialX, initialY; header.onmousedown = (e) => { isDragging = true; startX = e.clientX; startY = e.clientY; initialX = panel.offsetLeft; initialY = panel.offsetTop; }; document.onmousemove = (e) => { if (!isDragging) return; panel.style.left = (initialX + e.clientX - startX) + 'px'; panel.style.top = (initialY + e.clientY - startY) + 'px'; panel.style.right = 'auto'; }; document.onmouseup = () => isDragging = false; // 初始启动题目监控 setTimeout(() => { const course = document.getElementById('tk-course')?.value?.trim(); if (course) watchForQuestions(course); }, 3000); } function updateCloudUI() { const el = document.getElementById('tk-cloud-courses'); if (!el) return; if (cloudIndex) { el.textContent = `${cloudIndex.courses?.length || 0} 门 · ${Object.values(cloudIndex.count || {}).reduce((a,b)=>a+b,0) || 0} 题`; } else { el.textContent = '连接失败'; } } function qlog(msg) { if(!logArea) return; logArea.value += `[${new Date().toLocaleTimeString()}] ${msg}\n`; logArea.scrollTop = logArea.scrollHeight; } function updateStats(count) { if(countSpan) countSpan.innerText = count; } // ========================================== // 4. 导出逻辑 // ========================================== function exportTXT() { const db = getDB(); if(db.length === 0) return alert("题库为空!"); let txtContent = ""; db.forEach((q) => { txtContent += `【${q.type}】题目:${q.content}\n`; if ((q.type === "单选题" || q.type === "多选题") && q.options && q.options.length > 0) { q.options.forEach(opt => { if (opt.alias && opt.text) txtContent += `${opt.alias}. ${opt.text}\n`; }); } txtContent += `答案:${q.answer}\n\n`; }); const blob = new Blob([txtContent], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.setAttribute("href", url); link.setAttribute("download", `党校题库_${db.length}题.txt`); document.body.appendChild(link); link.click(); document.body.removeChild(link); qlog(`导出 TXT 成功。`); } function exportJSON() { const db = getDB(); if(db.length === 0) return alert("题库为空!"); const blob = new Blob([JSON.stringify(db, null, 4)], { type: 'application/json;charset=utf-8' }); const link = document.createElement("a"); link.href = URL.createObjectURL(blob); link.download = `党校题库_${db.length}题.json`; link.click(); qlog(`导出 JSON 成功。`); } function exportCSV() { const db = getDB(); if(db.length === 0) return alert("题库为空!"); let csvContent = "题型,题目,选项,正确答案\n"; db.forEach(q => { let optStr = q.options.map(o => `${o.alias}. ${o.text}`).join(" | "); csvContent += `"${q.type}","${q.content.replace(/"/g, '""')}","${optStr.replace(/"/g, '""')}","${String(q.answer).replace(/"/g, '""')}"\n`; }); const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8' }); const link = document.createElement("a"); link.href = URL.createObjectURL(blob); link.download = `党校题库_${db.length}题.csv`; link.click(); qlog(`导出 CSV 成功。`); } // ========================================== // 5. DOM 启发式扫描器 // ========================================== function scanDOMForQuestions() { qlog("开始深度扫描当前网页元素..."); let foundQuestions = []; const allElements = document.querySelectorAll('*'); let rawDataSources = []; for (let el of allElements) { if (el.__vue__) { try { let vueData = JSON.parse(JSON.stringify(el.__vue__.$data || {})); rawDataSources.push(vueData); } catch(e){} } } if (rawDataSources.length > 0) { rawDataSources.forEach(data => { let extracted = extractQuestionsFromData(data); foundQuestions = foundQuestions.concat(extracted); }); } if (foundQuestions.length > 0) { let added = saveToDB(foundQuestions); qlog(`DOM底层数据扫描完成,找到有效题目,新入库 ${added} 题!`); // 自动贡献到云端 const course = document.getElementById('tk-course')?.value?.trim(); if (course && added > 0) { contributeToCloud(course, foundQuestions); } } else { qlog("未能从当前页面的底层数据中扫描到规范题库。"); qlog("提示:如果页面显示了题目,建议通过『高级API接口』重新请求该页面的数据源。"); } } // ========================================== // 6. 高级 API 挖掘器 // ========================================== async function sendCustomApiRequest() { let method = document.getElementById('tk-api-method').value; let url = document.getElementById('tk-api-url').value.trim(); let body = document.getElementById('tk-api-body').value.trim(); if (!url) return alert("请输入要挖掘的接口路径!"); if (!url.startsWith('http')) { if (!url.startsWith('/')) url = '/' + url; url = window.location.origin + url; } qlog(`[挖掘机] 正在向 ${url} 发送 ${method} 请求...`); try { let options = { method: method, headers: { "Accept": "application/json, text/plain, */*", "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" } }; if (method === 'POST' && body) options.body = body; let response = await fetch(url, options); if (!response.ok) { qlog(`[挖掘机] 请求失败,HTTP状态码: ${response.status}`); return; } let resJson = await response.json(); let qList = extractQuestionsFromData(resJson); if (qList.length > 0) { let added = saveToDB(qList); qlog(`🎯 [挖掘机] 挖掘成功!发现 ${qList.length} 题,新入库 ${added} 题!`); // 自动贡献到云端 const course = document.getElementById('tk-course')?.value?.trim(); if (course && qList.length > 0) { contributeToCloud(course, qList); } } else { qlog(`[挖掘机] 接口请求成功,但返回的数据中没有识别到题目特征。`); console.qlog("挖掘返回原始数据:", resJson); } } catch (e) { qlog(`❌ [挖掘机] 请求异常: ${e.message}`); } } // ========================================== // 7. 错题本自动拉取 // ========================================== async function autoPullErrors() { qlog("开始全量拉取错题本..."); const course = document.getElementById('tk-course')?.value?.trim(); let current = 1; let totalPages = 1; let allRecords = []; while (current <= totalPages) { try { let res = await fetch("/api/student/test/myErrorQuestion/list", { method: 'POST', headers: { "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json" }, body: `current=${current}&size=100&keyword=` }); let resJson = await res.json(); if (resJson.code === 0 && resJson.data) { totalPages = resJson.data.pages || 1; let records = resJson.data.records || []; if(records.length > 0){ allRecords = allRecords.concat(records); let added = saveToDB(records); qlog(`错题本第${current}页:新入库 ${added} 题。`); } else break; } else break; current++; await new Promise(r => setTimeout(r, 600)); } catch (e) { break; } } qlog("错题本全量拉取完成!"); // 自动贡献到云端 if (course && allRecords.length > 0) { const normQuestions = allRecords.map(r => normalizeQuestion(r)).filter(Boolean); contributeToCloud(course, normQuestions); } } // ========================================== // 8. 网络拦截双引擎(增强:自动贡献云端) // ========================================== const courseInput = () => document.getElementById('tk-course')?.value?.trim(); // XHR 拦截 const originalXHR = window.XMLHttpRequest; window.XMLHttpRequest = function() { const xhr = new originalXHR(); xhr.addEventListener('load', function() { try { if (this.responseURL && this.responseURL.includes('/api/')) { let resData = this.responseType === 'json' ? this.response : JSON.parse(this.responseText); if (resData) { let qList = extractQuestionsFromData(resData); let added = saveToDB(qList); if (added > 0) { qlog(`[XHR拦截] 自动抓取入库 ${added} 题。`); const course = courseInput(); if (course) contributeToCloud(course, qList); } } } } catch (e) {} }); return xhr; }; // Fetch 拦截 const originalFetch = window.fetch; window.fetch = async function(...args) { const response = await originalFetch.apply(this, args); const cloneRes = response.clone(); cloneRes.json().then(resData => { try { let url = typeof args[0] === 'string' ? args[0] : (args[0] && args[0].url ? args[0].url : ''); if (url.includes('/api/')) { let qList = extractQuestionsFromData(resData); let added = saveToDB(qList); if (added > 0) { qlog(`[Fetch拦截] 自动抓取入库 ${added} 题。`); const course = courseInput(); if (course) contributeToCloud(course, qList); } } } catch(e) {} }).catch(() => {}); return response; }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initPanel); } else { initPanel(); } })();