melodyjerry
2021-11-30
脚本①(油猴Tampermonkey插件)
// ==UserScript==
// @name 熊猫超星网课助手
// @namespace xiongmao
// @version 9.0.1
// @description 自动挂机看尔雅MOOC,支持视频、音频、文档、图书自动完成,章节测验自动答题提交,支持自动切换任务点、挂机阅读时长、自动登录等,解除各类功能限制,开放自定义参数
// @author xiongmao
// @match *://*.chaoxing.com/*
// @match *://*.edu.cn/*
// @connect api.xmlm8.com
// @run-at document-end
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @grant GM_setClipboard
// @license MIT
// ==/UserScript==
// 设置修改后,需要刷新或重新打开网课页面才会生效
var setting = {
// 8E3 == 8000,科学记数法,表示毫秒数
time: 8E3 // 默认响应速度为8秒,不建议小于5秒
,token: \'\' // 捐助用户可以使用定制功能,更精准的匹配答案,此处填写捐助后获取的识别码
,review: 0 // 复习模式,完整挂机视频(音频)时长,支持挂机任务点已完成的视频和音频,默认关闭
,queue: 1 // 队列模式,开启后任务点逐一完成,关闭则单页面所有任务点同时进行,默认开启
// 1代表开启,0代表关闭
,video: 1 // 视频支持后台、切换窗口不暂停,支持多视频,默认开启
,work: 0 // 自动答题功能(章节测验),作业需要手动开启查询,高准确率,默认开启
,audio: 1 // 音频自动播放,与视频功能共享vol和rate参数,默认开启
,book: 1 // 图书阅读任务点,非课程阅读任务点,默认开启
,docs: 1 // 文档阅读任务点,PPT类任务点自动完成阅读任务,默认开启
// 本区域参数,上方为任务点功能,下方为独立功能
,jump: 1 // 自动切换任务点、章节、课程(需要配置course参数),默认开启
,read: \'0\' // 挂机课程阅读时间,单位是分钟,\'65\'代表挂机65分钟,请手动打开阅读页面,默认\'0\'分钟
,face: 0 // 解除面部识别(不支持二维码类面部采集),此功能仅为临时解除,默认关闭
,total: 0 // 显示课程进度的统计数据,在学习进度页面的上方展示,默认关闭
// 仅开启video(audio)时,修改此处才会生效
,line: \'公网1\' // 视频播放的默认资源线路,此功能适用于系统默认线路无资源,默认\'公网1\'
,http: \'标清\' // 视频播放的默认清晰度,无效参数则使用系统默认清晰度,默认\'标清\'
// 本区域参数,上方为video功能独享,下方为audio功能共享
,vol: \'0\' // 默认音量的百分数,设定范围:[0,100],\'0\'为静音,默认\'0\'
,rate: \'3\' // 视频播放默认倍率,参数范围0∪[0.0625,16],\'0\'为秒过,默认\'1\'倍
// 仅开启work时,修改此处才会生效
,auto: 0 // 答题完成后自动提交,默认关闭 改为1开启
,none: 0 // 无匹配答案时执行默认操作,关闭后若题目无匹配答案则会暂时保存已作答的题目,默认开启
,scale: 0 // 富文本编辑器高度自动拉伸,用于文本类题目,答题框根据内容自动调整大小,默认关闭
// 仅开启jump时,修改此处才会生效
,course: 0 // 当前课程完成后自动切换课程,仅支持按照根目录课程顺序切换,默认开启
,lock: 1 // 跳过未开放(图标是锁)的章节,即闯关模式或定时发放的任务点,默认开启
// 自动登录功能配置区
,school: \'账号为手机号可以不修改此参数\' // 学校/单位/机构码,要求完整有效可查询,例如\'清华大学\'
,username: \'\' // 学号/工号/借书证号(邮箱/手机号/账号),例如\'2018010101\',默认\'\'
,password: \'\' // 密码,例如\'123456\',默认\'\'
},
_self = unsafeWindow,
url = location.pathname,
top = _self;
if (url != \'/studyApp/studying\' && top != _self.top) document.domain = location.host.replace(/.+?\./, \'\');
try {
while (top != _self.top) {
top = top.parent.document ? top.parent : _self.top;
if (top.location.pathname == \'/mycourse/studentstudy\') break;
}
} catch (err) {
// console.log(err);
top = _self;
}
var $ = _self.jQuery || top.jQuery,
parent = _self == top ? self : _self.parent,
Ext = _self.Ext || parent.Ext || {},
UE = _self.UE,
vjs = _self.videojs;
String.prototype.toCDB = function() {
return this.replace(/\s/g, \'\').replace(/[\uff01-\uff5e]/g, function(str) {
return String.fromCharCode(str.charCodeAt(0) - 65248);
}).replace(/[“”]/g, \'"\').replace(/[‘’]/g, "\'").replace(/。/g, \'.\');
};
setting.normal = \'\'; // \':visible\'
// setting.time += Math.ceil(setting.time * Math.random()) - setting.time / 2;
setting.job = [\':not(*)\'];
setting.video && setting.job.push(\'iframe[src*="/video/index.html"]\');
setting.work && setting.job.push(\'iframe[src*="/work/index.html"]\');
setting.audio && setting.job.push(\'iframe[src*="/audio/index.html"]\');
setting.book && setting.job.push(\'iframe[src*="/innerbook/index.html"]\');
setting.docs && setting.job.push(\'iframe[src*="/ppt/index.html"]\', \'iframe[src*="/pdf/index.html"]\');
setting.tip = !setting.queue || top != _self && jobSort($ || Ext.query);
if (url == \'/mycourse/studentstudy\') {
_self.checkMobileBrowerLearn = $.noop;
var classId = location.search.match(/cla[zs]{2}id=(\d+)/i)[1] || 0,
courseId = _self.courseId || location.search.match(/courseId=(\d+)/i)[1] || 0;
setting.lock || $(\'#coursetree\').on(\'click\', \'[onclick*=void], [href*=void]\', function() {
_self.getTeacherAjax(courseId, classId, $(this).parent().attr(\'id\').slice(3));
});
} else if (url == \'/ananas/modules/video/index.html\' && setting.video) {
if (setting.review) _self.greenligth = Ext.emptyFn;
checkPlayer(_self.supportH5Video());
} else if (url == \'/work/doHomeWorkNew\' || url == \'/api/work\' || url == \'/work/addStudentWorkNewWeb\') {
if (!UE) {
var len = ($ || Ext.query || Array)(\'font:contains(未登录)\', document).length;
setTimeout(len == 1 ? top.location.reload : parent.greenligth, setting.time);
} else if (setting.work) {
setTimeout(relieveLimit, 0);
beforeFind();
}
} else if (url == \'/ananas/modules/audio/index.html\' && setting.audio) {
if (setting.review) _self.greenligth = Ext.emptyFn;
_self.videojs = hookAudio;
hookAudio.xhr = vjs.xhr;
} else if (url == \'/ananas/modules/innerbook/index.html\' && setting.book && setting.tip) {
setTimeout(function() {
_self.setting ? _self.top.onchangepage(_self.getFrameAttr(\'end\')) : _self.greenligth();
}, setting.time);
} else if (url.match(/^\/ananas\/modules\/(ppt|pdf)\/index\.html$/) && setting.docs && setting.tip) {
setTimeout(function() {
_self.setting ? _self.finishJob() : _self.greenligth();
}, setting.time);
frameElement.setAttribute(\'download\', 1);
} else if (url == \'/knowledge/cards\') {
$ && checkToNext();
} else if (url.match(/^\/(course|zt)\/\d+\.html$/)) {
setTimeout(function() {
+setting.read && _self.sendLogs && $(\'.course_section:eq(0) .chapterText\').click();
}, setting.time);
} else if (url == \'/ztnodedetailcontroller/visitnodedetail\') {
setting.read *= 60 / $(\'.course_section\').length;
setting.read && _self.sendLogs && autoRead();
} else if (url == \'/mycourse/studentcourse\') {
var gv = location.search.match(/d=\d+&/g);
setting.total && $(\'\', {
href: \'/moocAnalysis/chapterStatisticByUser?classI\' + gv[1] + \'courseI\' + gv[0] + \'userId=\' + _self.getCookie(\'_uid\') + \'&ut=s\',
target: \'_blank\',
title: \'点击查看章节统计\',
style: \'margin: 0 25px;\',
html: \'本课程共\' + $(\'.icon\').length + \'节,剩余\' + $(\'em:not(.openlock)\').length + \'节未完成\'
}).appendTo(\'.zt_logo\').parent().width(\'auto\');
} else if (url.match(/^\/visit\/(courses|interaction)$/)) {
setting.face && $(\'.zmodel\').on(\'click\', \'[onclick^=openFaceTip]\', DisplayURL);
} else if (location.host.match(/^passport2/)) {
setting.username && getSchoolId();
} else if (location.hostname == \'i.mooc.chaoxing.com\') {
_self.layui.use(\'layer\', function() {
this.layer.open({content: \'拖动进度条、倍速播放、秒过会导致不良记录!题库在慢慢补充,搜不到的题目系统会在次日进行自动补充\', title: \'超星网课助手提示\', btn: \'我已知悉\', offset: \'t\', closeBtn: 0});
});
} else if (url == \'/widget/pcvote/goStudentVotePage\') {
$(\':checked\').click();
$(\'.StudentTimu\').each(function(index) {
var ans = _self.questionlist[index].answer;
$(\':radio, :checkbox\', this).each(function(num) {
ans[num].isanswer && this.click();
});
$(\':text\', this).val(function(num) {
return $(ans[num].content).text().trim();
});
});
} else if (url == \'/work/selectWorkQuestionYiPiYue\') {
submitAnswer(getIframe().parent(), $.extend(true, [], parent._data));
}
function getIframe(tip, win, job) {
if (!$) return Ext.get(frameElement || []).parent().child(\'.ans-job-icon\') || Ext.get([]);
do {
win = win ? win.parent : _self;
job = $(win.frameElement).prevAll(\'.ans-job-icon\');
} while (!job.length && win.parent.frameElement);
return tip ? win : job;
}
function jobSort($) {
var fn = $.fn ? [getIframe(1), \'length\'] : [self, \'dom\'],
sel = setting.job.join(\', :not(.ans-job-finished) > .ans-job-icon\' + setting.normal + \' ~ \');
if ($(sel, fn[0].parent.document)[0] == fn[0].frameElement) return true;
if (!getIframe()[fn[1]] || getIframe().parent().is(\'.ans-job-finished\')) return null;
setInterval(function() {
$(sel, fn[0].parent.document)[0] == fn[0].frameElement && fn[0].location.reload();
}, setting.time);
}
function checkPlayer(tip) {
_self.videojs = hookVideo;
hookVideo.xhr = vjs.xhr;
Ext.isSogou = Ext.isIos = Ext.isAndroid = false;
var data = Ext.decode(_self.config(\'data\')) || {};
delete data.danmaku;
data.doublespeed = 1;
frameElement.setAttribute(\'data\', Ext.encode(data));
if (tip) return;
_self.supportH5Video = function() {return true;};
alert(\'此浏览器不支持html5播放器,请更换浏览器\');
}
function hookVideo() {
_self.alert = console.log;
var config = arguments[1],
line = Ext.Array.filter(Ext.Array.map(config.playlines, function(value, index) {
return value.label == setting.line && index;
}), function(value) {
return Ext.isNumber(value);
})[0] || 0,
http = Ext.Array.filter(config.sources, function(value) {
return value.label == setting.http;
})[0];
config.playlines.unshift(config.playlines[line]);
config.playlines.splice(line + 1, 1);
config.plugins.videoJsResolutionSwitcher.default = http ? http.res : 360;
config.plugins.studyControl.enableSwitchWindow = 1;
config.plugins.timelineObjects.url = \'/richvideo/initdatawithviewer?\';
config.plugins.seekBarControl.enableFastForward = 1;
if (!setting.queue) delete config.plugins.studyControl;
// config.preload = setting.tip ? \'auto\' : \'none\';
var player = vjs.apply(this, arguments),
a = \'\',
img = \' \';
player.volume(Math.round(setting.vol) / 100 || 0);
Ext.get(player.controlBar.addChild(\'Button\').el_).setHTML(a + img + \'\').dom.title = \'下载视频\';
player.on(\'loadstart\', function() {
setting.tip && this.play().catch(Ext.emptyFn);
this.playbackRate(setting.rate > 16 || setting.rate < 0.0625 ? 1 : setting.rate);
});
player.one([\'loadedmetadata\', \'firstplay\'], function() {
setting.two = setting.rate === \'0\' && setting.two < 1;
setting.two && config.plugins.seekBarControl.sendLog(this.children_[0], \'ended\', Math.floor(this.cache_.duration));
});
player.on(\'ended\', function() {
Ext.fly(frameElement).parent().addCls(\'ans-job-finished\');
});
return player;
}
function hookAudio() {
_self.alert = console.log;
var config = arguments[1];
config.plugins.studyControl.enableSwitchWindow = 1;
config.plugins.seekBarControl.enableFastForward = 1;
if (!setting.queue) delete config.plugins.studyControl;
var player = vjs.apply(this, arguments),
a = \'\',
img = \' \';
player.volume(Math.round(setting.vol) / 100 || 0);
player.playbackRate(setting.rate > 16 || setting.rate < 0.0625 ? 1 : setting.rate);
Ext.get(player.controlBar.addChild(\'Button\').el_).setHTML(a + img + \'\').dom.title = \'下载音频\';
player.on(\'loadeddata\', function() {
setting.tip && this.play().catch(Ext.emptyFn);
});
player.one(\'firstplay\', function() {
setting.rate === \'0\' && config.plugins.seekBarControl.sendLog(this.children_[0], \'ended\', Math.floor(this.cache_.duration));
});
player.on(\'ended\', function() {
Ext.fly(frameElement).parent().addCls(\'ans-job-finished\');
});
return player;
}
function relieveLimit() {
if (setting.scale) _self.UEDITOR_CONFIG.scaleEnabled = false;
$.each(UE.instants, function() {
var key = this.key;
this.ready(function() {
this.destroy();
UE.getEditor(key);
});
});
}
function beforeFind() {
setting.regl = parent.greenligth || $.noop;
if ($.type(parent._data) == \'array\') return setting.regl();
setting.div = $(
\'\' +
\'\' +
\'正在搜索答案...\' +
\'暂停答题\' +
\'\' + (setting.auto ? \'取消本次自动提交\' : \'开启本次自动提交\') + \'\' +
\'重新查询\' +
\'折叠面板\' +
\'\' +
\'\' +
\'\' +
\'\' +
\'题号\' +
\'题目(点击可复制)\' +
\'答案(点击可复制)\' +
\'\' +
\'\' +
\'\' +
\'\' +
\'答案提示框 已折叠\' +
\'\' +
\'\' +
\'\' +
\'\' +
\'\' +
\'\' +
\'\' +
\'\' +
\'\' +
\'\'
).appendTo(\'body\').on(\'click\', \'button, td\', function() {
var len = $(this).prevAll(\'button\').length;
if (this.nodeName == \'TD\') {
$(this).prev().length && GM_setClipboard($(this).text());
} else if (!$(this).siblings().length) {
$(this).parent().text(\'正在搜索答案...\');
setting.num++;
} else if (len === 0) {
if (setting.loop) {
clearInterval(setting.loop);
delete setting.loop;
len = [\'已暂停搜索\', \'继续答题\'];
} else {
setting.loop = setInterval(findAnswer, setting.time);
len = [\'正在搜索答案...\', \'暂停答题\'];
}
setting.div.children(\'div:eq(0)\').html(function() {
return $(this).data(\'html\') || len[0];
}).removeData(\'html\');
$(this).html(len[1]);
} else if (len == 1) {
setting.auto = !setting.auto;
$(this).html(setting.auto ? \'取消本次自动提交\' : \'开启本次自动提交\');
} else if (len == 2) {
parent.location.reload();
} else if (len == 3) {
setting.div.find(\'tbody, tfoot\').toggle();
}
}).find(\'table, td, th\').css(\'border\', \'1px solid\').end();
setting.lose = setting.num = 0;
setting.data = parent._data = [];
setting.over = \'跳过此题\';
setting.curs = $(\'script:contains(courseName)\', top.document).text().match(/courseName:\\'(.+?)\\'|$/)[1] || $(\'h1\').text().trim() || \'无\';
setting.loop = setInterval(findAnswer, setting.time);
var tip = ({undefined: \'任务点排队中\', null: \'等待切换中\'})[setting.tip];
tip && setting.div.children(\'div:eq(0)\').data(\'html\', tip).siblings(\'button:eq(0)\').click();
}
function findAnswer() {
if (setting.num >= $(\'.TiMu\').length) {
var arr = setting.lose ? [\'共有 \' + setting.lose + \' 道题目待完善(已深色标注)\', saveThis] : [\'答题已完成\', submitThis];
setting.div.children(\'div:eq(0)\').data(\'html\', arr[0]).siblings(\'button:eq(0)\').hide().click();
return setTimeout(arr[1], setting.time);
}
var $TiMu = $(\'.TiMu\').eq(setting.num),
question = filterImg($TiMu.find(\'.Zy_TItle:eq(0) .clearfix\')).replace(/^【.*?】\s*/, \'\').replace(/\s*(\d+\.\d+分)$/, \'\').replace(/[(]\s*[)]。$/,\'\').replace(/(\s*)。$/,\'\').replace(/[(]\s*[)]$/,\'\').replace(/(\s*)$/,\'\'),
type = $TiMu.find(\'input[name^=answertype]:eq(0)\').val() || \'-1\';
//setting.div.children(\'div:eq(0)\').text(encodeURIComponent(question)+\'正在搜索答案...\');
GM_xmlhttpRequest({
method: \'GET\',
url: \'http://api.xmlm8.com/tp/tk.php?t=\'+ encodeURIComponent(question),
headers: {
\'Content-type\': \'application/x-www-form-urlencoded\'
},
timeout: setting.time,
onload: function(xhr) {
if (!setting.loop) {
} else if (xhr.status == 200) {
var obj = $.parseJSON(xhr.responseText) || {};
if (obj.code == 1) {
setting.div.children(\'div:eq(0)\').text(\'正在搜索答案...\');
var td = \'\' + $TiMu.find(\'.Zy_TItle:eq(0) i\').text().trim() + \'\' +
td + \'" title="点击可复制">\' + (question.match(\'\' + (question.match(\' |