// ==UserScript== // @name 生态环境云课堂自动学习助手 // @namespace http://onlinelearning.21tb.com/ // @version 3.5 // @description 全国生态环境执法培训云课堂全自动学习:递归遍历iframe、精准关弹窗、自动循环学完所有必修、静音后台运行、全答完再提交 // @author study_bot // @match *://onlinelearning.21tb.com/* // @grant none // @run-at document-idle // @tag 教育,学习,自动化,网课,云课堂 // ==/UserScript== (function() { 'use strict'; const CONFIG = { checkInterval: 4000, actionCooldown: 15000 }; const state = { lastActionTime: 0, visitedCourses: new Set(JSON.parse(localStorage.getItem('visitedCourses') || '[]')) }; function log(msg) { console.log(`[自动学习v3.5] ${new Date().toLocaleTimeString()} | ${msg}`); } // 递归获取所有frame文档 function getAllDocs() { const docs = [document]; document.querySelectorAll('iframe').forEach(fr => { try { if (fr.contentDocument) docs.push(fr.contentDocument); } catch(e) {} }); return docs; } // 1. 精准关闭所有弹窗 function closePopups() { getAllDocs().forEach(doc => { try { // 通知弹窗关闭按钮 doc.querySelectorAll('button[aria-label="Close"], .el-dialog__close, .modal-close, .el-icon-close, button:has-text("关闭窗口")').forEach(btn => { if (btn.offsetParent) { btn.click(); log('关闭弹窗'); } }); // 点遮罩层 const modals = doc.querySelectorAll('.el-dialog__wrapper, .el-overlay'); modals.forEach(m => { if (getComputedStyle(m).display !== 'none') m.click(); }); } catch(e) {} }); } // 2. 静音播放所有视频 function playVideo() { getAllDocs().forEach(doc => { doc.querySelectorAll('video').forEach(v => { v.muted = true; v.volume = 0; v.playbackRate = 1.0; if (v.paused) v.play().catch(()=>{}); }); }); } // 3. 在课程列表页选未完成的必修课 function pickNextCourse() { const now = Date.now(); if (now - state.lastActionTime < CONFIG.actionCooldown) return; getAllDocs().forEach(doc => { try { if (!doc.location.href.includes('course_manage_user_pc')) return; // 所有课程卡片按钮 const cards = [...doc.querySelectorAll('button')].filter(b => b.innerText && b.offsetParent); for (let c of cards) { const t = c.innerText; // 条件:是必修课、0%/未完成、不是已完成、没学过 if (t.includes('必修') && !t.includes('已完成') && (t.includes('0.0%') || t.includes('未学习')) && !state.visitedCourses.has(t.slice(0,30))) { log('点未学必修课: ' + t.split('\n')[0]); c.click(); state.visitedCourses.add(t.slice(0,30)); localStorage.setItem('visitedCourses', JSON.stringify([...state.visitedCourses])); state.lastActionTime = now; return; } } } catch(e) {} }); } // 4. 播放页切下一节/未完成章节 function nextSection() { const now = Date.now(); if (now - state.lastActionTime < CONFIG.actionCooldown) return; getAllDocs().forEach(doc => { try { if (!doc.location.href.includes('courseLearning/play')) return; // 优先点绿色"下一节"按钮 const nextBtn = [...doc.querySelectorAll('button')].find(el => el.innerText?.trim() === '下一节' && el.offsetParent && !el.disabled); if (nextBtn) { log('点下一节'); nextBtn.click(); state.lastActionTime = now; return; } // 找右侧"未完成"章节 const unDone = [...doc.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.tagName === 'BUTTON') { p.click(); state.lastActionTime = now; log('点未完成章节'); return; } p = p.parentElement; } } // 课程学完返回列表 if (doc.body.innerText.includes('本课程学习完成') || doc.body.innerText.includes('课程学习完成')) { log('课程学完返回列表'); history.back(); state.lastActionTime = now; } } catch(e) {} }); } // 5. 自动答题:所有题答完再提交 async function answerQuiz() { getAllDocs().forEach(async doc => { try { const qs = doc.querySelectorAll('[class*=question-item], [class*=quiz-item]'); if (!qs.length) return; log(`检测到${qs.length}道题,开始作答`); for (let q of qs) { const opts = q.querySelectorAll('label, .el-radio, .el-checkbox-item'); 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,300)); } } await new Promise(r=>setTimeout(r,1500)); // 必须全部答完才提交 const allDone = [...qs].every(q => q.querySelectorAll('.is-checked').length > 0); if (allDone) { const submit = [...doc.querySelectorAll('button')].find(b => b.innerText?.includes('提交') && b.offsetParent); if (submit) { submit.click(); log('全部答完提交'); } } } catch(e) {} }); } // 主循环 async function loop() { closePopups(); playVideo(); pickNextCourse(); nextSection(); // 检测到题目就答题 const hasQuiz = getAllDocs().some(d => d.body.innerText.includes('单选题') || d.querySelectorAll('[class*=question-item]').length > 0); if (hasQuiz) await answerQuiz(); setTimeout(loop, CONFIG.checkInterval); } log('v3.5启动:递归遍历iframe,自动循环学完所有必修'); setTimeout(loop, 3000); })();