// ==UserScript== // @name 【学习通】【刷课】【继续教育学习】【超星小助手】 // @namespace wbmb // @version 1.0.0 // @description 支持超星视频、文档、答题 // @author wbmb // @run-at document-end // @storageName unrivalxxt // @match *://*.chaoxing.com/* // @match *://*.edu.cn/* // @match *://*.nbdlib.cn/* // @match *://*.hnsyu.net/* // @match *://*.ac.cn/* // @icon http://pan-yz.chaoxing.com/favicon.ico // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_addValueChangeListener // @grant GM_info // @connect mooc1-1.chaoxing.com // @connect mooc1.chaoxing.com // @connect mooc1-2.chaoxing.com // @connect passport2-api.chaoxing.com // @connect 14.29.190.187 // @connect cx.icodef.com // @license GPL-3.0-or-later // @original-script https://scriptcat.org/zh-CN/script-show-page/379 // @original-author unrival // @original-license GPL-3.0-or-later // ==/UserScript== /** * 学习通小助手 - 优化版 * 优化内容: * 1. 模块化重构 * 2. 性能优化(减少DOM操作、优化定时器、网络请求优化) * 3. 错误处理机制完善 * 4. 功能增强(智能任务调度、配置管理、缓存机制) * 5. 安全性优化 * 6. 可维护性优化 */ // 兼容性处理:为旧浏览器添加replaceAll方法 if (!String.prototype.replaceAll) { String.prototype.replaceAll = function(search, replacement) { return this.split(search).join(replacement); }; } (() => { 'use strict'; // 配置管理模块 const Config = { token: GM_getValue('tikutoken', ''), jumpType: 1, // 0:智能模式,1:遍历模式,2:不跳转 disableMonitor: 0, // 0:无操作,1:解除多端学习监控 accuracy: 60, //章节测试正确率百分比 randomDo: 1, //找不到答案时自动选择 backGround: 0, //是否对接超星挂机小助手 autoLogin: 0, //掉线是否自动登录 phoneNumber: '', //自动登录的手机号 password: '', //自动登录的密码 // 网络配置 host: 'http://14.29.190.187:54223/', ctUrl: 'https://cx.icodef.com/wyn-nb?v=4', // 获取配置 get(key) { return this[key]; }, // 设置配置 set(key, value) { this[key] = value; if (key === 'tikutoken') { GM_setValue('tikutoken', value); } } }; // 工具函数模块 const Utils = { // 获取URL参数 getQueryVariable(variable) { let q = location.search.substring(1), v = q.split("&"), r = false; for (let i = 0, l = v.length; i < l; i++) { let p = v[i].split("="); if (p[0] == variable) r = p[1]; } return r; }, // 获取Cookie getCookie(name) { return `; ${document.cookie}`.split(`; ${name}=`).pop().split(';').shift(); }, // 处理图片 handleImgs(s) { const imgEs = s.match(/(]*)>)/); if (imgEs) { for (let j = 0, k = imgEs.length; j < k; j++) { const urls = imgEs[j].match( /http[s]?:\/\/(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+/), url; if (urls) { const url = urls[0].replace(/http[s]?:\/\//, ''); s = s.replaceAll(imgEs[j], url); } } } return s; }, // 字符串处理 trim(s) { return this.handleImgs(s) .replaceAll('javascript:void(0);', '') .replaceAll(" ", '') .replaceAll(",", ',') .replaceAll("。", '.') .replaceAll(":", ':') .replaceAll(";", ';') .replaceAll("?", '?') .replaceAll("(", '(') .replaceAll(")", ')') .replaceAll("“", '"') .replaceAll("”", '"') .replaceAll("!", '!') .replaceAll("-", ' ') .replace(/(<([^>]+)>)/ig, '') .replace(/^\s+/ig, '') .replace(/\s+$/ig, ''); }, // 生成时间戳 getTimestamp() { return String(Math.round(new Date())); }, // 格式化时间 formatTime() { const nowTime = new Date(); const nowHour = (Array(2).join(0) + nowTime.getHours()).slice(-2); const nowMin = (Array(2).join(0) + nowTime.getMinutes()).slice(-2); const nowSec = (Array(2).join(0) + nowTime.getSeconds()).slice(-2); return `${nowHour}:${nowMin}:${nowSec}`; }, // 延迟执行 delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }, // 生成随机数 random(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } }; // 日志系统模块 const Logger = { logArry: [], maxLogs: 50, // 添加日志 addLog(str, color = "black") { if (this.logArry.length >= this.maxLogs) { this.logArry.shift(); } const timeStr = Utils.formatTime(); this.logArry.push(`[${timeStr}] ${str}`); this.updateLogView(); }, // 更新日志视图 updateLogView() { const logElement = document.getElementById('log'); if (!logElement) return; let logStr = ""; for (let logI = 0, logLen = this.logArry.length; logI < logLen; logI++) { logStr += this.logArry[logI] + "
"; } // 使用文档片段减少DOM操作 const fragment = document.createDocumentFragment(); const tempDiv = document.createElement('div'); tempDiv.innerHTML = logStr; while (tempDiv.firstChild) { fragment.appendChild(tempDiv.firstChild); } logElement.innerHTML = ''; logElement.appendChild(fragment); logElement.scrollTop = logElement.scrollHeight; } }; // 网络请求模块 const Network = { // 请求缓存 cache: new Map(), // 发送GET请求 get(url, headers = {}, timeout = 5000) { return new Promise((resolve, reject) => { // 检查缓存 const cacheKey = url; if (this.cache.has(cacheKey)) { resolve(this.cache.get(cacheKey)); return; } GM_xmlhttpRequest({ method: "get", headers, url, timeout, onload: (res) => { // 缓存响应 this.cache.set(cacheKey, res); resolve(res); }, onerror: (err) => reject(err), ontimeout: (err) => reject(err) }); }); }, // 发送POST请求 post(url, data, headers = {}, timeout = 5000) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "post", headers, url, data, timeout, onload: (res) => resolve(res), onerror: (err) => reject(err), ontimeout: (err) => reject(err) }); }); }, // 清除缓存 clearCache() { this.cache.clear(); } }; // 任务管理模块 const TaskManager = { missionList: {}, busyThread: 0, stop: false, // 添加任务 addTask(task) { this.missionList['m' + task.jobid] = { ...task, done: false, running: false }; }, // 执行任务 async executeTasks() { if (this.stop) return; // 检查是否有正在运行的任务 for (const itemName in this.missionList) { if (this.missionList[itemName].running) { setTimeout(() => this.executeTasks(), 500); return; } } // 执行下一个未完成的任务 for (const itemName in this.missionList) { if (!this.missionList[itemName].done) { const task = this.missionList[itemName]; task.running = true; try { switch (task.type) { case 'video': await VideoHandler.process(task); break; case 'document': await DocumentHandler.process(task); break; case 'work': await WorkHandler.process(task); break; } } catch (error) { Logger.addLog(`任务执行失败: ${error.message}`, 'red'); } finally { task.running = false; task.done = true; } setTimeout(() => this.executeTasks(), 500); return; } } // 所有任务完成 if (this.busyThread <= 0) { if (Config.get('jumpType') != 2) { unsafeWindow.top.jump = true; Logger.addLog('所有任务处理完毕,5秒后自动下一章', 'green'); } else { Logger.addLog('所有任务处理完毕,用户设置为不跳转,脚本已结束运行', 'green'); } } else { setTimeout(() => this.executeTasks(), 500); } }, // 增加忙碌线程数 increaseBusyThread() { this.busyThread++; }, // 减少忙碌线程数 decreaseBusyThread() { this.busyThread = Math.max(0, this.busyThread - 1); }, // 停止任务 stopTasks() { this.stop = true; } }; // 视频处理模块 const VideoHandler = { // 准备视频信息 async prepareVideo(item) { TaskManager.increaseBusyThread(); try { const statusUrl = `${location.protocol}//${location.host}/ananas/status/${item.property.objectid}?k=${Utils.getCookie('fid')}&flag=normal&_dc=${Utils.getTimestamp()}`; const res = await Network.get(statusUrl, { 'Host': location.host, 'Referer': GM_getValue('vrefer', `${location.protocol}//${location.host}/ananas/modules/video/index.html?v=2022-1118-1729`), 'Sec-Fetch-Site': 'same-origin' }); const videoInfo = JSON.parse(res.responseText); const duration = videoInfo.duration; const dtoken = videoInfo.dtoken; if (!duration) { this.addTaskToView('[无效视频]' + item.property.name); return; } TaskManager.addTask({ module: item.property.module, type: 'video', dtoken, duration, objectId: item.property.objectid, rt: item.property.rt || '0.9', otherInfo: item.otherInfo, doublespeed: item.property.doublespeed, jobid: item.jobid, name: item.property.name }); this.addTaskToView('[视频]' + item.property.name); } catch (error) { Logger.addLog('获取视频信息失败: ' + error.message, 'red'); } finally { TaskManager.decreaseBusyThread(); } }, // 处理视频任务 async process(item) { const rate = GM_getValue('unrivalrate', '1'); if (parseFloat(rate) <= 0) { Logger.addLog('奇怪的倍速,视频已自动跳过', 'orange'); await Utils.delay(5000); return; } // 检查是否支持后台挂机 const allowBackground = Math.round(new Date() / 1000) - parseInt(GM_getValue('unrivalBackgroundVideoEnable', '6')) < 15; if (allowBackground && Config.get('backGround')) { if (unsafeWindow.top.document.getElementsByClassName('catalog_points_sa').length > 0 || unsafeWindow.top.document.getElementsByClassName('lock').length > 0) { Logger.addLog('您已安装超星挂机小助手,但此课程可能为闯关模式,不支持后台挂机,将为您在线完成', 'blue'); } else { item.userid = Utils.getCookie('_uid') || Utils.getCookie('UID'); item.classId = Utils.getQueryVariable('clazzid') || Utils.getQueryVariable('clazzId') || Utils.getQueryVariable('classid') || Utils.getQueryVariable('classId'); item.review = unsafeWindow.top.unrivalReviewMode === '1'; item.reportUrl = GM_getValue('reportUrl', ''); item.rt = item.rt; GM_setValue('unrivalBackgroundVideo', item); document.cookie = "videojs_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; Logger.addLog('您已安装超星挂机小助手,已添加至后台任务,点我查看后台', 'green'); await Utils.delay(5000); return; } } // 在线处理视频 const videojs_id = String(parseInt(Math.random() * 9999999)); document.cookie = 'videojs_id=' + videojs_id + ';path=/'; Logger.addLog('开始刷视频:' + item.name + ',倍速:' + String(rate) + '倍'); Logger.addLog('视频观看信息每60秒上报一次,请耐心等待', 'green'); if (Config.get('disableMonitor')) { Logger.addLog('解除多端学习监控有清除进度风险,请谨慎使用', 'orange'); } let dtype = 'Video'; if (item.module.includes('audio')) { dtype = 'Audio'; } return new Promise((resolve) => { let playTime = 0, playsTime = 0, isdrag = '3', times = 0, first = true, loop; loop = setInterval(async () => { if (parseFloat(rate) <= 0) { clearInterval(loop); Logger.addLog('奇怪的倍速,视频已自动跳过', 'orange'); resolve(); return; } playsTime += parseFloat(rate); playTime = Math.ceil(playsTime); if (times == 0 || times % 30 == 0 || playTime >= item.duration) { if (first) { playTime = 0; } if (playTime >= item.duration) { clearInterval(loop); playTime = item.duration; isdrag = '4'; } else if (playTime > 0) { isdrag = '0'; } try { await this.reportVideoProgress(item, playTime, isdrag, dtype, rate, first); if (playTime >= item.duration) { if (unsafeWindow.top.unrivalReviewMode == '1') { Logger.addLog('视频已观看完毕', 'green'); } else { Logger.addLog('视频已观看完毕,但视频任务未完成', 'red'); } resolve(); } // 更新first变量 first = false; } catch (error) { Logger.addLog('上报视频进度失败: ' + error.message, 'red'); times = -10; } } times++; }, 1000); }); }, // 上报视频进度 async reportVideoProgress(item, playTime, isdrag, dtype, rate, first) { const classId = Utils.getQueryVariable('clazzid') || Utils.getQueryVariable('clazzId') || Utils.getQueryVariable('classid') || Utils.getQueryVariable('classId'); const UID = Utils.getCookie('_uid') || Utils.getCookie('UID'); const encUrl = `${Config.get('host')}chaoXing/v3/getEnc.php?classid=${classId}&playtime=${playTime}&duration=${item.duration}&objectid=${item.objectId}&jobid=${item.jobid}&uid=${UID}`; let enc = ''; try { const res = await Network.get(encUrl, {}, 2000); if (res && res.status == 200) { enc = res.responseText; if (enc.includes('--#')) { const warnInfo = enc.match(new RegExp('--#(.*?)--#', "ig"))[0].replace(/--#/ig, ''); Logger.addLog(warnInfo, 'red'); enc = enc.replace(/--#(.*?)--#/ig, ''); } if (enc.indexOf('.stop') >= 0) { TaskManager.stopTasks(); return; } } } catch (error) { // 使用本地计算作为备份 const jq = unsafeWindow.top.$ || unsafeWindow.top.jQuery; const strEc = `[${classId}][${UID}][${item.jobid}][${item.objectId}][${playTime * 1000}][d_yHJ!$pdA~5][${item.duration * 1000}][0_${item.duration}]`; enc = jq.md5(strEc); } if (enc.length != 32) { TaskManager.stopTasks(); return; } const reportUrl = GM_getValue('reportUrl', ''); const reportsUrl = `${reportUrl}/${item.dtoken}?clazzId=${classId}&playingTime=${playTime}&duration=${item.duration}&clipTime=0_${item.duration}&objectId=${item.objectId}&otherInfo=${item.otherInfo}&jobid=${item.jobid}&userid=${UID}&isdrag=${isdrag}&view=pc&enc=${enc}&rt=${item.rt}&dtype=${dtype}&_t=${Utils.getTimestamp()}`; const res = await Network.get(reportsUrl, { 'Host': location.host, 'Referer': GM_getValue('vrefer', `${location.protocol}//${location.host}/ananas/modules/video/index.html?v=2022-1118-1729`), 'Sec-Fetch-Site': 'same-origin', 'Content-Type': 'application/json' }); // 更新学习时间 const today = new Date(); const todayStr = `${today.getFullYear()}d${today.getMonth()}d${today.getDate()}`; const timelong = GM_getValue('unrivaltimelong', {}); if (!timelong[UID] || timelong[UID].today != todayStr) { timelong[UID] = { time: 0, today: todayStr }; } else { timelong[UID].time++; } GM_setValue('unrivaltimelong', timelong); // 检查学习时间 if (timelong[UID].time / 60 > 22 && item.doublespeed == 0 && unsafeWindow.top.unrivalReviewMode == '0') { Logger.addLog('今日学习时间过长,继续学习会导致清空进度,请明天再来', 'red'); return; } const ispass = JSON.parse(res.responseText); if (ispass.isPassed && unsafeWindow.top.unrivalReviewMode == '0') { Logger.addLog('视频任务已完成', 'green'); return true; } else if (isdrag == '4') { return true; } else { Logger.addLog(`${item.name}已观看${playTime}秒,剩余大约${item.duration - playTime}秒`); } }, // 添加任务到视图 addTaskToView(name) { const joblistElement = document.getElementById('joblist'); if (!joblistElement) return; const taskDiv = document.createElement('div'); taskDiv.className = 'panel panel-default'; taskDiv.innerHTML = `
${name}
`; joblistElement.appendChild(taskDiv); } }; // 文档处理模块 const DocumentHandler = { // 处理文档任务 async process(item) { Logger.addLog('开始刷文档:' + item.name); await Utils.delay(Utils.random(9000, 11000)); TaskManager.increaseBusyThread(); try { const classId = Utils.getQueryVariable('clazzid') || Utils.getQueryVariable('clazzId') || Utils.getQueryVariable('classid') || Utils.getQueryVariable('classId'); const courseId = Utils.getQueryVariable('courseid') || Utils.getQueryVariable('courseId'); const chapterId = Utils.getQueryVariable('knowledgeid'); const url = `${location.protocol}//${location.host}/ananas/job/document?jobid=${item.jobid}&knowledgeid=${chapterId}&courseid=${courseId}&clazzid=${classId}&jtoken=${item.jtoken}`; const res = await Network.get(url); const ispass = JSON.parse(res.responseText); if (ispass.status) { Logger.addLog('文档任务已完成', 'green'); } else { Logger.addLog('文档已阅读完成,但任务点未完成', 'red'); } } catch (error) { Logger.addLog('阅读文档失败: ' + error.message, 'red'); } finally { TaskManager.decreaseBusyThread(); } } }; // 答题处理模块 const WorkHandler = { // 处理答题任务 process(item) { return new Promise((resolve) => { Logger.addLog('开始刷章节测试:' + item.name); Logger.addLog('您设置的答题正确率为:' + String(Config.get('accuracy')) + '%,只有在高于此正确率时才会提交测试', 'blue'); // 显示答题面板 const workPanel = document.getElementById('workPanel'); const frameContent = document.getElementById('frame_content'); if (workPanel && frameContent) { workPanel.style.display = 'block'; const classId = Utils.getQueryVariable('clazzid') || Utils.getQueryVariable('clazzId') || Utils.getQueryVariable('classid') || Utils.getQueryVariable('classId'); const courseId = Utils.getQueryVariable('courseid') || Utils.getQueryVariable('courseId'); const chapterId = Utils.getQueryVariable('knowledgeid'); frameContent.src = `${location.protocol}//${location.host}/work/phone/work?workId=${item.jobid.replace('work-', '')}&courseId=${courseId}&clazzId=${classId}&knowledgeId=${chapterId}&jobId=${item.jobid}&enc=${item.enc}`; } // 监听答题完成 unsafeWindow.top.unrivalWorkInfo = ''; unsafeWindow.top.unrivalDoneWorkId = ''; const infoInterval = setInterval(() => { if (unsafeWindow.top.unrivalWorkInfo != '') { Logger.addLog(unsafeWindow.top.unrivalWorkInfo); unsafeWindow.top.unrivalWorkInfo = ''; } }, 100); // 检查跨域 const checkcross = setInterval(() => { if (unsafeWindow.top.unrivalWorkDone == false) { clearInterval(checkcross); return; } try { const ifW = frameContent.contentWindow; ifW.location.href; } catch (e) { if (e.message.indexOf('cross-origin') != -1) { clearInterval(checkcross); unsafeWindow.top.unrivalWorkDone = true; } } }, 2000); // 检查答题完成 const workDoneInterval = setInterval(() => { if (unsafeWindow.top.unrivalWorkDone) { unsafeWindow.top.unrivalWorkDone = false; clearInterval(workDoneInterval); clearInterval(infoInterval); unsafeWindow.top.unrivalDoneWorkId = ''; if (workPanel && frameContent) { workPanel.style.display = 'none'; frameContent.src = ''; } setTimeout(() => resolve(), 5000); } }, 500); }); } }; // 页面处理模块 const PageHandler = { // 初始化知识卡片页面 initKnowledgeCardsPage() { let allowBackground = false; const spans = document.getElementsByTagName('span'); for (let i = 0, l = spans.length; i < l; i++) { if (spans[i].innerHTML.indexOf('章节未开放') != -1) { if (location.href.indexOf("ut=s") != -1) { location.href = location.href.replace("ut=s", "ut=t").replace(/&cpi=[0-9]{1,10}/, ''); } else if (location.href.indexOf("ut=t") != -1) { spans[i].innerHTML = '此课程为闯关模式,请回到上一章节完成学习任务!'; return; } break; } } unsafeWindow.top.unrivalPageRd = String(Math.random()); // 检查浏览器版本 let cVersion = 999; if (!navigator.userAgent.includes("Firefox")) { try { cVersion = parseInt(navigator.userAgent.match(/Chrome\/[0-9]{2,3}./)[0].replace('Chrome/', '').replace('.', '')); } catch (e) {} } if (cVersion < 86) { Logger.addLog('您的浏览器内核过老,请更新版本或使用主流浏览器,推荐 edge浏览器', 'red'); TaskManager.stopTasks(); return; } if (navigator.userAgent.includes("Android")) { Logger.addLog('手机浏览器不保证能正常运行此脚本', 'orange'); } // 监听页面可见性变化 document.addEventListener('visibilitychange', function () { const isH = document.hidden; if (!isH) { Logger.addLog('挂机功能不稳定,不建议长时间最小化窗口', 'orange'); } }); // 初始化UI this.initUI(); // 解析页面数据 this.parsePageData(); }, // 初始化学生学习页面 initStudentStudyPage() { // 初始化音频播放器 const audiofile = 'data:audio/ogg;base64,T2dnUwACAAAAAAAAAABwRPFFAAAAAGFtEqwBHgF2b3JiaXMAAAAAAUAfAAAAAAAAUHgAAAAAAACZAU9nZ1MAAAAAAAAAAAAAcETxRQEAAAA7J4IBDP8F////////////tQN2b3JiaXMvAAAAWGlwaC5PcmcgbGliVm9yYmlzIEkgMjAxNDAxMjIgKFR1cnBha8OkcsOkamlpbikGAAAAJQAAAEVOQ09ERVI9U291bmQgU3R1ZGlvLCBsaWJWb3JiaXMgMS4zLjEbAAAAQUxCVU0gQVJUSVNUPUFkdmVudHVyZSBMYW5kFAAAAEFMQlVNPUFkdmVudHVyZSBMYW5kIQAAAEVOQ09ESU5HIEFQUExJQ0FUSU9OPVNvdW5kIFN0dWRpbxUAAABBUlRJU1Q9QWR2ZW50dXJlIExhbmQjAAAAVElUTEU9RW1wdHkgTG9vcCBGb3IgSlMgUGVyZm9ybWFuY2UBBXZvcmJpcxJCQ1YBAAABAAxSFCElGVNKYwiVUlIpBR1jUFtHHWPUOUYhZBBTiEkZpXtPKpVYSsgRUlgpRR1TTFNJlVKWKUUdYxRTSCFT1jFloXMUS4ZJCSVsTa50FkvomWOWMUYdY85aSp1j1jFFHWNSUkmhcxg6ZiVkFDpGxehifDA6laJCKL7H3lLpLYWKW4q91xpT6y2EGEtpwQhhc+211dxKasUYY4wxxsXiUyiC0JBVAAABAABABAFCQ1YBAAoAAMJQDEVRgNCQVQBABgCAABRFcRTHcRxHkiTLAkJDVgEAQAAAAgAAKI7hKJIjSZJkWZZlWZameZaouaov+64u667t6roOhIasBADIAAAYhiGH3knMkFOQSSYpVcw5CKH1DjnlFGTSUsaYYoxRzpBTDDEFMYbQKYUQ1E45pQwiCENInWTOIEs96OBi5zgQGrIiAIgCAACMQYwhxpBzDEoGIXKOScggRM45KZ2UTEoorbSWSQktldYi55yUTkompbQWUsuklNZCKwUAAAQ4AAAEWAiFhqwIAKIAABCDkFJIKcSUYk4xh5RSjinHkFLMOcWYcowx6CBUzDHIHIRIKcUYc0455iBkDCrmHIQMMgEAAAEOAAABFkKhISsCgDgBAIMkaZqlaaJoaZooeqaoqqIoqqrleabpmaaqeqKpqqaquq6pqq5seZ5peqaoqp4pqqqpqq5rqqrriqpqy6ar2rbpqrbsyrJuu7Ks256qyrapurJuqq5tu7Js664s27rkearqmabreqbpuqrr2rLqurLtmabriqor26bryrLryratyrKua6bpuqKr2q6purLtyq5tu7Ks+6br6rbqyrquyrLu27au+7KtC7vourauyq6uq7Ks67It67Zs20LJ81TVM03X9UzTdVXXtW3VdW1bM03XNV1XlkXVdWXVlXVddWVb90zTdU1XlWXTVWVZlWXddmVXl0XXtW1Vln1ddWVfl23d92VZ133TdXVblWXbV2VZ92Vd94VZt33dU1VbN11X103X1X1b131htm3fF11X11XZ1oVVlnXf1n1lmHWdMLqurqu27OuqLOu+ruvGMOu6MKy6bfyurQvDq+vGseu+rty+j2rbvvDqtjG8um4cu7Abv+37xrGpqm2brqvrpivrumzrvm/runGMrqvrqiz7uurKvm/ruvDrvi8Mo+vquirLurDasq/Lui4Mu64bw2rbwu7aunDMsi4Mt+8rx68LQ9W2heHVdaOr28ZvC8PSN3a+AACAAQcAgAATykChISsCgDgBAAYhCBVjECrGIIQQUgohpFQxBiFjDkrGHJQQSkkhlNIqxiBkjknIHJMQSmiplNBKKKWlUEpLoZTWUmotptRaDKG0FEpprZTSWmopttRSbBVjEDLnpGSOSSiltFZKaSlzTErGoKQOQiqlpNJKSa1lzknJoKPSOUippNJSSam1UEproZTWSkqxpdJKba3FGkppLaTSWkmptdRSb'; const audioPlayer = new Audio(audiofile); unsafeWindow.top.backNow = 0; audioPlayer.loop = true; unsafeWindow.audioPlayer = audioPlayer; // 防止viewer弹窗 setInterval(function () { try { unsafeWindow.jQuery.fn.viewer.Constructor.prototype.show = () => { }; } catch (e) {} }, 1000); // 初始化脚本列表 try { unsafeWindow.unrivalScriptList.push('Fuck me please'); } catch (e) { unsafeWindow.unrivalScriptList = ['Fuck me please']; } // 检查离线状态 setInterval(function () { if (PageHandler.checkOffline()) { setTimeout(function () { if (PageHandler.checkOffline()) { location.reload(); } }, 10000); } }, 3000); // 监听页面可见性变化 document.addEventListener('visibilitychange', function () { let c = 0; if (unsafeWindow.top.backNow == 0) { document.title = '⚠️请先激活挂机'; return; } else { document.title = '学生学习页面'; } if (document.hidden) { audioPlayer.play(); const timer = setInterval(function () { if (c) { document.title = '🙈挂机中'; c = 0; } else { document.title = '🙉挂机中'; c = 1; } if (!document.hidden) { clearInterval(timer); document.title = '学生学习页面'; } }, 1300); } else { audioPlayer.pause(); } }); // 重写getTeacherAjax函数 unsafeWindow.unrivalgetTeacherAjax = unsafeWindow.getTeacherAjax; unsafeWindow.getTeacherAjax = (courseid, classid, cid) => { if (cid == Utils.getQueryVariable('chapterId')) { return; } unsafeWindow.top.unrivalPageRd = ''; unsafeWindow.unrivalgetTeacherAjax(courseid, classid, cid); }; // 解除多端学习监控 if (Config.get('disableMonitor') == 1) { unsafeWindow.appendChild = unsafeWindow.Element.prototype.appendChild; unsafeWindow.Element.prototype.appendChild = function () { try { if (arguments[0].src && arguments[0].src.indexOf('detect.chaoxing.com') > 0) { return; } } catch (e) {} unsafeWindow.appendChild.apply(this, arguments); }; } // 初始化跳转功能 this.initJumpFunction(); }, // 初始化答题页面 initDoHomeWorkPage() { const wIdE = document.getElementById('workLibraryId') || document.getElementById('oldWorkId'); if (!wIdE) return; const wid = wIdE.value; unsafeWindow.top.unrivalWorkDone = false; // 重写alert函数 unsafeWindow.aalert = unsafeWindow.alert; unsafeWindow.alert = (msg) => { if (msg == '保存成功') { unsafeWindow.top.unrivalDoneWorkId = Utils.getQueryVariable('workId'); return; } unsafeWindow.aalert(msg); }; if (unsafeWindow.top.unrivalDoneWorkId == Utils.getQueryVariable('workId')) { unsafeWindow.top.unrivalWorkDone = true; return; } // 重写confirm函数 unsafeWindow.confirm = (msg) => true; // 解析题目 const questionList = this.parseQuestions(); if (questionList.length === 0) { Logger.addLog('未找到题目', 'red'); return; } // 处理题目 this.processQuestions(questionList, wid); }, // 初始化后台挂机页面 initBackgroundPage() { document.getElementsByTagName("html")[0].innerHTML = ` 学习通挂机小助手

学习通挂机小助手 


任务列表
运行日志
`; Logger.addLog('此页面不必保持在最前端,后台会自动进行任务', 'green'); // 定时提示 setInterval(function () { Logger.addLog('此页面不必保持在最前端,后台会自动进行任务', 'green'); Logger.addLog('如想禁用后台刷视频功能,请关闭脚本并重启浏览器', 'blue'); }, 120000); // 监听后台任务信息 GM_addValueChangeListener('unrivalxxtbackgroundinfo', function (name, old_value, new_value, remote) { if (old_value != new_value) { Logger.addLog(new_value); } }); // 检查后台运行状态 setInterval(function () { if (Math.round(new Date() / 1000) - parseInt(GM_getValue('unrivalBackgroundVideoEnable', '6')) > 15) { Logger.addLog('超星挂机小助手可能运行异常,如页面无反应,请尝试重启脚本猫或重启浏览器(脚本猫0.9.0版本有此问题)'); } }, 10000); // 显示任务列表 this.showBackgroundTasks(); setInterval(() => this.showBackgroundTasks(), 10000); }, // 检查离线状态 checkOffline() { const dleft = document.getElementsByClassName('left'); if (dleft.length == 1) { const img = dleft[0].getElementsByTagName('img'); if (img.length == 1) { if (img[0].src.indexOf('loading.gif') != -1) { return true; } } } return false; }, // 初始化UI initUI() { // 创建主界面 document.getElementsByTagName("html")[0].innerHTML = ` 学习通小助手

任务配置
开启倍数是会清进度的,不建议开启,除非是真的没时间了才开启倍数
视频倍速:
保存  |  复习模式  |   |  后台挂机   激活挂机

章节测试:
自动答题 |  自动提交 |  自动保存
题库Token:
保存
关注
Smiley face

作者是 大四学生 社畜,相信大家都是被大学网课而耽误的强国少年,我的专业是化学,但感觉学习计算机更符合自己的兴趣,也能更好地用科技便利生活,考研计算机了,因为脚本作者不更新,索性copycopy修改自己用,随后一想干脆发布出去,没想到发展到现在都有人用

当时放个赞赏码在这纯属侥幸,也没想到现在会从哥哥姐姐们手里收到零零碎碎的小费

感谢各位一直以来的支持,因为在准备毕设实在是太忙啦!

这个版本修复一些细节问题

留言于:2026.03.20

祝大家学业有成!

任务列表
运行日志
[00:00:00]如果此提示不消失,说明页面出现了错误,请联系作者
`; // 初始化UI事件 const htmlHook = setInterval(function () { const unrivalRate = document.getElementById('unrivalRate'); const updateRateButton = document.getElementById('updateRateButton'); const reviewModeButton = document.getElementById('reviewModeButton'); const autoDoWorkButton = document.getElementById('autoDoWorkButton'); const autoSubmitButton = document.getElementById('autoSubmitButton'); const autoSaveButton = document.getElementById('autoSaveButton'); if (unrivalRate && updateRateButton && reviewModeButton && autoDoWorkButton && autoSubmitButton && autoSaveButton) { clearInterval(htmlHook); // 初始化倍速值 const rate = GM_getValue('unrivalrate', '1'); unrivalRate.value = rate; // 隐藏后台挂机按钮(如果未启用) const fuckMeModeButton = document.getElementById('fuckMeModeButton'); if (!Config.get('backGround')) { fuckMeModeButton.style.display = "none"; } // 检查是否允许后台挂机 const allowBackground = Math.round(new Date() / 1000) - parseInt(GM_getValue('unrivalBackgroundVideoEnable', '6')) < 15; if (allowBackground) { fuckMeModeButton.setAttribute('href', 'unrivalxxtbackground/'); } // 绑定事件 document.getElementById('updateToken').onclick = function () { const token = document.getElementById('token').value; if (token.length == 16) { Logger.addLog('一之哥哥题库token已更新为' + token, 'green'); } else { Logger.addLog('请检查一之哥哥题库token', 'green'); } Config.set('token', token); }; document.getElementById('updateRateButton').onclick = function () { let urate = document.getElementById('unrivalRate').value; if (parseFloat(urate) == parseInt(urate)) { urate = parseInt(urate); } else { urate = parseFloat(urate); } GM_setValue('unrivalrate', urate); if (urate > 0) { Logger.addLog('视频倍速已更新为' + urate + '倍,将在3秒内生效', 'green'); } else { Logger.addLog('奇怪的倍速,将会自动跳过视频任务', 'orange'); } }; document.getElementById('backGround').onclick = function () { Logger.addLog('挂机激活成功,您现在可以最小化页面了', 'green'); document.getElementById('backGround').setAttribute('class', 'btn btn-success'); unsafeWindow.top.backNow = 1; }; document.getElementById('reviewModeButton').onclick = function () { const reviewButton = document.getElementById('reviewModeButton'); if (reviewButton.getAttribute('class') == 'btn btn-default') { reviewButton.setAttribute('class', 'btn btn-success'); Logger.addLog('复习模式已开启,遇到已完成的视频任务不会跳过', 'green'); GM_setValue('unrivalreview', '1'); unsafeWindow.top.unrivalReviewMode = '1'; } else { reviewButton.setAttribute('class', 'btn btn-default'); Logger.addLog('复习模式已关闭,遇到已完成的视频任务会自动跳过', 'green'); GM_setValue('unrivalreview', '0'); unsafeWindow.top.unrivalReviewMode = '0'; } }; document.getElementById('autoDoWorkButton').onclick = function () { const autoDoWorkButton = document.getElementById('autoDoWorkButton'); if (autoDoWorkButton.getAttribute('class') == 'btn btn-default') { autoDoWorkButton.setAttribute('class', 'btn btn-success'); Logger.addLog('自动做章节测试已开启,将会自动做章节测试', 'green'); GM_setValue('unrivaldowork', '1'); unsafeWindow.top.unrivalDoWork = '1'; } else { autoDoWorkButton.setAttribute('class', 'btn btn-default'); Logger.addLog('自动做章节测试已关闭,将不会自动做章节测试', 'green'); GM_setValue('unrivaldowork', '0'); unsafeWindow.top.unrivalDoWork = '0'; } }; document.getElementById('autoSubmitButton').onclick = function () { const autoSubmitButton = document.getElementById('autoSubmitButton'); if (autoSubmitButton.getAttribute('class') == 'btn btn-default') { autoSubmitButton.setAttribute('class', 'btn btn-success'); Logger.addLog('符合提交标准的章节测试将会自动提交', 'green'); GM_setValue('unrivalautosubmit', '1'); unsafeWindow.top.unrivalAutoSubmit = '1'; } else { autoSubmitButton.setAttribute('class', 'btn btn-default'); Logger.addLog('章节测试将不会自动提交', 'green'); GM_setValue('unrivalautosubmit', '0'); unsafeWindow.top.unrivalAutoSubmit = '0'; } }; document.getElementById('autoSaveButton').onclick = function () { const autoSaveButton = document.getElementById('autoSaveButton'); if (autoSaveButton.getAttribute('class') == 'btn btn-default') { autoSaveButton.setAttribute('class', 'btn btn-success'); Logger.addLog('不符合提交标准的章节测试将会自动保存', 'green'); GM_setValue('unrivalautosave', '1'); unsafeWindow.top.unrivalAutoSave = '1'; } else { autoSaveButton.setAttribute('class', 'btn btn-default'); Logger.addLog('不符合提交标准的章节测试将不会自动保存,等待用户自己操作', 'green'); GM_setValue('unrivalautosave', '0'); unsafeWindow.top.unrivalAutoSave = '0'; } }; // 初始化模式状态 try { unsafeWindow.top.unrivalReviewMode = GM_getValue('unrivalreview', '0') || '0'; unsafeWindow.top.unrivalDoWork = GM_getValue('unrivaldowork', '1') || '1'; unsafeWindow.top.unrivalAutoSubmit = GM_getValue('unrivalautosubmit', '1') || '1'; unsafeWindow.top.unrivalAutoSave = GM_getValue('unrivalautosave', '0') || '0'; if (unsafeWindow.top.unrivalReviewMode == '1') { Logger.addLog('复习模式已开启,遇到已完成的视频任务不会跳过', 'green'); document.getElementById('reviewModeButton').setAttribute('class', 'btn btn-success'); } if (unsafeWindow.top.unrivalDoWork == '1') { Logger.addLog('自动做章节测试已开启,将会自动做章节测试', 'green'); document.getElementById('autoDoWorkButton').setAttribute('class', 'btn btn-success'); } document.getElementById('autoSubmitButton').setAttribute('class', ['btn btn-default', 'btn btn-success'][unsafeWindow.top.unrivalAutoSubmit]); document.getElementById('autoSaveButton').setAttribute('class', ['btn btn-default', 'btn btn-success'][unsafeWindow.top.unrivalAutoSave]); } catch (e) { Logger.addLog('初始化模式状态失败: ' + e.message, 'red'); } } }, 100); }, // 解析页面数据 parsePageData() { // 获取参数 const scripts = document.getElementsByTagName('script'); let param = null; for (let i = 0, l = scripts.length; i < l; i++) { if (scripts[i].innerHTML.indexOf('mArg = "";') != -1 && scripts[i].innerHTML.indexOf('==UserScript==') == -1) { param = scripts[i].innerHTML.substring(scripts[i].innerHTML.indexOf('try{\n mArg = '), scripts[i].innerHTML.indexOf(';\n}catch(e){')).replace('try{\n mArg = ', ''); } } if (param == null) { Logger.addLog('未找到页面参数', 'red'); return; } // 获取视频引用 let vrefer; try { vrefer = document.getElementsByClassName('ans-attach-online ans-insertvideo-online')[0].src; } catch (e) { vrefer = `${location.protocol}//${location.host}/ananas/modules/video/index.html?v=2022-1118-1729`; } GM_setValue('vrefer', vrefer); GM_setValue('host', location.host); // 解析页面数据 try { const pageData = JSON.parse(param); const data = pageData.defaults; const jobList = []; const classId = data.clazzId; const chapterId = data.knowledgeid; const reportUrl = data.reportUrl; const ktoken = data.ktoken; GM_setValue('reportUrl', reportUrl); // 收集任务 for (let i = 0, l = pageData.attachments.length; i < l; i++) { const item = pageData.attachments[i]; if (item.job != true || item.isPassed == true) { if (unsafeWindow.top.unrivalReviewMode == '1' && item.type == 'video') { jobList.push(item); } continue; } else { jobList.push(item); } } // 处理任务 if (jobList.length <= 0) { if (Config.get('jumpType') != 2) { unsafeWindow.top.jump = true; Logger.addLog('此页无任务,5秒后自动下一章', 'green'); } else { Logger.addLog('此页无任务,用户设置为不跳转,脚本已结束运行', 'green'); } return; } // 处理每个任务 for (let i = 0, l = jobList.length; i < l; i++) { const item = jobList[i]; if (item.type == 'video') { VideoHandler.prepareVideo(item); } else if (item.type == 'document') { TaskManager.addTask({ type: 'document', jtoken: item.jtoken, jobid: item.jobid, name: item.property.name, done: false, running: false }); const joblistElement = document.getElementById('joblist'); if (joblistElement) { const taskDiv = document.createElement('div'); taskDiv.className = 'panel panel-default'; taskDiv.innerHTML = `
[文档]${item.property.name}
`; joblistElement.appendChild(taskDiv); } } else if (item.type == 'workid' && unsafeWindow.top.unrivalDoWork == '1') { TaskManager.addTask({ type: 'work', workid: item.property.workid, jobid: item.jobid, name: item.property.title, enc: item.enc, done: false, running: false }); const joblistElement = document.getElementById('joblist'); if (joblistElement) { const taskDiv = document.createElement('div'); taskDiv.className = 'panel panel-default'; taskDiv.innerHTML = `
[章节测试]${item.property.title}
`; joblistElement.appendChild(taskDiv); } } else { try { let jobName = item.property.name; if (jobName == undefined) { jobName = item.property.title; } const joblistElement = document.getElementById('joblist'); if (joblistElement) { const taskDiv = document.createElement('div'); taskDiv.className = 'panel panel-default'; taskDiv.innerHTML = `
已跳过:${jobName}
`; joblistElement.appendChild(taskDiv); } } catch (e) { Logger.addLog('处理任务时出错: ' + e.message, 'red'); } } } // 开始执行任务 setTimeout(() => TaskManager.executeTasks(), 1000); } catch (error) { Logger.addLog('解析页面数据失败: ' + error.message, 'red'); if (Config.get('jumpType') != 2) { unsafeWindow.top.jump = true; Logger.addLog('此页无任务,5秒后自动下一章', 'green'); } else { Logger.addLog('此页无任务,用户设置为不跳转,脚本已结束运行', 'green'); } } }, // 初始化跳转功能 initJumpFunction() { unsafeWindow.jump = false; setInterval(function () { if (Utils.getQueryVariable('mooc2') == '1') { const tabs = document.getElementsByClassName('posCatalog_select'); for (let i = 0, l = tabs.length; i < l; i++) { const tabId = tabs[i].getAttribute('id'); if (tabId.indexOf('cur') >= 0 && tabs[i].getAttribute('class') == 'posCatalog_select') { tabs[i].setAttribute('onclick', `getTeacherAjax('${Utils.getQueryVariable('courseid') || Utils.getQueryVariable('courseId')}','${Utils.getQueryVariable('clazzid') || Utils.getQueryVariable('clazzId') || Utils.getQueryVariable('classid') || Utils.getQueryVariable('classId')}','${tabId.replace('cur', '')}');`); } } } else { const h4s = document.getElementsByTagName('h4'), h5s = document.getElementsByTagName('h5'); for (let i = 0, l = h4s.length; i < l; i++) { if (h4s[i].getAttribute('id').indexOf('cur') >= 0) { h4s[i].setAttribute('onclick', `getTeacherAjax('${Utils.getQueryVariable('courseid') || Utils.getQueryVariable('courseId')}','${Utils.getQueryVariable('clazzid') || Utils.getQueryVariable('clazzId') || Utils.getQueryVariable('classid') || Utils.getQueryVariable('classId')}','${h4s[i].getAttribute('id').replace('cur', '')}');`); } } for (let i = 0, l = h5s.length; i < l; i++) { if (h5s[i].getAttribute('id').indexOf('cur') >= 0) { h5s[i].setAttribute('onclick', `getTeacherAjax('${Utils.getQueryVariable('courseid') || Utils.getQueryVariable('courseId')}','${Utils.getQueryVariable('clazzid') || Utils.getQueryVariable('clazzId') || Utils.getQueryVariable('classid') || Utils.getQueryVariable('classId')}','${h5s[i].getAttribute('id').replace('cur', '')}');`); } } } }, 1000); setInterval(function () { if (unsafeWindow.jump) { unsafeWindow.jump = false; unsafeWindow.top.unrivalDoneWorkId = ''; unsafeWindow.jjump = (rd) => { if (rd != unsafeWindow.top.unrivalPageRd) { return; } try { setTimeout(function () { if (rd != unsafeWindow.top.unrivalPageRd) { return; } if (Config.get('jumpType') == 1) { let but = null; if (Utils.getQueryVariable('mooc2') == '1') { but = document.getElementsByClassName('jb_btn jb_btn_92 fs14 prev_next next'); } else { but = document.getElementsByClassName('orientationright'); } try { setTimeout(function () { if (rd != unsafeWindow.top.unrivalPageRd) { return; } if (but.length > 0) { but[0].click(); } }, 2000); } catch (e) { Logger.addLog('跳转失败: ' + e.message, 'red'); } return; } if (Utils.getQueryVariable('mooc2') == '1') { const ul = document.getElementsByClassName('prev_ul')[0]; if (ul) { const lis = ul.getElementsByTagName('li'); for (let i = 0, l = lis.length; i < l; i++) { if (lis[i].getAttribute('class') == 'active') { if (i + 1 < l) { try { lis[i + 1].click(); } catch (e) { Logger.addLog('跳转失败: ' + e.message, 'red'); } return; } break; } } } const tabs = document.getElementsByClassName('posCatalog_select'); for (let i = 0, l = tabs.length; i < l; i++) { if (tabs[i].getAttribute('class') == 'posCatalog_select posCatalog_active') { let j = i; while (j + 1 < tabs.length) { const nextTab = tabs[j + 1]; if ((nextTab.innerHTML.includes('icon_Completed prevTips') && unsafeWindow.top.unrivalReviewMode == '0') || nextTab.innerHTML.includes('catalog_points_er prevTips')) { j++; continue; } if (nextTab.id.indexOf('cur') < 0) { j++; continue; } const clickF = setInterval(function () { if (rd != unsafeWindow.top.unrivalPageRd) { clearInterval(clickF); return; } nextTab.click(); }, 2000); break; } break; } } } else { const div = document.getElementsByClassName('tabtags')[0]; if (div) { const spans = div.getElementsByTagName('span'); for (let i = 0, l = spans.length; i < l; i++) { if (spans[i].getAttribute('class').indexOf('currents') >= 0) { if (i + 1 < l) { try { spans[i + 1].click(); } catch (e) { Logger.addLog('跳转失败: ' + e.message, 'red'); } return; } break; } } } const tabs = document.getElementsByTagName('span'); const newTabs = []; for (let i = 0, l = tabs.length; i < l; i++) { if (tabs[i].getAttribute('style') != null && tabs[i].getAttribute('style').indexOf('cursor:pointer;height:18px;') >= 0) { newTabs.push(tabs[i]); } } for (let i = 0, l = newTabs.length; i < l; i++) { if (newTabs[i].parentNode.getAttribute('class') == 'currents') { let j = i; while (j + 1 < newTabs.length) { const nextTab = newTabs[j + 1].parentNode; if ((nextTab.innerHTML.includes('roundpoint blue') && unsafeWindow.top.unrivalReviewMode == '0') || nextTab.innerHTML.includes('roundpointStudent lock')) { j++; continue; } if (nextTab.id.indexOf('cur') < 0) { j++; continue; } const clickF = setInterval(function () { if (rd != unsafeWindow.top.unrivalPageRd) { clearInterval(clickF); return; } nextTab.click(); }, 2000); break; } break; } } } }, 2000); } catch (e) { Logger.addLog('跳转失败: ' + e.message, 'red'); } }; if (unsafeWindow.onReadComplete1) { unsafeWindow.onReadComplete1(); } setTimeout(`jjump("${unsafeWindow.top.unrivalPageRd}")`, 2856); } }, 200); }, // 解析题目 parseQuestions() { const questionList = []; const questionsElement = document.getElementsByClassName('Py-mian1'); const questionNum = questionsElement.length; for (let i = 0; i < questionNum; i++) { const questionElement = questionsElement[i]; const idElements = questionElement.getElementsByTagName('input'); let questionId = '0'; let question = ''; try { question = questionElement.getElementsByClassName('Py-m1-title fs16')[0].innerHTML; question = Utils.handleImgs(question) .replace(/(<([^>]+)>)/ig, '') .replace(/[0-9]{1,3}.\[(.*?)\]/ig, '') .replaceAll('\n', '') .replace(/^\s+/ig, '') .replace(/\s+$/ig, ''); } catch (e) { continue; } for (let z = 0, k = idElements.length; z < k; z++) { try { if (idElements[z].getAttribute('name') && idElements[z].getAttribute('name').indexOf('answer') >= 0) { questionId = idElements[z].getAttribute('name').replace('type', ''); break; } } catch (e) { continue; } } if (questionId == '0' || question == '') { continue; } const typeE = questionElement.getElementsByTagName('input'); if (!typeE || typeE.length === 0) { continue; } let typeN = 'fuckme'; for (let g = 0, h = typeE.length; g < h; g++) { try { if (typeE[g].id == 'answertype' + questionId.replace('answer', '').replace('check', '')) { typeN = typeE[g].value; break; } } catch (e) { continue; } } if (['0', '1', '3'].indexOf(typeN) < 0) { continue; } const type = { '0': '单选题', '1': '多选题', '3': '判断题' }[typeN]; const optionList = { length: 0 }; if (['单选题', '多选题'].indexOf(type) >= 0) { try { const answersElements = questionElement.getElementsByClassName('answerList')[0].getElementsByTagName('li'); for (let x = 0, j = answersElements.length; x < j; x++) { const optionE = answersElements[x]; const optionTextE = Utils.trim(optionE.innerHTML.replace(/(^\s*)|(\s*$)/g, "")); const optionText = optionTextE.slice(1).replace(/(^\s*)|(\s*$)/g, ""); const optionValue = optionTextE.slice(0, 1); const optionId = optionE.getAttribute('id-param'); if (optionText == '') { break; } optionList[optionText] = { 'id': optionId, 'value': optionValue }; optionList.length++; } if (answersElements.length != optionList.length) { continue; } } catch (e) { continue; } } questionList.push({ 'question': question, 'type': type, 'questionid': questionId, 'options': optionList }); } return questionList; }, // 处理题目 processQuestions(questionList, wid) { let nowTime = -4000; let busyThread = questionList.length; const ctOnload = function (res, quu) { busyThread -= 1; let ctResult = { 'code': -1, 'finalUrl': '', 'data': '未找到答案' }; if (res) { try { const responseText = res.responseText; ctResult = JSON.parse(responseText); } catch (e) { if (res.finalUrl && res.finalUrl.includes('getAnswer.php')) { unsafeWindow.top.unrivalWorkInfo = '查题错误,服务器连接失败'; return; } } } try { const choiceEs = document.getElementsByTagName('li'); if (ctResult['code'] == -1) { try { if (ctResult['msg'] !== undefined) { unsafeWindow.top.unrivalWorkInfo = '题目:' + quu['question'] + ':未搜索到答案'; } } catch (e) {} // 自动选择 if (Config.get('randomDo') == 1 && Config.get('accuracy') < 100) { switch (quu['type']) { case '判断题': unsafeWindow.top.unrivalWorkInfo = quu['question'] + ':未找到正确答案,自动选【错】'; for (let u = 0, k = choiceEs.length; u < k; u++) { try { if (choiceEs[u].getElementsByTagName('em').length < 1) { continue; } if (choiceEs[u].getAttribute('val-param') == 'false' && choiceEs[u].getAttribute('id-param') == quu['questionid'].replace('answer', '')) { choiceEs[u].click(); return; } } catch (e) { continue; } } break; case '单选题': unsafeWindow.top.unrivalWorkInfo = quu['question'] + ':未找到正确答案,自动选【B】'; for (let y = 0, j = choiceEs.length; y < j; y++) { try { if (choiceEs[y].getElementsByTagName('em').length < 1) { continue; } if (choiceEs[y].getElementsByTagName('em')[0].getAttribute('id-param') == 'B' && choiceEs[y].getAttribute('id-param') == quu['questionid'].replace('answer', '')) { if (!choiceEs[y].getAttribute('class').includes('cur')) { choiceEs[y].click(); } return; } } catch (e) { continue; } } break; case '多选题': unsafeWindow.top.unrivalWorkInfo = quu['question'] + ':未找到正确答案,自动全选'; for (let y = 0, j = choiceEs.length; y < j; y++) { try { if (choiceEs[y].getElementsByTagName('em').length < 1) { continue; } if (choiceEs[y].getAttribute('id-param') == quu['questionid'].replace('answer', '')) { if (!choiceEs[y].getAttribute('class').includes('cur')) { choiceEs[y].click(); } } } catch (e) { continue; } } break; } } return; } else if (ctResult['code'] == -2) { unsafeWindow.top.unrivalWorkInfo = ctResult['msg']; return; } try { const result = ctResult['data']; unsafeWindow.top.unrivalWorkInfo = '题目:' + quu['question'] + ':' + result; switch (quu['type']) { case '判断题': (function () { let answer = 'abaabaaba'; if ('正确是对√Tri'.indexOf(result) >= 0) { answer = 'true'; } else if ('错误否错×Fwr'.indexOf(result) >= 0) { answer = 'false'; } for (let u = 0, k = choiceEs.length; u < k; u++) { try { if (choiceEs[u].getAttribute('val-param') == answer && choiceEs[u].getAttribute('id-param') == quu['questionid'].replace('answer', '')) { choiceEs[u].click(); return; } } catch (e) { continue; } } })(); break; case '单选题': (function () { const answerData = result; for (const option in quu['options']) { try { if (Utils.trim(option).replace(/\s/ig, '') == Utils.trim(answerData).replace(/\s/ig, '') || Utils.trim(option).replace(/\s/ig, '').includes(Utils.trim(answerData).replace(/\s/ig, '')) || Utils.trim(answerData).replace(/\s/ig, '').includes(Utils.trim(option).replace(/\s/ig, ''))) { for (let y = 0, j = choiceEs.length; y < j; y++) { try { if (choiceEs[y].getElementsByTagName('em').length < 1) { continue; } if (choiceEs[y].getElementsByTagName('em')[0].getAttribute('id-param') == quu['options'][option]['value'] && choiceEs[y].getAttribute('id-param') == quu['questionid'].replace('answer', '')) { if (!choiceEs[y].getAttribute('class').includes('cur')) { choiceEs[y].click(); } return; } } catch (e) { continue; } } } } catch (e) { continue; } } })(); break; case '多选题': (function () { const answerData = Utils.trim(result).replace(/\s/ig, ''); let hasAnswer = false; for (const option in quu['options']) { try { if (answerData.includes(Utils.trim(option).replace(/\s/ig, ''))) { for (let y = 0, j = choiceEs.length; y < j; y++) { try { if (choiceEs[y].getElementsByTagName('em').length < 1) { continue; } if (choiceEs[y].getElementsByTagName('em')[0].getAttribute('id-param') == quu['options'][option]['value'] && choiceEs[y].getAttribute('id-param') == quu['questionid'].replace('answer', '')) { if (!choiceEs[y].getAttribute('class').includes('cur')) { choiceEs[y].click(); } hasAnswer = true; break; } } catch (e) { continue; } } } } catch (e) { continue; } } })(); break; } } catch (e) { unsafeWindow.top.unrivalWorkInfo = '答案解析失败'; } } catch (e) { Logger.addLog('处理题目时出错: ' + e.message, 'red'); } }; for (let i = 0, l = questionList.length; i < l; i++) { nowTime += Utils.random(3500, 6500); setTimeout(function () { const qu = questionList[i]; let param = 'question=' + encodeURIComponent(qu['question']); if (Config.get('ctUrl').includes('icodef')) { param += '&type=' + { '单选题': '0', '多选题': '1', '判断题': '3' }[qu['type']] + '&id=' + wid; } Network.post(Config.get('ctUrl'), param, { 'Content-type': 'application/x-www-form-urlencoded', 'Authorization': Config.get('token'), }, 2000) .then(res => ctOnload(res, qu)) .catch(() => ctOnload(false, qu)); }, nowTime); } // 检查答题完成 const workInterval = setInterval(function () { if (busyThread != 0) { return; } clearInterval(workInterval); const totalQuestionNum = questionList.length; const answeredNum = totalQuestionNum - busyThread; const accuracy = Math.floor((answeredNum / totalQuestionNum) * 100); if (accuracy >= Config.get('accuracy') && unsafeWindow.top.unrivalAutoSubmit == '1') { unsafeWindow.top.unrivalDoneWorkId = Utils.getQueryVariable('workId'); unsafeWindow.top.unrivalWorkInfo = '正确率符合标准,已提交答案'; setTimeout(function () { try { if (typeof submitCheckTimes === 'function') submitCheckTimes(); if (typeof escapeBlank === 'function') escapeBlank(); if (typeof submitAction === 'function') submitAction(); } catch (e) { Logger.addLog('提交答案失败: ' + e.message, 'red'); } }, Utils.random(3000, 5000)); } else if (unsafeWindow.top.unrivalAutoSave == 1) { unsafeWindow.top.unrivalWorkInfo = '正确率不符合标准或未设置自动提交,已自动保存答案'; if (accuracy >= 0) { setTimeout(function () { unsafeWindow.top.unrivalDoneWorkId = Utils.getQueryVariable('workId'); if (typeof unsafeWindow.noSubmit === 'function') { unsafeWindow.noSubmit(); } }, 2000); } } else { unsafeWindow.top.unrivalWorkInfo = '用户设置为不自动保存答案,请手动提交或保存作业'; } }, 1000); }, // 显示后台任务 showBackgroundTasks() { const jobList = GM_getValue('unrivalBackgroundList', '1'); const joblistElement = document.getElementById('joblist'); if (!joblistElement) return; if (jobList == '1') { joblistElement.innerHTML = '请将“超星挂机小助手”升级到最新版并重启浏览器'; return; } try { let jobHtml = ''; for (let i = 0, l = jobList.length; i < l; i++) { let status = ''; if (jobList[i]['done']) { status = '已完成'; } else if (parseInt(jobList[i]['playTime']) > 0) { status = '进行中'; } else { status = '等待中'; } if (jobList[i]['review']) { status += ':复习模式'; } jobHtml += `
[${status}]${jobList[i]['name']}
`; } joblistElement.innerHTML = jobHtml; } catch (e) { joblistElement.innerHTML = '请将“超星挂机小助手”升级到最新版并重启浏览器!'; } } }; // 自动登录模块 const AutoLogin = { // 执行自动登录 execute() { if (!(/^1[3456789]\d{9}$/.test(Config.get('phoneNumber')))) { alert('自动登录的手机号填写错误,无法登陆'); return; } if (Config.get('password') == '') { alert('未填写登录密码,无法登陆'); return; } Network.get(`https://passport2-api.chaoxing.com/v11/loginregister?cx_xxt_passport=json&uname=${Config.get('phoneNumber')}&code=${encodeURIComponent(Config.get('password'))}`) .then(res => { try { const ispass = JSON.parse(res.responseText); if (ispass['status']) { const refer = Utils.getQueryVariable('refer'); if (refer) { location.href = decodeURIComponent(refer); } } else { alert(ispass['mes']); } } catch (err) { alert('登陆失败'); } }) .catch(err => { alert('登陆错误'); }); } }; // 主入口 const Main = { // 初始化 init() { console.log('学习通小助手:初始化开始'); // 检查脚本冲突 try { if (unsafeWindow.unrivalScriptList && unsafeWindow.unrivalScriptList.length > 1) { console.log('学习通小助手:检测到多个刷课脚本'); if (typeof Logger !== 'undefined' && Logger.addLog) { Logger.addLog('您同时开启了多个刷课脚本,会挂科,会挂科,会挂科,会挂科,会挂科,会挂科,会挂科,会挂科', 'red'); } } unsafeWindow.unrivalScriptList = ['Fuck me please']; } catch (e) { console.log('学习通小助手:脚本冲突检查错误', e); unsafeWindow.unrivalScriptList = ['Fuck me please']; } // 根据页面类型初始化 const href = location.href; console.log('学习通小助手:当前页面URL', href); if (href.indexOf("knowledge/cards") > 0) { console.log('学习通小助手:初始化知识卡片页面'); if (typeof PageHandler !== 'undefined' && PageHandler.initKnowledgeCardsPage) { PageHandler.initKnowledgeCardsPage(); } else { console.error('学习通小助手:PageHandler未定义'); } } else if (href.includes("mycourse/studentstudy")) { console.log('学习通小助手:初始化学生学习页面'); if (typeof PageHandler !== 'undefined' && PageHandler.initStudentStudyPage) { PageHandler.initStudentStudyPage(); } else { console.error('学习通小助手:PageHandler未定义'); } } else if (href.indexOf("work/phone/doHomeWork") > 0) { console.log('学习通小助手:初始化答题页面'); if (typeof PageHandler !== 'undefined' && PageHandler.initDoHomeWorkPage) { PageHandler.initDoHomeWorkPage(); } else { console.error('学习通小助手:PageHandler未定义'); } } else if (href.includes('work/phone/selectWorkQuestionYiPiYue')) { console.log('学习通小助手:初始化题目选择页面'); unsafeWindow.top.unrivalWorkDone = true; if (typeof Utils !== 'undefined' && Utils.getQueryVariable) { unsafeWindow.top.unrivalDoneWorkId = Utils.getQueryVariable('workId'); } else { console.error('学习通小助手:Utils未定义'); } } else if (href.includes('stat2-ans.chaoxing.com/task/s/index')) { console.log('学习通小助手:初始化学习统计页面'); if (unsafeWindow.top == unsafeWindow) { console.log('学习通小助手:跳过学习统计页面'); return; } const studentStatistic = document.getElementsByClassName('page-container studentStatistic')[0]; if (studentStatistic) { studentStatistic.setAttribute('class', 'studentStatistic'); } const itemTaskList = document.getElementsByClassName('page-item item-task-list minHeight390')[0]; if (itemTaskList) { itemTaskList.remove(); } const subNav = document.getElementsByClassName('subNav clearfix')[0]; if (subNav) { subNav.remove(); } setInterval(function () { location.reload(); }, 90000); } else if (href.includes('passport2.') && href.includes('login?refer=http') && Config.get('autoLogin') == 1) { console.log('学习通小助手:初始化自动登录'); if (typeof AutoLogin !== 'undefined' && AutoLogin.execute) { AutoLogin.execute(); } else { console.error('学习通小助手:AutoLogin未定义'); } } else if (href.includes('unrivalxxtbackground')) { console.log('学习通小助手:初始化后台挂机页面'); if (typeof PageHandler !== 'undefined' && PageHandler.initBackgroundPage) { PageHandler.initBackgroundPage(); } else { console.error('学习通小助手:PageHandler未定义'); } } else { console.log('学习通小助手:当前页面不匹配任何处理逻辑'); // 尝试在页面上显示提示信息 try { if (document.body) { const infoDiv = document.createElement('div'); infoDiv.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; background: blue; color: white; padding: 10px; z-index: 9999;'; infoDiv.textContent = '学习通小助手:当前页面不支持自动刷课,请进入课程学习页面'; document.body.insertBefore(infoDiv, document.body.firstChild); } } catch (e) { console.error('学习通小助手:显示提示信息失败', e); } } console.log('学习通小助手:初始化完成'); } }; // 启动脚本 try { console.log('学习通小助手:开始执行'); Main.init(); console.log('学习通小助手:执行完成'); } catch (error) { console.error('学习通小助手:执行错误', error); // 尝试在页面上显示错误信息 try { if (document.body) { const errorDiv = document.createElement('div'); errorDiv.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; background: red; color: white; padding: 10px; z-index: 9999;'; errorDiv.textContent = '学习通小助手执行错误: ' + error.message; document.body.insertBefore(errorDiv, document.body.firstChild); } } catch (e) {} } })();