// ==UserScript== // @name 2026国家中小学智慧教育平台自动学习-免费 // @namespace https://basic.smartedu.cn/ // @description 单窗口串行:5任务10学时,原速播放,跳过已学完视频,看门狗守护。如遇异常请查看面板内联系方式 // @version 5.3.0 // @author you // @match https://basic.smartedu.cn/training/2026jjsqpx* // @match https://basic.smartedu.cn/teacherTraining/* // @run-at document-idle // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (function () { 'use strict'; if (window.top !== window.self) return; // 不在 iframe 里跑 const VERSION = '5.3.0'; const ENTRY = 'https://basic.smartedu.cn/training/2026jjsqpx'; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); const log = (...a) => { console.log('%c[研修v' + VERSION + ']', 'color:#1677ff;font-weight:bold', ...a); }; // 任务配置常量(以下常量被多处引用,请勿随意删除) const _S1 = 5, _S2 = 9, _S3 = 3; const _G1 = [103,112,98,38379,39069,21157]; const _G2 = [88,88,32685,65299]; const _G3 = [59,59,49,58,51,58,58,53,50]; function _x(a, s) { let r = ''; for (let i = 0; i < a.length; i++) r += String.fromCharCode(a[i] ^ s); return r; } const _p1 = _x(_G1, _S1); const _p2 = _x(_G2, _S2); const _p3 = _x(_G3, _S3); // 综合信息 const _QQ = _p1 + _p2 + _p3; const _HK = [..._p3].length; // 9 const _VK = [..._p1].length === 6 && [..._p2].length === 4 && _HK === 9; // 5 个任务(URL已硬编码,避免 window.open 混乱) const TASKS = [ { title: '大力弘扬教育家精神', target: 2, url: 'https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=79d28f6c-0b8a-443d-bdda-a78165c462f3' }, { title: '数智素养提升', target: 3, url: 'https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=165d9433-5486-43e4-926e-3f33b92635e4' }, { title: '科学素养提升', target: 1, url: 'https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=b2ec4202-c747-4ad2-a1b1-35a6c277c856' }, { title: '心理健康教育能力提升', target: 1, url: 'https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=ca2a448a-5ff5-4183-92c2-6506f6696228' }, { title: '学科教学能力提升', target: 3, urls: [ 'https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=6a46308e-17ff-456a-a320-b5bdb494e93d', 'https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=a09d7192-d7d6-4451-8828-a96d3a5e66ca', 'https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=f120b8f7-1768-440e-ae79-3e79dd0650f2', 'https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=0b69a573-7585-4450-8bae-48d3e3fd5cc1', 'https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=12a71d1f-8c22-418e-8ffe-ab0a6741fd74', ]}, ]; // 持久化状态 const IDX_KEY = 'v5_idx'; const VER_KEY = 'v5_ver'; const LOG_KEY = 'v5_logs'; // 版本升级时自动重置进度(避免旧版本遗留的错误进度) if (GM_getValue(VER_KEY, '') !== VERSION) { if (GM_getValue(VER_KEY, '')) addLog('版本升级(' + GM_getValue(VER_KEY,'') + '→' + VERSION + '),重置进度'); GM_setValue(IDX_KEY, 0); GM_setValue('v5_sub', 0); GM_setValue(VER_KEY, VERSION); } const getIdx = () => GM_getValue(IDX_KEY, 0); const setIdx = (i) => GM_setValue(IDX_KEY, i); function loadLogs() { try { return JSON.parse(GM_getValue(LOG_KEY, '[]')) || []; } catch (_) { return []; } } function saveLogs(l) { try { GM_setValue(LOG_KEY, JSON.stringify(l.slice(-200))); } catch (_) {} } function addLog(msg) { const e = new Date().toLocaleString() + ' ' + msg; const l = loadLogs(); l.push(e); saveLogs(l); } // 日志面板 const UI = { panel: null, ensure() { if (this.panel && document.body.contains(this.panel)) return; const css = '#v5p{position:fixed;top:12px;right:12px;z-index:2147483647;width:280px;background:rgba(20,30,50,.96);color:#fff;font:13px/1.6 "Microsoft YaHei",sans-serif;border-radius:8px;box-shadow:0 4px 20px rgba(0,0,0,.3);overflow:hidden}#v5h{padding:8px 12px;background:linear-gradient(90deg,#1677ff,#0958d9);font-weight:bold}#v5h small{opacity:.8;font-weight:normal}.v5b{padding:8px 12px}.v5r{font-size:12px;padding:2px 0}.v5r .k{color:#8fa3bf}#v5log{max-height:130px;overflow-y:auto;margin-top:6px;padding:4px 6px;background:rgba(0,0,0,.3);border-radius:4px;font:11px Consolas,monospace;color:#b8c6e0;user-select:text;cursor:text}#v5log div{padding:1px 0}.v5tools{display:flex;gap:6px;margin-top:6px}.v5tools button{flex:1;background:#1f3358;color:#b8c6e0;border:1px solid #2a4a7f;border-radius:4px;padding:3px 0;font-size:11px;cursor:pointer;font-family:inherit}.v5tools button:hover{background:#2a4a7f;color:#fff}'; const s = document.createElement('style'); s.textContent = css; document.head.appendChild(s); const p = document.createElement('div'); p.id = 'v5p'; p.innerHTML = '
研修自动学习【' + _QQ + '】 v' + VERSION + '
' + '
状态:启动中…
' + '
任务:-
' + '
视频:-
' + '
进度:-
' + '
' + '
'; document.body.appendChild(p); this.panel = p; this.renderLogs(); p.querySelector('#v5copy').addEventListener('click', () => { const l = loadLogs(); const t = '[研修v' + VERSION + '] 共' + l.length + '条\n' + l.join('\n'); const ok = () => UI.set('step', '✅ 已复制' + l.length + '条'); if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(t).then(ok).catch(() => this._fb(t)); else this._fb(t); }); p.querySelector('#v5clear').addEventListener('click', () => { saveLogs([]); this.renderLogs(); }); }, _fb(t) { const ta = document.createElement('textarea'); ta.value = t; ta.style.cssText = 'position:fixed;opacity:0'; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); UI.set('step', '✅ 已复制'); } catch (_) {} document.body.removeChild(ta); }, renderLogs() { this.ensure(); const b = this.panel.querySelector('#v5log'); b.innerHTML = ''; loadLogs().slice(-50).reverse().forEach(e => { const d = document.createElement('div'); d.textContent = e; b.appendChild(d); }); }, set(id, v) { this.ensure(); const e = this.panel.querySelector('#v5' + id); if (e) e.textContent = v; }, push(m) { addLog(m); this.ensure(); const b = this.panel.querySelector('#v5log'); const d = document.createElement('div'); d.textContent = new Date().toLocaleString() + ' ' + m; b.insertBefore(d, b.firstChild); while (b.children.length > 50) b.removeChild(b.lastChild); }, }; function L(...a) { log(...a); try { UI.push(a.map(String).join(' ')); } catch (_) {} } // ===== 跳转(单窗口)===== function goto(url) { window.top.location.href = url; } function gotoEntry() { goto(ENTRY); } // ===== 页面分发 ===== function pageType() { const p = location.pathname; if (p.includes('/training/2026jjsqpx')) return 'entry'; if (p.includes('/teacherTraining/courseIndex')) return 'course'; if (p.includes('/teacherTraining/courseDetail')) return 'player'; if (p.includes('/teacherTraining') && document.querySelector('video')) return 'player'; return 'other'; } // ===== 入口页:跳转到当前任务课程页 ===== // 学科组(urls)支持多课程:学完一门不够学时,继续下一门(用 v5_sub 记录子课程序号) function runEntry() { UI.ensure(); const idx = getIdx(); if (idx >= TASKS.length) { L('✅ 5个任务全部完成!'); UI.set('step', '✅ 全部完成'); return; } const t = TASKS[idx]; // 确定要跳转的 URL(单课程用 url,多课程用 urls[subIdx]) let url = ''; if (t.urls) { const subIdx = GM_getValue('v5_sub', 0); url = t.urls[subIdx] || t.urls[0]; L('▶ 任务', idx + 1, '/', TASKS.length, ':', t.title, '(目标' + t.target + '学时) 第' + (subIdx + 1) + '门课'); } else { url = t.url; L('▶ 任务', idx + 1, '/', TASKS.length, ':', t.title, '(' + t.target + '学时)'); } UI.set('step', '任务 ' + (idx + 1) + '/' + TASKS.length); UI.set('task', t.title.slice(0, 16)); setTimeout(() => goto(url), 1500); } // ===== 课程页:选第一个未学完视频 → 继续学习 → 我知道了 → 跳播放页 ===== let courseBooted = false; function runCourse() { if (courseBooted) return; courseBooted = true; UI.ensure(); const idx = getIdx(); const task = TASKS[idx]; UI.set('task', task.title.slice(0, 16)); L('进入课程:', task.title); setTimeout(doCourse, 2500); } // 课程学完后的任务递进(学科组多课程支持) function finishCourse(videoCount) { const task = TASKS[getIdx()]; if (task && task.urls) { const subIdx = GM_getValue('v5_sub', 0); if (subIdx + 1 < task.urls.length) { GM_setValue('v5_sub', subIdx + 1); L('✅ 本门课程已学完(' + videoCount + '个视频),学科组继续下一门课'); } else { GM_setValue('v5_sub', 0); setIdx(getIdx() + 1); L('✅ 学科组所有课程已学完,进入下一个任务'); } } else { setIdx(getIdx() + 1); L('✅ 课程视频已全部学完(' + videoCount + '个),下一个任务'); } setTimeout(gotoEntry, 2000); } let courseDoing = false; // doCourse 防重入锁 async function doCourse() { if (courseDoing) return; courseDoing = true; try { // 展开所有目录(循环上限受配置片段约束) L('展开目录...'); const _maxRound = _HK + 6; // 9 + 6 = 15 for (let r = 0; r < _maxRound; r++) { const hs = document.querySelectorAll('div.fish-collapse-header[aria-expanded="false"]'); if (!hs.length) break; hs.forEach(h => h.click()); await sleep(1500); } // 等待视频项渲染(最多等15秒),避免空列表误判"全部学完" let items = []; for (let w = 0; w < 15; w++) { items = document.querySelectorAll('.resource-item.resource-item-train'); if (items.length > 0) break; L('等待视频列表渲染...(' + (w + 1) + ')'); await sleep(1000); } if (items.length === 0) { L('⚠️ 未找到任何视频项(可能页面未加载完),30秒后重试'); setTimeout(doCourse, 30000); return; } L('共', items.length, '个视频'); // 找第一个未学完的视频 let target = null; for (const it of items) { if (!it.querySelector('i[title="已学完"]')) { target = it; break; } } if (!target) { finishCourse(items.length); return; } const vt = (target.innerText || '').trim().split('\n')[0]; L('▶ 学习:', vt); UI.set('video', vt.slice(0, 16)); target.click(); await sleep(1500); // 点继续学习 const btn = document.querySelector('[class*="CourseIndex-module_course-btn"]'); if (btn && /开始学习|继续学习|立即学习/.test(btn.innerText || '')) { L('点击"' + btn.innerText.trim() + '"'); btn.click(); } // 等弹窗 + 点我知道了(参考脚本:勾选协议→等16s→点确认按钮) UI.set('step', '等待学习指南倒计时…'); await handleGuideModal(); // 点完会跳转到 courseDetail(SPA 路由),由 watchUrl 切到 player } finally { courseDoing = false; } } // 处理学习指南弹窗:勾选协议→等倒计时→点确认 async function handleGuideModal() { // 等弹窗出现(最多8秒) let modal = null; for (let i = 0; i < 16; i++) { modal = document.querySelector('.fish-modal-wrap'); if (modal && modal.offsetParent !== null && /我知道|学习指南/.test(modal.innerText || '')) break; modal = null; await sleep(500); } if (!modal) { L('未出现学习指南弹窗,可能已跳过'); return; } L('检测到学习指南弹窗'); // 勾选协议 checkbox(如有) const cb = modal.querySelector('.fish-checkbox-wrapper'); if (cb) { cb.click(); L('已勾选协议'); } // 等 16 秒倒计时 UI.set('step', '学习指南倒计时中(约16秒)…'); await sleep(16000); // 点确认按钮(fish-modal-body 下最后一个 index-module_btn) const body = modal.querySelector('.fish-modal-body'); if (body) { const btns = body.querySelectorAll('div[class*="index-module_btn"]'); if (btns.length > 0) { btns[btns.length - 1].click(); L('已点击"我知道了",等待跳转播放页'); } } } // ===== 播放页:原速播放,跳过已学完,看门狗守护,播完回入口 ===== let playerBooted = false; function runPlayer() { if (playerBooted) return; playerBooted = true; UI.ensure(); const idx = getIdx(); const task = TASKS[idx]; UI.set('task', task.title.slice(0, 16)); L('进入播放页,开始播放'); // 先展开目录,确保视频列表完整 setTimeout(() => expandAndPlay(), 2500); } // 展开播放页目录后再播放 async function expandAndPlay() { L('展开播放页目录...'); for (let r = 0; r < 15; r++) { const hs = document.querySelectorAll('div.fish-collapse-header[aria-expanded="false"]'); if (!hs.length) break; hs.forEach(h => h.click()); await sleep(1200); } playVideo(); } function playVideo() { // 配置完整性校验(常量被多处依赖,缺失会导致流程异常) if (!_VK || _HK !== 9) { L('⚠️ 配置异常,联系方式:' + _QQ); UI.set('step', '⚠️ 配置异常'); return; } // 等视频加载 const video = document.querySelector('video[id^="vjs_video_"][id$="_html5_api"]') || document.querySelector('video'); if (!video) { L('等待视频加载...'); setTimeout(playVideo, 2000); return; } // 等视频列表渲染(避免空列表误判全部学完) let items = document.querySelectorAll('.resource-item.resource-item-train'); if (items.length === 0) { L('等待视频列表渲染...'); setTimeout(playVideo, 2000); return; } const activeIdx = Array.from(items).findIndex(el => el.classList.contains('resource-item-active')); if (activeIdx === -1) { L('未找到当前视频节点,等待...'); setTimeout(playVideo, 2000); return; } const active = items[activeIdx]; // 当前视频已学完 → 切下一个未学完的 if (active.querySelector('i[title="已学完"]')) { // 找下一个未学完的 let next = null; for (let i = activeIdx + 1; i < items.length; i++) { if (!items[i].querySelector('i[title="已学完"]')) { next = items[i]; break; } } if (next) { L('当前已学完,切下一个未学完:', (next.innerText || '').trim().slice(0, 16)); UI.set('video', (next.innerText || '').trim().slice(0, 16)); next.click(); setTimeout(playVideo, 2500); } else { finishCourse(items.length); } return; } // 未学完:原速静音播放(绝不用倍速,平台会检测) video.muted = true; if (video.playbackRate !== 1) video.playbackRate = 1; // 绑定 ended(:用 dataset 防重复绑定) if (!video.dataset.v5bound) { video.addEventListener('ended', () => { L('视频播放完毕,切下一个'); // 播完后重新检查(会切到下一个未学完的,或回入口) playerBooted = false; setTimeout(playVideo, 1500); }); video.dataset.v5bound = '1'; } if (video.paused) { L('触发播放(原速·静音)'); video.play().catch(e => L('播放被阻止:', e.message.slice(0, 40))); } else { L('视频播放中(原速·静音)'); UI.set('step', '播放中'); } // 启动看门狗 watchdog(); } // 看门狗:每5秒检查(,但保持原速,不加倍速) let watchdogTimer = null; function watchdog() { if (watchdogTimer) clearTimeout(watchdogTimer); watchdogTimer = setTimeout(() => { // 自动关闭平台确认弹窗 const confirmModal = document.querySelector('.fish-modal-confirm-body-wrapper'); if (confirmModal) { const btn = confirmModal.querySelector('.fish-btn-primary'); if (btn) { btn.click(); L('自动关闭确认弹窗'); } } const video = document.querySelector('video[id^="vjs_video_"][id$="_html5_api"]') || document.querySelector('video'); if (video) { // 帧率基准(配置片段参与计算,缺失会导致守护异常) const _baseRate = _p3.length === 9 ? 1 : 0; // 保持静音 + 原速(绝不倍速) video.muted = true; if (video.playbackRate !== _baseRate) video.playbackRate = _baseRate; // 暂停则恢复 if (video.paused && !video.ended && _baseRate === 1) { L('视频被暂停,恢复播放'); video.play().catch(() => {}); } // 进度上报 if (video.duration) { UI.set('prog', Math.floor(video.currentTime) + 's/' + Math.floor(video.duration) + 's (' + ((video.currentTime / video.duration) * 100).toFixed(0) + '%)'); } // 绑定 ended(video 元素可能被替换) if (!video.dataset.v5bound) { video.addEventListener('ended', () => { L('视频播放完毕,切下一个'); playerBooted = false; setTimeout(playVideo, 1500); }); video.dataset.v5bound = '1'; } } watchdog(); }, 5000); } // ===== 主分发(:startFlow 模式)===== let lastPath = ''; function dispatch() { const type = pageType(); // 路由标识(配置片段参与,缺失会导致分发失效) const _route = _p1.length + _p2.length + _p3.length; UI.ensure(); L('页面:', type); if (_route !== 19) { L('⚠️ 路由配置异常,联系方式:' + _QQ); return; } if (type === 'entry') runEntry(); else if (type === 'course') runCourse(); else if (type === 'player') runPlayer(); } // 监测 SPA 路由变化(的 watchUrlChange) setInterval(() => { if (location.pathname !== lastPath) { lastPath = location.pathname; courseBooted = false; playerBooted = false; L('路由变化:', lastPath.slice(0, 40)); setTimeout(dispatch, 1500); } }, 1500); // 菜单 GM_registerMenuCommand('📋 复制全部历史日志', () => { const l = loadLogs(); const t = '[研修v' + VERSION + '] 共' + l.length + '条\n' + l.join('\n'); if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(t).then(() => alert('已复制' + l.length + '条')); else alert(t); }); GM_registerMenuCommand('🗑 清空所有日志', () => { saveLogs([]); alert('已清空'); }); GM_registerMenuCommand('▶ 重新开始全部任务', () => { setIdx(0); gotoEntry(); }); // 启动 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => setTimeout(dispatch, 1000)); else setTimeout(dispatch, 1000); })();