// ==UserScript== // @name 兰秋xxt(课) // @namespace https://bbs.tampermonkey.net.cn/ // @version 0.2.0 // @description try to take over the world! // @author LQ // @match *://*.chaoxing.com/* // @connect q.icodef.com // @run-at document-end // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_setClipboard // @grant GM_setValue // @grant GM_getValue // @grant GM_info // @grant GM_getResourceText // @require https://greasyfork.org/scripts/445293/code/TyprMd5.js // @require https://cdn.staticfile.org/limonte-sweetalert2/11.0.1/sweetalert2.all.min.js // @require https://cdn.staticfile.org/jquery/3.6.0/jquery.min.js // @resource Table https://www.forestpolice.org/ttf/2.0/table.json // ==/UserScript== (function() { 'use strict'; var _window = unsafeWindow, _location = location, _d = _window.document, $ = _window.jQuery || top.jQuery, md5 = md5 || window.md5, UE = _window.UE, Swal = Swal || window.Swal, _host = "https://q.icodef.com"; var _mlist, _defaults, _domList; var $subBtn, $saveBtn, $frame_c; var reportUrlChange = 0; var setting ={ review: 0, // 复习模式 work: 1, // 做测验 delayTime: 4000, // 延迟时间 video: 1, // 视频 tash: 1, // 只处理任务点任务 rate:2, // 视频倍速 sub:1, // 测验自动提交 force: 0, // 测验强制提交 token: "jJdcbuwCmXL71B2o", // every-api token } decryptFont(); // https://mooc1.chaoxing.com/mycourse/studentstudy? // chapterId=995044321& // courseId=245627009& // clazzid=104640032& // cpi=152846479& // enc=f755814018af976076b03a3fc8ab3910& // mooc2=1& // openc=4a45097897dcfc34be21302f7b4556dc if (_location.pathname.includes('/mycourse/studentstudy')) { showBox() $('#ne-21log', window.parent.document).html('初始化完毕!') } else if (_location.pathname.includes('/knowledge/cards')) { var params = getTaskParams() if (params == null || params == '$mArg' || $.parseJSON(params)['attachments'].length <= 0) { logger('无任务点可处理,即将跳转页面', 'red') toNext() } else { setTimeout(() => { top.checkJob ? top.checkJob = () => false : true _domList = [] _mlist = $.parseJSON(params)['attachments'] _defaults = $.parseJSON(params)['defaults'] $.each($('.wrap .ans-cc .ans-attach-ct'), (i, t) => { _domList.push($(t).find('iframe')) }) missonStart() }, 3000) } } else if (_location.pathname.includes('/exam/test/reVersionTestStartNew')) { showBox() setTimeout(() => { missonExam() }, 3000) } // 展示日志 function showBox() { if (top.document.querySelector('#ne-21box') == undefined) { var box_html = `
`; $(box_html).appendTo('body'); } else { $('#ne-21log', window.parent.document).html('') } } function logger(str, color) { // 1. 选择父窗口中的日志容器元素 let logSelector = $('#ne-21log', window.parent.document); // 2. 获取当前时间(时:分:秒) let _time = new Date().toLocaleTimeString(); // 3. 创建日志条目元素(带时间戳和指定颜色) $('

[' + _time + ']' + str + '

') .prependTo(logSelector) // 添加到日志容器顶部 .on("click", function () { // 绑定点击事件 // 4. 点击时复制日志中的特定内容(从"题目:"到"
---->"之间的文本) GM_setClipboard(getStr($(this).html(), "题目:", "
---->")); // 5. 显示复制成功提示 Swal.fire({ text: '已复制', position: 'top-end', width: 150, timer: 1500, showConfirmButton: false, }); }); } function toNext() { refreshCourseList().then((res) => { // 不做作业,或者是复习模式 if (setting.review || !setting.work) { setTimeout(() => { if (top.document.querySelector("#mainid > .prev_next.next") == void 0) { top.document.querySelector("#prevNextFocusNext").click(); return; } top.document.querySelector("#mainid > .prev_next.next").click(); // top.document.querySelector('#prevNextFocusNext.jb_btn.jb_btn_92.fs14.prev_next.next.fr').click(); }, setting.delayTime) // 点击下一节按钮 return } // 解析课程章节数据 let _t = [] $.each($(res).find('li'), (_, t) => { let curid = $(t).find('.posCatalog_select').attr('id'), status = $(t).find('.prevHoverTips').text(), name = $(t).find('.posCatalog_name').attr('title'); if (curid.indexOf('cur') != -1) { _t.push({ 'curid': curid, 'status': status, 'name': name }) } }) // 定位当前章节并查找下一个带完成任务 let _curChaterId = $('#coursetree', window.parent.document).find('.posCatalog_active').attr('id') let _curIndex = _t.findIndex((item) => item['curid'] == _curChaterId) for (_curIndex; _curIndex < _t.length - 1; _curIndex++) { // 检查当前章节是否未完成 if (_t[_curIndex]['status'].indexOf('待完成') != -1) { setTimeout(() => { top.document.querySelector('#prevNextFocusNext.jb_btn.jb_btn_92.fs14.prev_next.next.fr').click(); }, Math.random * setting.delayTime) // 点击下一节按钮 return } // 检查下一个章节的状态 let t = _t[_curIndex + 1] if (t['status'].indexOf('待完成') != -1) { setTimeout(() => { top.document.querySelector('#prevNextFocusNext.jb_btn.jb_btn_92.fs14.prev_next.next.fr').click(); showBox() }, Math.random * setting.delayTime) // 点击下一节按钮 return } else if (t['status'].indexOf('闯关模式') != -1) { logger('当前为闯关模式,请完成之前的章节', 'red') return } else if (t['status'].indexOf('开放时间') != -1) { logger('章节未开放', 'red') } } logger('此课程处理完毕', 'green') return }) } function missonStart() { showBox(); if (_mlist.length <= 0) { logger('此页面任务处理完毕,准备跳转页面', 'green') return toNext() } let _type = _mlist[0]['type'], _dom = _domList[0], _task = _mlist[0]; if (_type == undefined) { _type = _mlist[0]['property']["module"] } switch (_type) { case "video": if (_mlist[0]['property']['module'] == 'insertvideo') { logger('开始处理视频', 'purple'); missonVideo(_dom, _task); break; } else { logger('未知类型任务,跳过', 'red'); switchMission(); break; } case "workid": logger('开始处理测验', 'purple'); missonWork(_dom, _task); break; case "document": logger('开始处理文档', 'purple'); missonDoucument(_dom, _task); break; case "read": logger('开始处理阅读', 'purple'); missonRead(_dom, _task); break; default: logger('不支持此类型,跳过','red'); switchMission(); break; } } function switchMission() { _mlist.splice(0, 1) _domList.splice(0, 1) setTimeout(missonStart, 5000) } function missonVideo(dom, obj) { if (!setting.video) { logger('用户设置不处理视频任务,准备开始下一个任务。', 'red') setTimeout(() => { switchMission() }, Math.random * setting.delayTime) return } let isDo; if (setting.task) { logger("当前只处理任务点任务", 'red') if (obj['jobid'] == undefined ? false : true) { isDo = true } else { isDo = false } } else { logger("当前默认处理所有任务(包括非任务点任务)", 'red') isDo = true } if (isDo) { let classId = _defaults['clazzId'], userId = _defaults['userid'], fid = _defaults['fid'], reportUrl = _defaults['reportUrl'], isPassed = obj['isPassed'], otherInfo = obj['otherInfo'], jobId = obj['property']['_jobid'], name = obj['property']['name'], objectId = obj['property']['objectid']; // 图片遮挡 let ifs = $(dom).attr('style'); $(dom).contents().find('body').find('.main').attr('style', 'visibility:hidden;') $(dom).contents().find('body').prepend('') // 视频状态检测 if (!setting.review && isPassed == true) { logger('视频:' + name + '检测已完成,准备处理下一个任务', 'green') switchMission() return } else if (setting.review) { logger('已开启复习模式,开始处理视频:' + name, 'pink') } $.ajax({ url: _location.protocol + '//' + _location.host + "/ananas/status/" + objectId + '?k=' + fid + '&flag=normal&_dc=' + String(Math.round(new Date())), type: "GET", success: function (res) { try { let duration = res['duration'], dtoken = res['dtoken'], clipTime = '0_' + duration, playingTime = 0, isdrag = 3; var _rt = 0.9; if (setting.rate == 0) { logger('已开启视频秒过,可能会导致进度重置、挂科等问题。', 'red') } else if (setting.rate > 1 && setting.rate <= 16) { logger('已开启视频倍速,当前倍速:' + setting.rate, 'blue') logger('已经开启倍速, 进度40秒更新一次', 'blue') } else if (setting.rate > 16) { setting.rate = 2 logger('超过允许设置的最大倍数, 已重置为2倍速。', 'red') } else { logger("视频进度每隔40秒更新一次, 请等待耐心等待...", 'blue') } logger("视频:" + name + "开始播放") updateVideo(reportUrl, dtoken, classId, playingTime, duration, clipTime, objectId, otherInfo, jobId, userId, isdrag, _rt).then((status) => { switch (status) { case 1: logger("视频:" + name + "已播放" + String((playingTime / duration) * 100).slice(0, 4) + '%', 'purple') isdrag = 0 break case 3: _rt = 1 break default: console.log(status) } }) let _loop = setInterval(() => { playingTime += 40 * setting.rate if (playingTime >= duration || setting.rate == 0) { clearInterval(_loop) // 清除定时器 playingTime = duration // 强制设为总时长 isdrag = 4 // 标记为播放完成状态 } else if (_rt == 1 && playingTime == 40 * setting.rate) { isdrag = 3 } else { isdrag = 0 } updateVideo(reportUrl, dtoken, classId, playingTime, duration, clipTime, objectId, otherInfo, jobId, userId, isdrag, _rt).then((status) => { switch (status) { case 0: playingTime -= 40 break case 1: logger("视频:" + name + "已播放" + String((playingTime / duration) * 100).slice(0, 4) + '%', 'purple') break case 2: clearInterval(_loop) logger("视频:" + name + "检测播放完毕,准备处理下一个任务。", 'green') switchMission() break case 3: playingTime -= 40 _rt = Number(_rt) == 1 ? 0.9 : 1 break default: console.log(status) } }) }, setting.rate == 0 ? 5000 : 40000) } catch (e) { logger('发生错误:' + e, 'red') } } }); } else { logger('用户设置只处理属于任务点的任务,准备处理下一个任务', 'green') switchMission() return } } function updateVideo(reportUrl, dtoken, classId, playingTime, duration, clipTime, objectId, otherInfo, jobId, userId, isdrag, _rt) { return new Promise((resolve) => { getEnc(classId, userId, jobId, objectId, playingTime, duration, clipTime).then((enc) => { if (reportUrlChange) { reportUrl = http2https(reportUrl) } $.ajax({ url: reportUrl + '/' + dtoken + '?clazzId=' + classId + '&playingTime=' + playingTime + '&duration=' + duration + '&clipTime=' + clipTime + '&objectId=' + objectId + '&otherInfo=' + otherInfo + '&jobid=' + jobId + '&userid=' + userId + '&isdrag=' + isdrag + '&view=pc&enc=' + enc + '&rt=' + Number(_rt) + '&dtype=Video&_t=' + String(Math.round(new Date())), type: 'GET', success: function (res) { try { if (res['isPassed']) { if (setting.review && playingTime != duration) { resolve(1) } else { resolve(2) } } else { if (setting.rate == 0 && playingTime == duration) { resolve(2) } else { resolve(1) } } } catch (e) { logger('发生错误:' + e, 'red') resolve(0) } }, error: function (xhr) { if (xhr.status == 403) { logger('超星返回错误信息, 尝试更换参数, 40s后将重试', 'red') resolve(3) } else { reportUrlChange = 1; logger('超星返回错误信息', 'red') } } }) }) }); } function missonDoucument(dom, obj) { if (setting.task) { if (obj['jobid'] == undefined) { logger("当前只处理任务点任务,跳过", 'red') switchMission() return } } let jobId = obj['property']['jobid'], name = obj['property']['name'], jtoken = obj['jtoken'], knowledgeId = _defaults['knowledgeid'], courseId = _defaults['courseid'], clazzId = _defaults['clazzId']; if (obj['job'] == undefined) { logger('文档:' + name + '检测已完成,准备执行下一个任务。', 'green') switchMission() return } $.ajax({ url: _location.protocol + "//" + _location.host + '/ananas/job/document?jobid=' + jobId + '&knowledgeid=' + knowledgeId + '&courseid=' + courseId + '&clazzid=' + clazzId + '&jtoken=' + jtoken + '&_dc=' + String(Math.round(new Date())), method: 'GET', success: function (res) { if (res.status) { logger('文档:' + name + res.msg + ',准备执行下一个任务。', 'green') } else { logger('文档:' + name + '处理异常,跳过。', 'red') } switchMission() return } }) } function missonRead(dom, obj) { if (setting.task) { if (obj['jobid'] == undefined) { logger("当前只处理任务点任务,跳过", 'red') switchMission() return } } let jobId = obj['property']['jobid'], name = obj['property']['title'], jtoken = obj['jtoken'], knowledgeId = _defaults['knowledgeid'], courseId = _defaults['courseid'], clazzId = _defaults['clazzId']; if (obj['job'] == undefined) { logger('阅读:' + name + ',检测已完成,准备执行下一个任务。', 'green') switchMission() return } $.ajax({ url: _location.protocol + '//' + _location.host + '/ananas/job/readv2?jobid=' + jobId + '&knowledgeid=' + knowledgeId + '&courseid=' + courseId + '&clazzid=' + clazzId + '&jtoken=' + jtoken + '&_dc=' + String(Math.round(new Date())), method: 'GET', success: function (res) { if (res.status) { logger('阅读:' + name + res.msg + ',准备执行下一个任务。', 'green') } else { logger('阅读:' + name + '处理异常,跳过。', 'red') } switchMission() return } }) } function missonWork(dom, obj) { // 不处理测验 if (!setting.work) { logger('用户设置不自动处理测验,准备处理下一个任务', 'green') switchMission() return } let isDo; if (setting.task) { logger("当前只处理任务点任务", 'red') if (obj['jobid'] == undefined ? false : true) { isDo = true } else { isDo = false } } else { logger("当前默认处理所有任务(包括非任务点任务)", 'red') isDo = true } if (isDo) { if (obj['jobid'] !== undefined) { var phoneWeb = _location.protocol + '//' + _location.host + '/work/phone/work?workId=' + obj['jobid'].replace('work-', '') + '&courseId=' + _defaults['courseid'] + '&clazzId=' + _defaults['clazzId'] + '&knowledgeId=' + _defaults['knowledgeid'] + '&jobId=' + obj['jobid'] + '&enc=' + obj['enc'] // 调用移动端处理函数 setTimeout(() => { startDoPhoneCyWork(0, dom, phoneWeb) }, 3000) } else { // 调用PC端处理函数 setTimeout(() => { startDoCyWork(0, dom) }, 3000) } } else { logger('用户设置只处理属于任务点的任务,准备处理下一个任务', 'green') switchMission() return } } function startDoPhoneCyWork(index, doms, phoneWeb) { // 任务列表遍历完成 if (index == doms.length) { logger('此页面全部测验已处理完毕!准备进行下一项任务') setTimeout(missonStart, 5000) return } logger('等待测验框架加载...', 'purple') getElement($(doms[index]).contents()[0], 'iframe').then(element => { let workIframe = element if (workIframe.length == 0) { setTimeout(() => { startDoPhoneCyWork(index, doms) }, 5000) } let workStatus = $(workIframe).contents().find('.newTestCon .newTestTitle .testTit_status').text().trim() if (!workStatus) { logger("获取测验状态失败", "red"); _domList.splice(0, 1) setTimeout(missonStart, 2000); return } if (workStatus.indexOf("已完成") != -1) { logger('测验:' + (index + 1) + ',检测到此测验已完成,准备跳转。', 'green') setTimeout(()=>{switchMission()},2000) } else if (workStatus.indexOf("待做") != -1 || workStatus.indexOf("待完成") != -1) { logger('测验:' + (index + 1) + ',准备处理此测验...', 'purple') $(workIframe).attr('src', phoneWeb) getElement($(doms[index]).contents()[0], 'iframe[src="' + phoneWeb + '"]').then((element) => { setTimeout(() => { doPhoneWork($(element).contents()) }, 3000) }) } else if (workStatus.indexOf('待批阅') != -1) { _mlist.splice(0, 1) _domList.splice(0, 1) logger('测验:' + (index + 1) + ',测验待批阅,跳过', 'red') setTimeout(() => { startDoPhoneCyWork(index + 1, doms, phoneWeb) }, Math.random * setting.delayTime) } else { _mlist.splice(0, 1) _domList.splice(0, 1) logger('测验:' + (index + 1) + ',未知状态或用户选择不收录答案,跳过', 'red') setTimeout(() => { startDoPhoneCyWork(index + 1, doms, phoneWeb) }, Math.random * setting.delayTime) } }) } function startDoCyWork(index, doms) { if (index == doms.length) { logger('此页面全部测验已处理完毕!准备进行下一项任务') setTimeout(missonStart, 5000) return } logger('等待测验框架加载...', 'purple') getElement($(doms[index]).contents()[0], 'iframe').then(element => { let workIframe = element if (workIframe.length == 0) { setTimeout(() => { startDoCyWork(index, doms) }, 5000) } let workStatus = $(workIframe).contents().find('.newTestCon .newTestTitle .testTit_status').text().trim() if (!workStatus) { logger("获取测验状态失败", "red"); _domList.splice(0, 1) setTimeout(missonStart, 2000) return } if (setting.share && workStatus.indexOf("已完成") != -1) { logger('测验:' + (index + 1) + ',检测到此测验已完成,准备收录答案。', 'green') // setTimeout(() => { upLoadWork(index, doms, workIframe) }, 2000) } else if (workStatus.indexOf("待做") != -1) { logger('测验:' + (index + 1) + ',准备处理此测验...', 'purple') setTimeout(() => { doWork(index, doms, workIframe) }, 5000) } else if (workStatus.indexOf('待批阅') != -1) { _mlist.splice(0, 1) _domList.splice(0, 1) logger('测验:' + (index + 1) + ',测验待批阅,跳过', 'red') setTimeout(() => { startDoCyWork(index + 1, doms) }, 5000) } else { _mlist.splice(0, 1) _domList.splice(0, 1) logger('测验:' + (index + 1) + ',未知状态或用户选择不收录答案,跳过', 'red') setTimeout(() => { startDoCyWork(index + 1, doms) }, 5000) } }) } function doPhoneWork($dom) { let $cy = $dom.find('.Wrappadding form') $subBtn = $cy.find('.zquestions .zsubmit .btn-ok-bottom') $saveBtn = $cy.find('.zquestions .zsubmit .btn-save') let TimuList = $cy.find('.zquestions .Py-mian1') startDoPhoneTimu(0, TimuList) } function doWork(index, doms, dom) { $frame_c = $(dom).contents(); let $CyHtml = $frame_c.find('.CeYan') let TiMuList = $CyHtml.find('.TiMu') $subBtn = $CyHtml.find('.ZY_sub').find('.Btn_blue_1') $saveBtn = $CyHtml.find('.ZY_sub').find('.btnGray_1') startDoWork(index, doms, 0, TiMuList) } function startDoPhoneTimu(index, TimuList) { if (index == TimuList.length) { if (setting.sub) { logger('测验处理完成,准备自动提交。', 'green') setTimeout(() => { $subBtn.click() setTimeout(()=>{ const outerIframe = top.document.querySelector('#iframe'); // 外层iframe if (outerIframe) { // 获取外层iframe的文档 const outerDoc = outerIframe.contentDocument || outerIframe.contentWindow.document; // 从中层iframe const middleIframe = outerDoc.querySelector("iframe"); if (middleIframe) { // 获取中层iframe的文档 const middleDoc = middleIframe.contentDocument || middleIframe.contentWindow.document; // 从内层iframe获取元素 const innerIframe = middleDoc.getElementById('frame_content'); if (innerIframe) { // 获取内层iframe的文档 const innerDoc = innerIframe.contentDocument || innerIframe.contentWindow.document; // 在内层文档中查找元素 const targetElement = innerDoc.getElementById('okBtn'); if (targetElement) { // 操作目标元素 targetElement.click(); } } } } setTimeout(() => { logger('提交成功,准备切换下一个任务。', 'green') _mlist.splice(0, 1) _domList.splice(0, 1) setTimeout(() => { switchMission() }, 3000) }, setting.delayTime) },3000) }, setting.delayTime) } else { logger('测验处理完成,存在无答案题目,自动保存!', 'green') setTimeout(() => { // $saveBtn.click() setTimeout(() => { logger('保存成功,准备切换下一个任务。', 'green') _mlist.splice(0, 1) _domList.splice(0, 1) setTimeout(() => { switchMission() }, 3000) }, 3000) },setting.delayTime) } return } let questionFull = $(TimuList[index]).find('.Py-m1-title').html() let _question = tidyQuestion(questionFull).replace(/.*?\[.*?题\]\s*\n\s*/, '').trim() let _type = ({ 单选题: 0, 多选题: 1, 填空题: 2, 判断题: 3, 简答题: 4, 选择题: 5 })[questionFull.match(/.*?\[(.*?)]|$/)[1]] let _a = [] let _answerTmpArr switch (_type) { case 0: // 单选题 // alert("danxuanti") getAnswer(_type, _question).then((agrs) => { // 提取当前题目选项,将处理后的选项文本存入数组 _a _answerTmpArr = $(TimuList[index]).find('.answerList.singleChoice li') $.each(_answerTmpArr, (i, t) => { _a.push(tidyStr($(t).html()).replace(/^[A-Z]\s*\n\s*/, '').trim()) }) // 匹配正确答案并选择 let _i = _a.findIndex((item) => item == agrs) if (_i == -1) { logger('未匹配到正确答案,跳过此题', 'red') setting.sub = 0 setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) } else { // 找到匹配答案 $(_answerTmpArr[_i]).click() logger('自动答题成功,准备切换下一题', 'green') setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) } }).catch((agrs) => { setting.sub = 0 if (agrs['c'] == 0) { setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) } }) break; case 1: // 多选题 getAnswer(_type, _question).then((agrs) => { if (agrs == '暂无答案') { logger('未匹配到正确答案,跳过此题', 'red') setting.sub = 0 setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) } else { // 提取并处理选项 _answerTmpArr = $(TimuList[index]).find('.answerList.multiChoice li') $.each(_answerTmpArr, (i, t) => { let _tt = tidyStr($(t).html()).replace(/^[A-Z]\s*\n\s*/, '').trim() if (agrs.indexOf(_tt) != -1) { // 选中 setTimeout(() => { $(_answerTmpArr[i]).click() }, 300) } }) // 检查是否选中 let check = 0 setTimeout(() => { $.each(_answerTmpArr, (i, t) => { if ($(t).attr('class').indexOf('cur') != -1) { check = 1 } }) if (check) { logger('自动答题成功,准备切换下一题', 'green') } else { logger('未能正确选择答案,请手动选择,跳过此题', 'red') setting.sub = 0 } setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) }, 1000) } }).catch((agrs) => { setting.sub = 0 if (agrs['c'] == 0) { setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) } }) break; case 2: // 填空题 getAnswer(_type, _question).then((agrs) => { if (agrs == '暂无答案') { logger('未匹配到正确答案,跳过此题', 'red') setting.sub = 0 setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) return } let answers = agrs.split('#') let tkList = $(TimuList[index]).find('.blankList2 input') $.each(tkList, (i, t) => { setTimeout(() => { $(t).val(answers[i]) }, 200) }) setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) }).catch((agrs) => { setting.sub = 0 if (agrs['c'] == 0) { setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) } }) break; case 3: // 判断题 getAnswer(_type, _question).then((agrs) => { if (agrs == '暂无答案') { logger('未匹配到正确答案,跳过此题', 'red') setting.sub = 0 setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) } else { let _true = '正确|是|对|√|T|ri' _answerTmpArr = $(TimuList[index]).find('.answerList.panduan li') if (_true.indexOf(agrs) != -1) { $.each(_answerTmpArr, (i, t) => { if ($(t).attr('val-param') == 'true') { $(t).click() } }) } else { $.each(_answerTmpArr, (i, t) => { if ($(t).attr('val-param') == 'false') { $(t).click() } }) } logger('自动答题成功,准备切换下一题', 'green') setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) } }).catch((agrs) => { setting.sub = 0 if (agrs['c'] == 0) { setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) } }) break; case 4: // 简答题 getAnswer(_type, _question).then((agrs) => { if (agrs == '暂无答案') { logger("未匹配到正确答案,跳过此题", "red") setting.sub = 0 setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.delayTime) return } logger("简答题不支持自动填入,请参考修改答案,手动完成。", "purple"); setting.sub = 0 setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.time) }).catch((agrs) => { setting.sub = 0 if (agrs['c'] == 0) { setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.time) } }) break; case 5: getAnswer(_type, _question).then(() => { setting.sub = 0 logger('此类型题目无法区分单/多选,请手动选择答案', 'red') setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.time) }).catch((agrs) => { setting.sub = 0 if (agrs['c'] == 0) { setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.time) } }) break default: logger('暂不支持处理此类型题目:' + questionFull.match(/.*?\[(.*?)]|$/)[1] + ',跳过!请手动作答。', 'red') setting.sub = 0 setTimeout(() => { startDoPhoneTimu(index + 1, TimuList) }, setting.time) break; } } function startDoWork(index, doms, c, TiMuList) { if (c == TiMuList.length) { if (setting.sub) { logger('测验处理完成,准备自动提交。', 'green') setTimeout(() => { $subBtn.click() setTimeout(() => { // 这个地方不一样 $frame_c.find('#confirmSubWin > div > div > a.bluebtn').click() logger('提交成功,准备切换下一个任务。', 'green') _mlist.splice(0, 1) _domList.splice(0, 1) setTimeout(() => { startDoCyWork(index + 1, doms) }, 3000) }, 3000) }, 5000) } else { logger('测验处理完成,存在无答案题目或者用户设置不提交。', 'red') } return } let questionFull = $(TiMuList[c]).find('.Zy_TItle.clearfix > div').html() // questionFull = tidyQuestion(questionFull).replace("/.*?/", ""); let _question = tidyQuestion(questionFull) let _TimuType = ({ 单选题: 0, 多选题: 1, 填空题: 2, 判断题: 3, 简答题: 4 })[questionFull.match(/^【(.*?)】|$/)[1]] let _a = [] let _answerTmpArr switch (_TimuType) { case 0: // 单选题 _answerTmpArr = $(TiMuList[c]).find('.Zy_ulTop li').find('a') $.each(_answerTmpArr, (i, t) => { _a.push(tidyStr($(t).html())) }) getAnswer(_TimuType, _question).then((agrs) => { let _i = _a.findIndex((item) => item == agrs) if (_i == -1) { logger('未匹配到正确答案,跳过', 'red') setting.sub = 0 } else { $(_answerTmpArr[_i]).parent().click(); // $(_answerTmpArr[_i]).parent().find('input').attr('checked', 'checked') } setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.delayTime) }).catch(() => { setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.delayTime) }) break case 1: // 多选题 _answerTmpArr = $(TiMuList[c]).find('.Zy_ulTop li').find('a') getAnswer(_TimuType, _question).then((agrs) => { $.each(_answerTmpArr, (i, t) => { if (agrs.indexOf(tidyStr($(t).html())) != -1) { $(_answerTmpArr[i]).parent().find('input').attr('checked', 'checked') _a.push(['A', 'B', 'C', 'D', 'E', 'F', 'G'][i]) } }) let id = getStr($(TiMuList[c]).find('.Zy_ulTop li:nth-child(1)').attr('onclick'), 'addcheck(', ');').replace('(', '').replace(')', '') if (_a.length <= 0) { logger('未匹配到正确答案,跳过', 'red') setting.sub = 0 } else { $(TiMuList[c]).find('.Zy_ulTop').parent().find('#answer' + id).val(_a.join("")) } setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.delayTime) }).catch(() => { setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.delayTime) }) break; // case 2: // let _textareaList = $(TiMuList[c]).find('.Zy_ulTk .XztiHover1') // getAnswer(_TimuType, _question).then((agrs) => { // let _answerList = agrs.split("#") // $.each(_textareaList, (i, t) => { // setTimeout(() => { // $(t).find('#ueditor_' + i).contents().find('.view p').html(_answerList[i]); // $(t).find('textarea').html('

' + _answerList[i] + '

') // }, 300) // }) // setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.time) // }).catch((agrs) => { // setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.time) // }) // break // case 3: // _answerTmpArr = $(TiMuList[c]).find('.Zy_ulBottom li') // let _true = '正确|是|对|√|T|ri' // let _false = '错误|否|错|×|F|wr' // getAnswer(_TimuType, _question).then((agrs) => { // if (_true.indexOf(agrs) != -1) { // $(TiMuList[c]).find('.Zy_ulBottom li').find('.ri').parent().find('input').attr('checked', 'checked') // } else if (_false.indexOf(agrs) != -1) { // $(TiMuList[c]).find('.Zy_ulBottom li').find('.wr').parent().find('input').attr('checked', 'checked') // } else { // logger('未匹配到正确答案,跳过', 'red') // setting.sub = 0 // } // setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.time) // }).catch((agrs) => { // setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.time) // }) // break // case 4: // let _textareaLista = $(TiMuList[c]).find('.Zy_ulTk .XztiHover1') // getAnswer(_TimuType, _question).then((agrs) => { // if (agrs == '暂无答案') { // setting.sub = 0 // } // let _answerList = agrs.split("#") // $.each(_textareaLista, (i, t) => { // setTimeout(() => { // $(t).find('#ueditor_' + i).contents().find('.view p').html(_answerList[i]); // $(t).find('textarea').html('

' + _answerList[i] + '

') // }, 300) // }) // setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.time) // }).catch(() => { // setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList) }, setting.time) // }) // break default: logger("未知题型,跳过", "red"); setTimeout(() => { startDoWork(index, doms, c + 1, TiMuList); }, setting.delayTime); } } function missonExam() { let $_examtable = $('.mark_table').find('.whiteDiv') let _questionFull = tidyStr($_examtable.find('h3.mark_name').html().trim()) let _qType = ({ 单选题: 0, 多选题: 1, 填空题: 2, 判断题: 3 })[_questionFull.match(/[(](.*?),.*?分[)]|$/)[1]] let _question = tidyQuestion(_questionFull.replace(/[(].*?分[)]/, '').replace(/^\s*/, '')) let $_ansdom = $_examtable.find('#submitTest').find('.stem_answer') let _answerTmpArr; let _a = [] switch (_qType) { case 0: // 单选题 _answerTmpArr = $_ansdom.find('.clearfix.answerBg .fl.answer_p') getAnswer(_qType, _question).then((agrs) => { $.each(_answerTmpArr, (i, t) => { _a.push(tidyStr($(t).html())) }) let _i = _a.findIndex((item) => item == agrs) if (_i == -1) { logger('未匹配到正确答案,跳过此题', 'red') setTimeout(toNextExam, 5000) } else { setTimeout(() => { if ($(_answerTmpArr[_i]).parent().find('span').attr('class').indexOf('check_answer') == -1) { $(_answerTmpArr[_i]).parent().click() logger('自动答题成功,准备切换下一题', 'green') toNextExam() } else { logger('此题已作答,准备切换下一题', 'green') toNextExam() } }, 300) } }).catch((agrs) => { if (agrs['c'] == 0) { toNextExam() } }) break; case 1: // 多选题 _answerTmpArr = $_ansdom.find('.clearfix.answerBg .fl.answer_p') getAnswer(_qType, _question).then((agrs) => { if ($_ansdom.find('.clearfix.answerBg span.check_answer_dx').length > 0) { logger('此题已作答,准备切换下一题', 'green') toNextExam() } else { $.each(_answerTmpArr, (i, t) => { if (agrs.indexOf(tidyStr($(t).html())) != -1) { setTimeout(() => { $(_answerTmpArr[i]).parent().click() }, 300) } }) logger('自动答题成功,准备切换下一题', 'green') toNextExam() } }).catch((agrs) => { if (agrs['c'] == 0) { toNextExam() } }) break; case 2: // 填空题 var _textareaList = $_ansdom.find('.Answer .divText .subEditor textarea') getAnswer(_qType, _question).then((agrs) => { let _answerTmpArr = agrs.split('#') $.each(_textareaList, (i, t) => { let _id = $(t).attr('id') setTimeout(() => { UE.getEditor(_id).setContent(_answerTmpArr[i]) }, 300) }) logger('自动答题成功,准备切换下一题', 'green') toNextExam() }).catch((agrs) => { if (agrs['c'] == 0) { toNextExam() } }) break; case 3: // 判断题 var _true = '正确|是|对|√|T|ri' var _false = '错误|否|错|×|F|wr' var _i = 0 _answerTmpArr = $_ansdom.find('.clearfix.answerBg .fl.answer_p') $.each(_answerTmpArr, (i, t) => { _a.push($(t).text().trim()) }) getAnswer(_qType, _question).then((agrs) => { if (_true.indexOf(agrs) != -1) { _i = _a.findIndex((item) => _true.indexOf(item) != -1) } else if (_false.indexOf(agrs) != -1) { _i = _a.findIndex((item) => _false.indexOf(item) != -1) } else { logger('答案匹配出错,准备切换下一题', 'green') toNextExam() return } if ($(_answerTmpArr[_i]).parent().find('span').attr('class').indexOf('check_answer') == -1) { setTimeout(() => { $(_answerTmpArr[_i]).parent().click() }, 300) logger('自动答题成功,准备切换下一题', 'green') toNextExam() } else { logger('此题已作答,准备切换下一题', 'green') toNextExam() } }).catch((agrs) => { if (agrs['c'] == 0) { toNextExam() } }) break default: logger("未知题目类型,不支持","red") toNextExam(); break; } } function toNextExam() { let $_examtable = $('.mark_table').find('.whiteDiv') let $nextbtn = $_examtable.find('.nextDiv a.jb_btn') setTimeout(() => { $nextbtn.click() }, (setting.delayTime + (Math.random() + 1)*1000)) } function getAnswer(_t, _q) { return new Promise((resolve, reject) => { let encodeQuestion = encodeURIComponent(_q); GM_xmlhttpRequest({ method: 'GET', url: _host + '/api/v1/q/'+ encodeQuestion +'?simple=true&token='+ setting.token +'&split=%23', headers: { 'Authorization': setting.token }, timeout: setting.delayTime, onload: function (xhr) { // alert("请求成功") var obj; var _answer = ''; // 成功响应 if (xhr.status == 200) { obj = $.parseJSON(xhr.responseText), _answer = obj.data; if (obj.code == 0 && _answer) { logger('题目:' + _q + "
---->答案:" + _answer, 'purple') resolve(_answer) } else { logger("题库未知错误 --> getAnswer()", 'red') setting.sub = 0 reject({ 'c': 0 }) } } else if (xhr.status == 400) { logger('未找到答案', 'red'); setting.sub = 0; reject({ 'c': 0 }) } else { logger("其他状态码异常", "red"); setting.sub = 0; reject({'c':0}) } }, ontimeout: function () { logger('题库请求超时,等待', 'red') reject({ 'c': 0 }) }, onerror: function(error){ logger("错误"+error,"red") reject({ 'c': 0 }) } }); }) } function refreshCourseList() { let _p = parseUrlParams() return new Promise((resolve) => { $.ajax({ url: _location.protocol + '//' + _location.host + '/mycourse/studentstudycourselist?courseId=' + _p['courseid'] + '&chapterId=' + _p['knowledgeid'] + '&clazzid=' + _p['clazzid'] + '&mooc2=1', type: 'GET', dateType: 'html', success: function (res) { resolve(res) } }) }) } function getEnc(a, b, c, d, e, f, g) { return new Promise((resolve, reject) => { try { let strEnc = `[${a}][${b}][${c}][${d}][${e * 1e3}][d_yHJ!$pdA~5][${f * 1e3}][${g}]`; resolve(md5(strEnc)); } catch (e) { logger('获取enc出错' + e, 'red') reject() } }); } function tidyQuestion(s) { if (s) { let str = s .replace(/<(?!img).*?>/g, "") .replace(/^【.*?】\s*/, '') .replace(/\s*(\d+\.\d+分)$/, '') .replace(/^\d+[.、]/, '') .trim().replace(/ /g, '') .replace('javascript:void(0);', '') .replace(new RegExp(" ", ("gm")), '') .replace(/^\s+/, '') .replace(/\s+$/, ''); return str } else { return null } } function tidyStr(s) { if (s) { let str = s.replace(/<(?!img).*?>/g, "").replace(/^【.*?】\s*/, '').replace(/\s*(\d+\.\d+分)$/, '').trim().replace(/ /g, '').replace(new RegExp(" ", ("gm")), '').replace(/^\s+/, '').replace(/\s+$/, ''); return str } else { return null } } function http2https(url) { let _url = url.replace(/^http:/, "https:"); return _url; } function getElement(parent, selector, timeout = 0) { /** * Author cxxjackie * From https://bbs.tampermonkey.net.cn */ return new Promise(resolve => { let result = parent.querySelector(selector); if (result) return resolve(result); let timer; const mutationObserver = window.MutationObserver || window.WebkitMutationObserver || window.MozMutationObserver; if (mutationObserver) { const observer = new mutationObserver(mutations => { for (let mutation of mutations) { for (let addedNode of mutation.addedNodes) { if (addedNode instanceof Element) { result = addedNode.matches(selector) ? addedNode : addedNode.querySelector(selector); if (result) { observer.disconnect(); timer && clearTimeout(timer); return resolve(result); } } } } }); observer.observe(parent, { childList: true, subtree: true }); if (timeout > 0) { timer = setTimeout(() => { observer.disconnect(); return resolve(null); }, timeout); } } else { const listener = e => { if (e.target instanceof Element) { result = e.target.matches(selector) ? e.target : e.target.querySelector(selector); if (result) { parent.removeEventListener('DOMNodeInserted', listener, true); timer && clearTimeout(timer); return resolve(result); } } }; parent.addEventListener('DOMNodeInserted', listener, true); if (timeout > 0) { timer = setTimeout(() => { parent.removeEventListener('DOMNodeInserted', listener, true); return resolve(null); }, timeout); } } }); } function getStr(str, start, end) { // 1. 构建正则表达式: // - `${start}(.*?)${end}` 表示匹配 start 后面跟着任意字符(非贪婪模式),直到遇到 end // - 使用 new RegExp 动态创建正则表达式,支持变量作为标记 let res = str.match(new RegExp(`${start}(.*?)${end}`)); // 2. 如果匹配成功,返回第一个捕获组(索引1)的内容;否则返回 null return res ? res[1] : null; } // 用于解析当前 URL 中的查询参数(即问号 ? 后面的部分),并将其转换为 JavaScript 对象 function parseUrlParams() { // 获取 URL 的查询部分(从 ? 开始的字符串),并去掉开头的 ? let query = window.location.search.substring(1); // 将查询字符串按 & 分割成参数对数组 let vars = query.split("&"); // 初始化结果对象 let javaScriptObject = {}; // 遍历参数对数组 for (let i = 0; i < vars.length; i++) { // 将每个参数对按 = 分割为键和值 let pair = vars[i].split("="); // 将键值对存入结果对象(注意:这里没有处理编码问题) javaScriptObject[pair[0]] = pair[1]; } // 返回解析后的对象 return javaScriptObject; } function getTaskParams() { try { // 1. 获取当前页面的所有脚本标签 var _iframeScripts = _d.scripts, _p = null; // 2. 遍历所有脚本标签 for (let i = 0; i < _iframeScripts.length; i++) { // 3. 筛选包含 "mArg = "";" 且不包含油猴脚本标记的脚本 if (_iframeScripts[i].innerHTML.indexOf('mArg = "";') != -1 && _iframeScripts[i].innerHTML.indexOf('==UserScript==') == -1) { // 4. 处理脚本内容:移除所有空白字符 const scriptContent = _iframeScripts[i].innerHTML.replace(/\s/g, ""); // 5. 使用 getStr 函数提取 mArg 的值 _p = getStr(scriptContent, 'try{mArg=', ';}catch'); // 6. 找到后立即返回结果 return _p; } } // 7. 未找到匹配的脚本,返回 null return _p; } catch (e) { console.log("发生错误",e) // 8. 发生异常时返回 null return null; } } function decryptFont() { var $tip = $('style:contains(font-cxsecret)'); if (!$tip.length) return; var font = $tip.text().match(/base64,([\w\W]+?)'/)[1]; font = Typr.parse(base64ToUint8Array(font))[0]; var table = JSON.parse(GM_getResourceText('Table')); var match = {}; for (var i = 19968; i < 40870; i++) { $tip = Typr.U.codeToGlyph(font, i); if (!$tip) continue; $tip = Typr.U.glyphToPath(font, $tip); $tip = md5(JSON.stringify($tip)).slice(24); match[i] = table[$tip]; } $('.font-cxsecret').html(function (index, html) { $.each(match, function (key, value) { key = String.fromCharCode(key); key = new RegExp(key, 'g'); value = String.fromCharCode(value); html = html.replace(key, value); }); return html; }).removeClass('font-cxsecret'); } function base64ToUint8Array(base64) { var data = window.atob(base64); var buffer = new Uint8Array(data.length); for (var i = 0; i < data.length; ++i) { buffer[i] = data.charCodeAt(i); } return buffer; } })();