// ==UserScript== // @name 生态环境云课堂自动学习助手 // @namespace http://onlinelearning.21tb.com/ // @version 3.1 // @description 全国生态环境执法培训云课堂全自动学习:学完一门自动切下一门必修,自动关弹窗、自动播放切章节、自动答完题,静音后台运行 // @author study_bot // @match *://onlinelearning.21tb.com/* // @grant none // @run-at document-idle // @noframes // @tag 教育,学习,自动化,网课,云课堂 // @license MIT // ==/UserScript== (function() { 'use strict'; const CONFIG = { checkInterval: 5000, actionCooldown: 12000, }; const state = { lastActionTime: 0, visitedCourses: new Set(JSON.parse(localStorage.getItem('visitedCourses') || '[]')), }; function log(msg) { console.log(`[自动学习v3.1] ${new Date().toLocaleTimeString()} | ${msg}`); } function closePopups() { try { document.querySelectorAll('.el-dialog__close, .el-message-box__close, .close-btn, .el-icon-close').forEach(b => b.click()); } catch(e) {} } function playVideo() { try { document.querySelectorAll('video').forEach(v => { v.muted = true; v.volume = 0; v.playbackRate = 1; if (v.paused) v.play().catch(()=>{}); }); } catch(e) {} } // 首页自动进我的课程 function goCourseList() { const now = Date.now(); if (now - state.lastActionTime < CONFIG.actionCooldown) return; try { if (location.pathname.includes('/student/index')) { const btn = [...document.querySelectorAll('a, div, span')].find(el => el.innerText?.trim() === '我的课程' && el.offsetParent); if (btn) { log('进入我的课程'); btn.click(); state.lastActionTime = now; } } } catch(e) {} } // 课程列表自动选未学必修 function pickNextCourse() { const now = Date.now(); if (now - state.lastActionTime < CONFIG.actionCooldown) return; try { if (!location.href.includes('course_manage_user_pc')) return; const cards = [...document.querySelectorAll('[class*=card], [class*=item]')]; for (let c of cards) { const t = c.innerText || ''; if (t.includes('必修') && !t.includes('已完成') && !t.includes('100%') && !state.visitedCourses.has(t.slice(0,20))) { log('点击未学必修: ' + t.split('\n')[0]); c.click(); state.visitedCourses.add(t.slice(0,20)); localStorage.setItem('visitedCourses', JSON.stringify([...state.visitedCourses])); state.lastActionTime = now; return; } } } catch(e) {} } // 播放页切下一节 function nextSection() { const now = Date.now(); if (now - state.lastActionTime < CONFIG.actionCooldown) return; try { if (!location.href.includes('courseLearning/play')) return; const nextBtn = [...document.querySelectorAll('button, div')].find(el => el.innerText?.trim() === '下一节' && el.offsetParent); if (nextBtn) { log('点下一节'); nextBtn.click(); state.lastActionTime = now; return; } // 找未完成章节点 const unDone = [...document.querySelectorAll('span, div')].filter(el => el.innerText?.trim() === '未完成' && el.offsetParent); for (let el of unDone) { let p = el.parentElement; for (let i=0;i<6;i++) { if (!p) break; if (p.tagName === 'LI' || p.tagName === 'A') { p.click(); state.lastActionTime = now; log('点未完成章节'); return; } p = p.parentElement; } } // 当前课程所有章节学完,自动回课程列表选下一门 const noNext = [...document.querySelectorAll('button')].find(b => b.innerText?.includes('下一节') && b.disabled); if (noNext || document.body.innerText.includes('本课程学习完成')) { log('当前课程已学完,返回课程列表'); history.back(); state.lastActionTime = now; } } catch(e) {} } // 自动答题 async function answerQuiz() { try { const qs = document.querySelectorAll('[class*=question]'); if (!qs.length) return; log(`检测到${qs.length}题,开始作答`); for (let q of qs) { const opts = q.querySelectorAll('label, .option, .el-radio, .el-checkbox'); const unsel = [...opts].filter(o => !o.classList.contains('is-checked')); if (unsel.length) { unsel[Math.floor(Math.random()*unsel.length)].click(); await new Promise(r=>setTimeout(r,200)); } } await new Promise(r=>setTimeout(r,1000)); const allDone = [...qs].every(q => q.querySelectorAll('.is-checked').length > 0); if (allDone) { const submit = [...document.querySelectorAll('button')].find(b => b.innerText?.includes('提交')); if (submit) { submit.click(); log('所有题答完提交'); } } } catch(e) {} } async function loop() { closePopups(); playVideo(); goCourseList(); pickNextCourse(); nextSection(); if (document.body.innerText.includes('单选题')) await answerQuiz(); setTimeout(loop, CONFIG.checkInterval); } log('v3.1启动:学完一门自动切下一门必修'); setTimeout(loop, 3000); })();