// ==UserScript== // @name 2026年5月广东省教师继续教育专业课、公需课-自动学习、答题 // @namespace auto-study-gds // @version 3.2 // @description 自动播放课程视频、自动切换下一节、自动答题、防挂机检测 // @match https://jsxx.gds.edu.cn/study/course/* // @match https://jsglpt.gds.edu.cn/study/course/* // @match https://jsxx.gds.edu.cn/*/study/course/* // @match https://jsglpt.gds.edu.cn/*/study/course/* // @grant none // @run-at document-idle // ==/UserScript== (function () { 'use strict'; // ============ 配置 ============ var CONFIG = { VIDEO_CHECK_INTERVAL: 5000, // 每5秒检查视频 MOUSE_MOVE_INTERVAL: 15000, // 每15秒移动鼠标 SCROLL_INTERVAL: 25000, // 每25秒微滚动 SAFE_CLICK_INTERVAL: 45000, // 每45秒安全点击 QUIZ_CHECK_INTERVAL: 2000, // 每2秒检查答题弹窗 NEXT_VIDEO_DELAY: 10000, // 视频结束10秒后切换 RESUME_RETRIES: 3, // 恢复播放重试次数 INIT_DELAY: 3000, // 页面加载后等待3秒 MAX_LOG_LENGTH: 200, // 日志最大条数 }; // 课程ID var COURSE_ID = (function () { var m = location.pathname.match(/c_([a-f0-9]{32})/i); return m ? 'c_' + m[1] : null; })(); // ============ 日志 ============ var LOG = []; function log(msg, type) { type = type || 'info'; var ts = new Date().toLocaleTimeString(); var prefix = { info: 'INF', warn: 'WRN', error: 'ERR', quiz: 'QUIZ', video: 'VID' }; var line = '[' + ts + '] [' + (prefix[type] || 'INF') + '] ' + msg; console.log('[AutoStudy] ' + line); LOG.push(line); if (LOG.length > CONFIG.MAX_LOG_LENGTH) LOG.shift(); updatePanelStatus(type + ': ' + msg); } // ============ 状态浮窗 ============ var panelCreated = false; function createStatusPanel() { if (panelCreated || document.getElementById('_asp')) return; panelCreated = true; var panel = document.createElement('div'); panel.id = '_asp'; panel.style.cssText = 'position:fixed;top:10px;right:10px;z-index:999999;' + 'background:rgba(0,0,0,0.88);color:#0f0;padding:10px 14px;border-radius:8px;' + 'font-size:12px;font-family:Consolas,monospace;width:320px;' + 'box-shadow:0 2px 12px rgba(0,0,0,0.4);user-select:none;'; panel.innerHTML = '
AutoStudy v3.0
' + '
等待视频...
' + '' + '
' + '
' + '' + '' + '' + '
'; document.body.appendChild(panel); // 暂停/继续 document.getElementById('_aspToggle').onclick = function () { window._autoStudyPaused = !window._autoStudyPaused; this.textContent = window._autoStudyPaused ? '继续' : '暂停'; this.style.background = window._autoStudyPaused ? '#533' : '#333'; log(window._autoStudyPaused ? '脚本已暂停' : '脚本已继续', 'warn'); }; // 手动下一节 document.getElementById('_aspNext').onclick = function () { log('手动切换下一节', 'warn'); forceGoToNextVideo(); }; // 显示/隐藏日志 var logVisible = false; document.getElementById('_aspLogToggle').onclick = function () { logVisible = !logVisible; var logEl = document.getElementById('_aspLog'); logEl.style.display = logVisible ? 'block' : 'none'; logEl.style.maxHeight = logVisible ? '200px' : '60px'; if (logVisible) { logEl.textContent = LOG.slice(-20).join('\n'); } }; } function updatePanelStatus(msg) { var el = document.getElementById('_aspLog'); if (el && el.style.display !== 'none') { el.textContent = LOG.slice(-20).join('\n'); } } function updateVideoDisplay() { var v = getVideo(); var el = document.getElementById('_aspVideo'); if (!el) return; if (!v || !v.duration) { el.textContent = '等待视频加载...'; return; } var cur = formatTime(v.currentTime); var dur = formatTime(v.duration); var pct = (v.currentTime / v.duration * 100).toFixed(1); var state = v.paused ? ' || PAUSED' : v.ended ? ' || ENDED' : ' || PLAYING'; el.textContent = cur + '/' + dur + ' (' + pct + '%)' + state; // 标题 var titleEl = document.getElementById('_aspTitle'); if (titleEl) { var h3 = document.querySelector('.g-studyAct-box h3'); var name = h3 ? h3.textContent.trim().substring(0, 28) : '未知'; titleEl.textContent = 'AutoStudy - ' + name; } } // ============ 防挂机 ============ function spoofVisibility() { try { Object.defineProperty(document, 'hidden', { get: function () { return false; }, configurable: true }); } catch (e) { } try { Object.defineProperty(document, 'visibilityState', { get: function () { return 'visible'; }, configurable: true }); } catch (e) { } // 阻止 visibilitychange / blur 事件 ['visibilitychange', 'webkitvisibilitychange'].forEach(function (evtName) { document.addEventListener(evtName, function (e) { e.stopImmediatePropagation(); }, true); }); window.addEventListener('blur', function (e) { e.stopImmediatePropagation(); }, true); log('页面可见性伪装已启用'); } // ============ 鼠标模拟 ============ function simulateMouseMove(x, y) { var el = document.elementFromPoint(x, y); ['mouseenter', 'mouseover', 'mousemove'].forEach(function (type) { var evt = new MouseEvent(type, { clientX: x, clientY: y, bubbles: true, cancelable: true, view: window }); if (el) el.dispatchEvent(evt); document.dispatchEvent(evt); }); } function simulateSafeClick(x, y) { var el = document.elementFromPoint(x, y); if (!el) return; var tag = el.tagName.toLowerCase(); if (['video', 'input', 'select', 'textarea', 'a', 'button'].indexOf(tag) >= 0) return; if (el.closest('video, input, select, textarea, a.btn, button')) return; ['mousedown', 'mouseup', 'click'].forEach(function (type) { el.dispatchEvent(new MouseEvent(type, { clientX: x, clientY: y, bubbles: true, cancelable: true, button: 0 })); }); } // ================================================================ // 自动答题模块 // 弹窗结构: .mylayer-layer > .mylayer-content > #questionDiv +