// ==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;
}
})();