✨超星学习通网课助手|视频挂机考试答题|聚合题库字体还原|完全免费永久使用【网课通用版】

【🥇操作简单】超星尔雅MOOC自动挂机,无需配置安装即可使用。【🔊功能齐全】支持视频、音频、文档、图书自动完成;章节测验自动答题、自动提交,支持自动切换任务点、挂机阅读时长、自动登录等。【📔独家题库】独家丰富试题库,精准识别,答案全对。【✨功能扩展】解除各类功能限制,解除字体加密,支持下载视频、pdf文档,开放自定义参数

As of 21/03/2023. See the latest version.

  1. // ==UserScript==
  2. // @name ✨超星学习通网课助手|视频挂机考试答题|聚合题库字体还原|完全免费永久使用【网课通用版】
  3. // @namespace Muketool
  4. // @version 2.0.2
  5. // @description 【🥇操作简单】超星尔雅MOOC自动挂机,无需配置安装即可使用。【🔊功能齐全】支持视频、音频、文档、图书自动完成;章节测验自动答题、自动提交,支持自动切换任务点、挂机阅读时长、自动登录等。【📔独家题库】独家丰富试题库,精准识别,答案全对。【✨功能扩展】解除各类功能限制,解除字体加密,支持下载视频、pdf文档,开放自定义参数
  6. // @author Muketool
  7. // @match *://*.chaoxing.com/*
  8. // @connect api.muketool.com
  9. // @connect api2.muketool.com
  10. // @run-at document-end
  11. // @grant unsafeWindow
  12. // @grant GM_addStyle
  13. // @grant GM_getResourceText
  14. // @grant GM_xmlhttpRequest
  15. // @grant GM_setClipboard
  16. // @grant GM_getResourceURL
  17. // @require https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.6.0/jquery.min.js
  18. // @require https://cdn.jsdelivr.net/gh/photopea/Typr.js@15aa12ffa6cf39e8788562ea4af65b42317375fb/src/Typr.min.js
  19. // @require https://cdn.jsdelivr.net/gh/photopea/Typr.js@f4fcdeb8014edc75ab7296bd85ac9cde8cb30489/src/Typr.U.min.js
  20. // @resource CxSecretsFont https://static2.muketool.com/scripts/cx/fonts/cxsecret.json
  21. // @resource Layui https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.8/css/layui.css
  22. // @resource LayuiIconFont-woff2 https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.8/font/iconfont.woff2
  23. // @resource LayuiIconFont-woff https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.8/font/iconfont.woff
  24. // @resource LayuiIconFont-ttf https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/layui/2.6.8/font/iconfont.ttf
  25. // @license MIT
  26. // @original-script https://greasyfork.org/scripts/369625
  27. // @original-author wyn665817
  28. // @original-license MIT
  29. // @icon https://static2.muketool.com/web/icon.png
  30. // ==/UserScript==
  31. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  32. // 设置修改后,需要刷新或重新打开网课页面才会生效(0关闭,1开启),修改的时候不要删掉末尾的,号,否则会报错
  33. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  34. var setting = {
  35. // 选择要使用的题库。默认为http://api.muketool.com,速度更快,可以自行修改为http://api2.muketool.com,速度略慢些但更稳定
  36. tiku: 'http://api.muketool.com',
  37. // 默认响应速度为8秒,不建议小于3秒,否则高峰期可能出现答题失败的情况。5E3 == 5000,科学记数法,表示毫秒数
  38. time: 8E3,
  39. // 复习模式,完整挂机视频(音频)时长,支持挂机任务点已完成的视频和音频
  40. review: 0,
  41. // 队列模式,开启后任务点逐一完成,关闭则单页面所有任务点同时进行
  42. queue: 1,
  43. // 视频支持后台、切换窗口不暂停,支持多视频
  44. video: 1,
  45. // 自动答题功能(章节测验),作业需要手动开启查询,高准确率
  46. work: 1,
  47. // 音频自动播放,与视频功能共享vol和rate参数
  48. audio: 1,
  49. // 图书阅读任务点,非课程阅读任务点
  50. book: 1,
  51. // 文档阅读任务点,PPT类任务点自动完成阅读任务
  52. docs: 1,
  53. // 自动切换标签、章节、课程(需要配置course参数)
  54. jump: 1,
  55. // 挂机课程阅读时间,单位分钟
  56. read: '10',
  57. // 显示课程进度的统计数据,在学习进度页面的上方展示
  58. total: 1,
  59. ////////////////////////////////////////////////////////////////////
  60. // 仅开启video(audio)时,修改此处才会生效
  61. ////////////////////////////////////////////////////////////////////
  62. // 视频播放的默认资源线路
  63. line: '公网1',
  64. // 视频播放的默认清晰度
  65. http: '标清',
  66. // 默认音量的百分数,设定范围:[0,100],'0'为静音
  67. vol: '0',
  68. // 倍速已经失效,建议一倍速看,多倍速会异常提示
  69. rate: '0',
  70. // 答题完成后自动保存,默认开启, 仅开启work时,修改此处才会生效
  71. auto_save: 1,
  72. // 答题完成后自动提交,默认关闭, 仅开启work时,修改此处才会生效
  73. auto_submit: 0,
  74. // 无匹配答案时执行默认操作,关闭后若题目无匹配答案则会暂时保存已作答的题目
  75. none: 0,
  76. // 富文本编辑器高度自动拉伸,用于文本类题目,答题框根据内容自动调整大小
  77. scale: 1,
  78. // 当前课程完成后自动切换课程,仅支持按照根目录课程顺序切换,默认关闭
  79. course: 1,
  80. // 跳过未开放(图标是锁)的章节,即闯关模式或定时发放的任务点,默认开启
  81. lock: 1,
  82. // 搜索历史记录
  83. search_history: 1,
  84. script: 'cx',
  85. script_version: '2.0.1',
  86. },
  87. _self = unsafeWindow,
  88. url = location.pathname,
  89. top = _self;
  90. if (url != '/studyApp/studying' && top != _self.top) document.domain = location.host.replace(/.+?\./, '');
  91. try {
  92. while (top != _self.top) {
  93. top = top.parent.document ? top.parent : _self.top;
  94. if (top.location.pathname == '/mycourse/studentstudy') break;
  95. }
  96. } catch (err) {
  97. top = _self;
  98. }
  99. GM_addStyle(`
  100. @import url(${GM_getResourceURL('Layui')});
  101. `);
  102. GM_addStyle(`
  103. @font-face {
  104. font-family: 'layui-icon';
  105. src: url(${GM_getResourceURL('LayuiIconFont-woff2')}) format('woff2'),
  106. url(${GM_getResourceURL('LayuiIconFont-woff')}.woff) format('woff'),
  107. url(${GM_getResourceURL('LayuiIconFont-ttf')}) format('truetype');
  108. font-weight: normal;
  109. font-style: normal;
  110. }
  111. ${GM_getResourceText('Layui')}
  112. `);
  113. var $ = _self.jQuery || top.jQuery,
  114. parent = _self == top ? self : _self.parent,
  115. Ext = _self.Ext || parent.Ext || {},
  116. UE = _self.UE,
  117. vjs = _self.videojs;
  118. $('.Header').find('a:contains(回到旧版)')[0] ? $('.Header').find('a:contains(回到旧版)')[0].click() : '';
  119. if (location.href.indexOf('mooc2=1') != -1) {
  120. location.href = location.href.replace('mooc2=1', 'mooc2=0');
  121. }
  122. String.prototype.toCDB = function () {
  123. return this.replace(/\s/g, '').replace(/[\uff01-\uff5e]/g, function (str) {
  124. return String.fromCharCode(str.charCodeAt(0) - 65248);
  125. }).replace(/[“”]/g, '"').replace(/[‘’]/g, "'").replace(/。/g, '.');
  126. };
  127. _self.alert = console.log;
  128. setting.normal = '';
  129. setting.job = [':not(*)'];
  130. setting.video && setting.job.push('iframe[src*="/video/index.html"]');
  131. setting.work && setting.job.push('iframe[src*="/work/index.html"]');
  132. setting.audio && setting.job.push('iframe[src*="/audio/index.html"]');
  133. setting.book && setting.job.push('iframe[src*="/innerbook/index.html"]');
  134. setting.docs && setting.job.push('iframe[src*="/ppt/index.html"]', 'iframe[src*="/pdf/index.html"]');
  135. if (url == '/mycourse/studentstudy') {
  136. showMtDashboard();
  137. switchToNormal();
  138. _self.checkMobileBrowerLearn = $.noop;
  139. var classId = location.search.match(/cla[zs]{2}id=(\d+)/i)[1] || 0,
  140. courseId = _self.courseId || location.search.match(/courseId=(\d+)/i)[1] || 0;
  141. !setting.jump || setting.lock || $('#coursetree').on('click', '[onclick*=void], [href*=void]', function () {
  142. _self.getTeacherAjax(courseId, classId, $(this).parent().attr('id').slice(3));
  143. });
  144. } else if (url == '/ananas/modules/video/index.html' && setting.video) {
  145. switchToNormal();
  146. if (setting.review) _self.greenligth = Ext.emptyFn;
  147. passVideo()
  148. } else if (url == '/work/doHomeWorkNew' || url == '/api/work' || url == '/work/addStudentWorkNewWeb') {
  149. top.courseId = location.search.match(/courseId=(\d+)/i)[1];
  150. if (!UE) {
  151. var len = ($ || Ext.query || Array)('font:contains(未登录)', document).length;
  152. setTimeout(len == 1 ? top.location.reload : parent.greenligth, setting.time);
  153. } else if (setting.work) {
  154. setTimeout(relieveLimit, 0);
  155. beforeFind();
  156. }
  157. } else if (url == '/ananas/modules/innerbook/index.html' && setting.book) {
  158. setTimeout(function () {
  159. if (getTip()) _self.setting ? _self.top.onchangepage(_self.getFrameAttr('end')) : _self.greenligth();
  160. }, setting.time);
  161. } else if (url.match(/^\/ananas\/modules\/(ppt|pdf)\/index\.html$/) && setting.docs) {
  162. setTimeout(function () {
  163. if (getTip()) _self.setting ? _self.finishJob() : _self.greenligth();
  164. }, setting.time);
  165. frameElement.setAttribute('download', 1);
  166. if (_self.downloadNum == '') _self.downloadNum = '1';
  167. } else if (url == '/knowledge/cards') {
  168. $ && checkToNext();
  169. } else if (url.match(/^\/(course|zt)\/\d+\.html$/)) {
  170. setTimeout(function () {
  171. +setting.read && _self.sendLogs && $('.course_section:eq(0) .chapterText').click();
  172. }, setting.time);
  173. } else if (url == '/ztnodedetailcontroller/visitnodedetail') {
  174. setting.read *= 60 / $('.course_section').length;
  175. setting.read && _self.sendLogs && autoRead();
  176. } else if (url == '/mycourse/studentcourse') {
  177. var gv = location.search.match(/d=\d+&/g);
  178. setting.total && $('<a>', {
  179. href: '/moocAnalysis/chapterStatisticByUser?classI' + gv[1] + 'courseI' + gv[0] + 'userId=' + _self.getCookie('_uid') + '&ut=s',
  180. target: '_blank',
  181. title: '点击查看章节统计',
  182. style: 'margin: 0 25px;',
  183. html: '本课程共' + $('.icon').length + '节,剩余' + $('em:not(.openlock)').length + '节未完成'
  184. }).appendTo('.zt_logo').parent().width('auto');
  185. } else if (location.hostname == 'i.mooc.chaoxing.com') {} else if (url == '/work/selectWorkQuestionYiPiYue') {
  186. submitAnswer(getIframe().parent(), $.extend(true, [], parent._data));
  187. } else if (url == '/exam-ans/exam/test') {};
  188.  
  189. function decryptText() {
  190. var $tip = $('style:contains(font-cxsecret)');
  191. if (!$tip.length) return;
  192. var font = $tip.text().match(/base64,([\w\W]+?)'/)[1];
  193. font = Typr.parse(base64ToUint8Array(font))[0];
  194. var CxSecretsFont = JSON.parse(GM_getResourceText('CxSecretsFont'));
  195. var match = {};
  196. for (var i = 19968; i < 40870; i++) {
  197. $tip = Typr.U.codeToGlyph(font, i);
  198. if (!$tip) continue;
  199. $tip = Typr.U.glyphToPath(font, $tip);
  200. $tip = $.md5(JSON.stringify($tip)).slice(24);
  201. match[i] = CxSecretsFont[$tip];
  202. }
  203. $('.font-cxsecret').html(function (index, html) {
  204. $.each(match, function (key, value) {
  205. key = String.fromCharCode(key);
  206. key = new RegExp(key, 'g');
  207. value = String.fromCharCode(value);
  208. html = html.replace(key, value);
  209. });
  210. return html;
  211. }).removeClass('font-cxsecret');
  212.  
  213. function base64ToUint8Array(base64) {
  214. var data = window.atob(base64);
  215. var buffer = new Uint8Array(data.length);
  216. for (var i = 0; i < data.length; ++i) {
  217. buffer[i] = data.charCodeAt(i);
  218. }
  219. return buffer;
  220. }
  221. }
  222.  
  223. function time_to_sec(time) {
  224. let s = 0;
  225. let t = 1;
  226. for (let i = time.split(':').length - 1; i >= 0; i--) {
  227. s += Number(time.split(':')[i]) * t
  228. t *= 60
  229. }
  230. return s;
  231. };
  232.  
  233. function getTip() {
  234. return top != _self && jobSort($ || Ext.query);
  235. }
  236.  
  237. function passVideo() {
  238. skipQuestion();
  239. getTip() && setTimeout(() => {
  240. let vd = $('video')[0];
  241. if (vd) {
  242. vd.volume = vd.volume === 0 ? 1 : 0;
  243. $('.vjs-big-play-button')[0].click();
  244. }
  245. }, 2000)
  246. }
  247.  
  248. function jobSort($) {
  249. var fn = $.fn ? [getIframe(1), 'length'] : [self, 'dom'],
  250. sel = setting.job.join(', :not(.ans-job-finished) > .ans-job-icon' + setting.normal + ' ~ ');
  251. if (!getIframe()[fn[1]] || getIframe().parent().is('.ans-job-finished')) return 0;
  252. if (!setting.queue || $(sel, fn[0].parent.document)[0] == fn[0].frameElement) return 1;
  253. setInterval(function () {
  254. $(sel, fn[0].parent.document)[0] == fn[0].frameElement && fn[0].location.reload();
  255. }, setting.time);
  256. }
  257.  
  258. function getIframe(tip, win, job) {
  259. if (!$) return Ext.get(frameElement || []).parent().child('.ans-job-icon') || Ext.get([]);
  260. do {
  261. win = win ? win.parent : _self;
  262. job = $(win.frameElement).prevAll('.ans-job-icon');
  263. } while (!job.length && win.parent.frameElement);
  264. return tip ? win : job;
  265. }
  266.  
  267. function relieveLimit() {
  268. if (setting.scale) _self.UEDITOR_CONFIG.scaleEnabled = false;
  269. $.each(UE.instants, function () {
  270. var key = this.key;
  271. this.ready(function () {
  272. this.destroy();
  273. UE.getEditor(key);
  274. });
  275. });
  276. }
  277.  
  278. function beforeFind() {
  279. decryptText();
  280. setting.regl = parent.greenligth || $.noop;
  281. if ($.type(parent._data) == 'array') return setting.regl();
  282. switchToAnswering();
  283. let $mt_dashboard = _self.top.$('#mt-dashboard');
  284. setInterval(function () {
  285. if (setting.work == 1) {
  286. findAnswer();
  287. }
  288. }, setting.time);
  289. $mt_dashboard.on('click', 'td', function () {
  290. $(this).prev().length && GM_setClipboard($(this).text());
  291. });
  292. $mt_dashboard.on('click', 'button', function () {
  293. button_clicked = $(this).attr('id');
  294. if (button_clicked == 'mt-setting-button-1') {
  295. if (setting.work) {
  296. $('#mt-dashboard-status', $mt_dashboard).html('<i class="layui-icon layui-icon-pause"></i>&nbsp;<span class="layui-font-13" style="font-weight: bold;">自动搜题已临时关闭,您可在下方重新开启</span>');
  297. $('#mt-setting-button-1', $mt_dashboard).html('<i class="layui-icon layui-icon-close"></i>自动答题已关闭');
  298. } else {
  299. $('#mt-dashboard-status', $mt_dashboard).html('<i class="layui-icon layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop"></i>&nbsp;<span class="layui-font-13" style="font-weight: bold;">正在拼命搜索试题答案中......</span>');
  300. $('#mt-setting-button-1', $mt_dashboard).html('<i class="layui-icon layui-icon-ok"></i>自动答题已开启');
  301. }
  302. setting.work = !setting.work;
  303. } else if (button_clicked == 'mt-setting-button-2') {
  304. setting.auto_submit = !setting.auto_submit;
  305. setting.auto_submit ? $('#mt-setting-button-2', $mt_dashboard).html('<i class="layui-icon layui-icon-ok"></i>自动提交已开启') : $('#mt-setting-button-2', $mt_dashboard).html('<i class="layui-icon layui-icon-close"></i>自动提交已关闭');
  306. } else if (button_clicked == 'mt-setting-button-3') {
  307. location.reload();
  308. } else if (button_clicked == 'mt-setting-button-4') {
  309. setting.search_history = !setting.search_history;
  310. setting.search_history ? $('#mt-setting-button-4', $mt_dashboard).html('<i class="layui-icon layui-icon-down"></i>搜题记录已显示') : $('#mt-setting-button-4', $mt_dashboard).html('<i class="layui-icon layui-icon-right"></i>搜题记录已隐藏');
  311. setting.search_history ? $('#mt-dashboard-history', $mt_dashboard).show() : $('#mt-dashboard-history', $mt_dashboard).hide();
  312. setting.search_history ? $('#mt-table-tips', $mt_dashboard).html('温馨提示:点击下方表格中的文字可直接复制~~') : $('#mt-table-tips', $mt_dashboard).html('搜题历史记录已隐藏,您可在上方重新开启');
  313. }
  314. });
  315. setting.lose = setting.num = 0;
  316. setting.data = parent._data = [];
  317. setting.over = '<button style="margin-right: 10px;">跳过此题</button>';
  318. setting.curs = $('script:contains(courseName)', top.document).text().match(/courseName:'(.+?)'|$/)[1] || $('h1').text().trim() || '无';
  319. var tip = ({
  320. undefined: '任务点排队中',
  321. 0: '等待切换中'
  322. })[getTip()];
  323. tip && $('#mt-dashboard-status', $mt_dashboard).data('html', tip).siblings('button:eq(0)').click();
  324. if (tip) {
  325. $('#mt-dashboard-status', $mt_dashboard).html(tip);
  326. $mt_dashboard.siblings('button:eq(0)').click();
  327. }
  328. }
  329.  
  330. function findAnswer() {
  331. let $mt_dashboard = _self.top.$('#mt-dashboard');
  332. if (setting.num >= $('.TiMu').length) {
  333. if (setting.lose) {
  334. $('#mt-mt-dashboard-status', $mt_dashboard).html(`<i class="layui-icon layui-icon-about"></i>&nbsp;<span class="layui-font-13" style="font-weight: bold; color:red; ">有【${setting.lose}】道题目的答案不完全匹配,已在搜题记录区域高亮显示</span>`)
  335. }
  336. if (!setting.lose && setting.auto_submit) {
  337. return setTimeout(submitThis, setting.time);
  338. }
  339. if (setting.auto_save) {
  340. return setTimeout(saveThis, setting.time);
  341. }
  342. }
  343. var $TiMu = $('.TiMu').eq(setting.num);
  344. var question = filterImg($TiMu.find('.Zy_TItle:eq(0) .clearfix')).replace(/^【.*?】\s*/, '').replace(/\s*(\d+\.\d+分)$/, ''),
  345. type = $TiMu.find('input[name^=answertype]:eq(0)').val() || '-1';
  346. GM_xmlhttpRequest({
  347. method: 'POST',
  348. url: setting.tiku + '/cx/v2/query',
  349. headers: {
  350. 'Content-type': 'application/json'
  351. },
  352. data: JSON.stringify({
  353. question: question,
  354. type: type,
  355. }),
  356. timeout: setting.time,
  357. onload: function (xhr) {
  358. if (!setting.work) {} else if (xhr.status == 200) {
  359. var obj = $.parseJSON(xhr.responseText) || {};
  360. obj.answer = obj.data;
  361. if (obj.code != -1) {
  362. var answer = obj.answer.replace(/&/g, '&amp;').replace(/<(?!img)/g, '&lt;');
  363. obj.answer = /^http/.test(answer) ? '<img src="' + obj.answer + '">' : obj.answer;
  364. $(
  365. '<tr>' +
  366. '<td class="layui-font-12">' + $TiMu.find('.Zy_TItle:eq(0) i').text().trim() + '</td>' +
  367. '<td class="layui-font-12">' + (question.match('<img') ? question : question.replace(/&/g, '&amp;').replace(/</g, '&lt')) + '</td>' +
  368. '<td class="layui-font-12">' + (/^http/.test(answer) ? obj.answer : '') + obj.answer + '</td>' +
  369. '</tr>'
  370. ).appendTo($mt_dashboard.find('tbody')).css('background-color', fillAnswer($TiMu.find('ul:eq(0)').find('li'), obj, type) ? '' : '#FFC107');
  371. setting.num++;
  372. } else {
  373. $(
  374. '<tr>' +
  375. '<td class="layui-font-12">' + $TiMu.find('.Zy_TItle:eq(0) i').text().trim() + '</td>' +
  376. '<td class="layui-font-12">' + (question.match('<img') ? question : question.replace(/&/g, '&amp;').replace(/</g, '&lt')) + '</td>' +
  377. '<td class="layui-font-12">' + obj.msg + '</td>' +
  378. '</tr>'
  379. ).appendTo($mt_dashboard.find('tbody')).css('background-color', '#FFC107');
  380. setting.num++;
  381. }
  382. } else {
  383. $('#mt-dashboard-status', $mt_dashboard).html('<i class="layui-icon layui-icon-close-fill"></i>&nbsp;<span class="layui-font-13" style="font-weight: bold;">Muketool服务器连接异常,可能是正常维护或被攻击,请稍后重试......</span>')
  384. }
  385. },
  386. ontimeout: function () {
  387. $('#mt-dashboard-status', $mt_dashboard).html('<i class="layui-icon layui-icon-close-fill"></i>&nbsp;<span class="layui-font-13" style="font-weight: bold;">Muketool服务器连接异常,可能是正常维护或被攻击,请稍后重试......</span>')
  388. }
  389. });
  390. }
  391.  
  392. function fillAnswer($li, obj, type) {
  393. var $input = $li.find(':radio, :checkbox'),
  394. str = String(obj.data).toCDB() || new Date().toString(),
  395. data = str.split(/#|\x01|\|/),
  396. opt = obj.opt || str,
  397. state = setting.lose;
  398. obj.code > 0 && $input.each(function (index) {
  399. if (this.value == 'true') {
  400. data.join().match(/(^|,)(正确|是|对|√|T|ri|right|true)(,|$)/) && this.click();
  401. } else if (this.value == 'false') {
  402. data.join().match(/(^|,)(错误|否|错|×|F|wr|wrong|false)(,|$)/) && this.click();
  403. } else {
  404. var tip = filterImg($li.eq(index).find('.after')).toCDB() || new Date().toString();
  405. Boolean($.inArray(tip, data) + 1 || (type == '1' && str.indexOf(tip) + 1)) == this.checked || this.click();
  406. }
  407. }).each(function () {
  408. if (!/^A?B?C?D?E?F?G?$/.test(opt)) return false;
  409. Boolean(opt.match(this.value)) == this.checked || this.click();
  410. });
  411. if (type.match(/^[013]$/)) {
  412. $input.is(':checked') || (setting.none ? ($input[Math.floor(Math.random() * $input.length)] || $()).click() : setting.lose++);
  413. } else if (type.match(/^(2|[4-9]|1[08])$/)) {
  414. data = String(obj.data).split(/#|\x01|\|/);
  415. str = $li.end().find('textarea').each(function (index) {
  416. index = (obj.code > 0 && data[index]) || this.value || '';
  417. UE.getEditor(this.name).setContent(index.trim());
  418. }).length;
  419. (obj.code == 1 && data.length == str) || setting.none || setting.lose++;
  420. } else {
  421. setting.none || setting.lose++;
  422. }
  423. return state == setting.lose;
  424. }
  425.  
  426. function saveThis() {
  427. if (!setting.auto_save) return setTimeout(saveThis, setting.time);
  428. $('#tempsave').click();
  429. setting.regl();
  430. }
  431.  
  432. function submitThis() {
  433. if (!setting.auto_submit) {} else if (!$('.Btn_blue_1:visible').length) {
  434. return setting.regl();
  435. } else if ($('#confirmSubWin:visible').length) {
  436. var btn = $('#tipContent + * > a').offset() || {
  437. top: 0,
  438. left: 0
  439. },
  440. mouse = document.createEvent('MouseEvents');
  441. btn = [btn.left + Math.ceil(Math.random() * 46), btn.top + Math.ceil(Math.random() * 26)];
  442. mouse.initMouseEvent('click', true, true, document.defaultView, 0, 0, 0, btn[0], btn[1], false, false, false, false, 0, null);
  443. _self.event = $.extend(true, {}, mouse);
  444. delete _self.event.isTrusted;
  445. _self.form1submit();
  446. } else {
  447. $('.Btn_blue_1')[0].click();
  448. }
  449. setTimeout(submitThis, Math.ceil(setting.time * Math.random()) * 2);
  450. }
  451.  
  452. function checkToNext() {
  453. var $tip = $(setting.job.join(', '), document).prevAll('.ans-job-icon' + setting.normal);
  454. setInterval(function () {
  455. $tip.parent(':not(.ans-job-finished)').length || setting.jump && toNext();
  456. }, setting.time);
  457. }
  458.  
  459. function toNext() {
  460. let $ = _self.parent.$;
  461. var $cur = $('#cur' + $('#chapterIdid').val()),
  462. $tip = $('span.currents ~ span'),
  463. sel = setting.review ? 'html' : '.blue';
  464. if (!$cur.has(sel).length && $tip.length) return $tip.eq(0).click();
  465. $tip = $('.roundpointStudent, .roundpoint').parent();
  466. $tip = $tip.slice($tip.index($cur) + 1).not(':has(' + sel + ')');
  467. $tip.not(setting.lock ? ':has(.lock)' : 'html').find('span').eq(0).click();
  468. $tip.length || setting.course && switchCourse();
  469. }
  470.  
  471. function switchCourse() {
  472. GM_xmlhttpRequest({
  473. method: 'GET',
  474. url: '/visit/courses/study?isAjax=true&fileId=0&debug=',
  475. headers: {
  476. 'Referer': location.origin + '/visit/courses',
  477. 'X-Requested-With': 'XMLHttpRequest'
  478. },
  479. onload: function (xhr) {
  480. var $list = $('.curFile .courseName', xhr.responseText),
  481. index = $list.index($list.filter('[href*="courseid=' + top.courseId + '&"]')) + 1;
  482. index = index && $list.eq(index).attr('href');
  483. setting.course = index && goCourse(index);
  484. }
  485. });
  486. }
  487.  
  488. function goCourse(url) {
  489. GM_xmlhttpRequest({
  490. method: 'GET',
  491. url: url,
  492. onload: function (xhr) {
  493. $.globalEval('location.href = "' + $('.articlename a[href]', xhr.responseText).attr('href') + '";');
  494. }
  495. });
  496. }
  497.  
  498. function autoRead() {
  499. $('html, body').animate({
  500. scrollTop: $(document).height() - $(window).height()
  501. }, Math.round(setting.read) * 1E3, function () {
  502. $('.nodeItem.r i').click();
  503. }).one('click', '#top', function (event) {
  504. $(event.delegateTarget).stop();
  505. });
  506. }
  507.  
  508. function submitAnswer($job, data) {
  509. $job.removeClass('ans-job-finished');
  510. data = data.length ? $(data) : $('.TiMu').map(function () {
  511. var title = filterImg($('.Zy_TItle .clearfix', this));
  512. return {
  513. question: title.replace(/^【.*?】\s*/, ''),
  514. type: ({
  515. 单选题: 0,
  516. 多选题: 1,
  517. 填空题: 2,
  518. 判断题: 3
  519. })[title.match(/^【(.*?)】|$/)[1]]
  520. };
  521. });
  522. data = $.grep(data.map(function (index) {
  523. var $TiMu = $('.TiMu').eq(index);
  524. if (!($.isPlainObject(this) && this.type < 4 && $TiMu.find('.fr').length)) {
  525. return false;
  526. } else if (this.type == 2) {
  527. var $ans = $TiMu.find('.Py_tk, .Py_answer').eq(0);
  528. if (!$TiMu.find('.cuo').length && this.code) {
  529. return false;
  530. } else if (!$ans.find('.cuo').length) {
  531. this.option = $ans.find('.clearfix').map(function () {
  532. return filterImg(this);
  533. }).get().join('#') || '无';
  534. } else if (this.code) {
  535. this.code = -1;
  536. } else {
  537. return false;
  538. }
  539. } else if (this.type == 3) {
  540. var ans = $TiMu.find('.font20:last').text();
  541. if ($TiMu.find('.cuo').length) {
  542. this.option = ({
  543. '√': '错误',
  544. '×': '正确'
  545. })[ans] || '无';
  546. } else if (!this.code) {
  547. this.option = ({
  548. '√': '正确',
  549. '×': '错误'
  550. })[ans] || '无';
  551. } else {
  552. return false;
  553. }
  554. } else {
  555. var text = $TiMu.find('.Py_answer > span:eq(0)').text();
  556. if ($TiMu.find('.dui').length && this.code && !/^A?B?C?D?E?F?G?$/.test(this.option)) {
  557. return false;
  558. } else if ($TiMu.find('.dui').length || text.match('正确答案')) {
  559. text = text.match(/[A-G]/gi) || [];
  560. this.option = $.map(text, function (value) {
  561. return filterImg($TiMu.find('.fl:contains(' + value + ') + a'));
  562. }).join('#') || '无';
  563. this.key = text.join('');
  564. } else if (this.code) {
  565. this.code = -1;
  566. } else {
  567. return false;
  568. }
  569. }
  570. return this;
  571. }), function (value) {
  572. return value && value.option != '无';
  573. });
  574. setting.curs = $('script:contains(courseName)', top.document).text().match(/courseName:\'(.+?)\'|$/)[1] || $('h1').text().trim() || '无';
  575. data.length && GM_xmlhttpRequest({
  576. method: 'POST',
  577. url: setting.tiku + '/cx/v2/work',
  578. headers: {
  579. 'Content-type': 'application/json'
  580. },
  581. data: JSON.stringify({
  582. course: setting.curs,
  583. data: (Ext.encode || JSON.stringify)(data),
  584. jobid: $('#jobid').val().slice(5),
  585. workId: $('#workId').val(),
  586. })
  587. });
  588. $job.addClass('ans-job-finished');
  589. }
  590.  
  591. function showMtDashboard() {
  592. $('#mt-dashboard').remove();
  593. const dashboardHtml = `
  594. <div id="mt-dashboard" class="layui-card" style="top: 30px; left: 10px; position: fixed;width: 360px; margin-left: 20px; touch-action: none; border-radius: 10px;box-shadow: 0px 6px 20px -6px #0b2b9e26; border: 3px solid #7431F9">
  595. <div class="layui-card-header" style="background-color: #7431F9; color: white; border-bottom:0px;">
  596. <i class="layui-icon layui-icon-senior"></i>
  597. <span style="font-weight: bold;">Muketool 网课助手&nbsp;&nbsp;</span>
  598. <span id="mt-dashboard-version">
  599. <a href="https://www.muketool.com" target="_blank" class="layui-btn layui-btn-xs" style="color: white;background-color: #7431F9; border: 1px solid white;border-radius: 5px;">${setting.script_version}</a>
  600. </span>
  601. <span id="mt-dashboard-help">
  602. <a href="https://www.muketool.com" target="_blank" class="layui-btn layui-btn-xs" style="background-color: white; color: black;border-radius: 5px;">使用帮助</a>
  603. </span>
  604. </div>
  605. <div class="layui-card-body " style="border-radius: 10px; padding-bottom:30px;">
  606. <div id="mt-dashboard-status">
  607. <i class="layui-icon layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop"></i>&nbsp;
  608. <span class="layui-font-13" style="font-weight: bold;">正在自动执行相关任务,请喝杯茶耐心等待......</span>
  609. </div>
  610. <div id="mt-dashboard-tips">
  611. <hr class="layui-border-cyan">
  612. <div class="layui-font-12" style="margin-bottom: 5px;">
  613. 欢迎使用Muketool网课助手,该面板将控制脚本的运行及显示相关的通知,您可以使用鼠标拖动面板调整位置哦 :)
  614. </div>
  615. </div>
  616. <div id="mt-dashboard-notifications">
  617. <hr class="layui-border-cyan">
  618. <div class="layui-font-12" style="margin-bottom: 5px;">
  619. 正在加载中...
  620. </div>
  621. </div>
  622. <div id="mt-dashboard-setting">
  623. <hr class="layui-border-cyan">
  624. <div class="layui-btn-container">
  625. <button type="button" id="mt-setting-button-1" class="layui-btn layui-btn-sm" style="background-color: white;border-radius: 5px; color: black; border-color: #7431F9"><i class="layui-icon layui-icon-ok"></i>自动答题已开启
  626. </button>
  627. <button type="button" id="mt-setting-button-2" class="layui-btn layui-btn-sm" style="background-color: white;border-radius: 5px; color: black; border-color: #7431F9"><i class="layui-icon layui-icon-close"></i>自动提交已关闭
  628. </button>
  629. <button type="button" id="mt-setting-button-3" class="layui-btn layui-btn-sm" style="background-color: white;border-radius: 5px; color: black; border-color: #7431F9"><i class="layui-icon layui-icon-refresh"></i>重新搜索答案
  630. </button>
  631. <button type="button" id="mt-setting-button-4" class="layui-btn layui-btn-sm" style="background-color: white;border-radius: 5px; color: black; border-color: #7431F9"><i class="layui-icon layui-icon-down"></i>搜题记录已显示
  632. </button>
  633. </div>
  634. </div>
  635. <div style="max-height: 200px; overflow: auto;">
  636. <hr class="layui-border-cyan">
  637. <div class="layui-font-12" id="mt-table-tips">
  638. 温馨提示:点击下方表格中的文字可直接复制。
  639. </div>
  640. <table class="layui-table" id="mt-dashboard-history" >
  641. <colgroup>
  642. <col>
  643. <col>
  644. <col>
  645. </colgroup>
  646. <thead>
  647. <tr>
  648. <th class="layui-font-12 layui-center" style="font-weight: bold;">题号</th>
  649. <th class="layui-font-12 layui-center" style="font-weight: bold;">题目</th>
  650. <th class="layui-font-12 layui-center" style="font-weight: bold;">答案</th>
  651. </tr>
  652. </thead>
  653. <tbody>
  654. </tbody>
  655. </table>
  656. </div>
  657. </div>
  658. </div>
  659. `;
  660. _self.top.$(dashboardHtml).appendTo('body');
  661. let $mt_dashboard = _self.top.$('#mt-dashboard');
  662. var $body = $('body');
  663. var $document = $(_self.top.document);
  664. $mt_dashboard.on('mousedown', function (e) {
  665. e.preventDefault();
  666. var x = e.clientX,
  667. y = e.clientY,
  668. l = $mt_dashboard.position().left,
  669. t = $mt_dashboard.position().top;
  670. var scrollTop = $document.scrollTop();
  671. $body.css('cursor', 'move');
  672. $mt_dashboard.css('cursor', 'move');
  673. $document.on('mousemove', function (e) {
  674. $mt_dashboard.css({
  675. left: l + e.clientX - x,
  676. top: t + e.clientY - y - scrollTop
  677. });
  678. }).on('mouseup', function () {
  679. $body.css('cursor', '');
  680. $mt_dashboard.css('cursor', '');
  681. $(this).off('mousemove mouseup');
  682. });
  683. });
  684. var $dashboardTips = $('#mt-dashboard-tips', $mt_dashboard);
  685. var $dashboardNotifications = $('#mt-dashboard-notifications', $mt_dashboard);
  686. var $dashboardVersion = $('#mt-dashboard-version', $mt_dashboard);
  687. var $dashboardHelp = $('#mt-dashboard-doc', $mt_dashboard);
  688. var resp_version, resp_tips, resp_notifications, resp_update, resp_help;
  689. GM_xmlhttpRequest({
  690. method: 'GET',
  691. url: setting.tiku + '/cx/v2/notification?script=' + setting.script + '&version=' + setting.script_version,
  692. timeout: setting.time,
  693. onload: function (xhr) {
  694. if (xhr.status == 200) {
  695. var obj = $.parseJSON(xhr.responseText) || {};
  696. resp_version = obj.version;
  697. resp_tips = obj.tips;
  698. resp_notifications = obj.notifications;
  699. resp_update = obj.update;
  700. resp_help = obj.help;
  701. if (resp_version != setting.script_version && resp_version != '') {
  702. $dashboardVersion.html(`<a href="${resp_update}" target="_blank" class="layui-btn layui-btn-xs" style="color: white;background-color: #7431F9; border: 1px solid white;border-radius: 5px;">更新脚本</a>`)
  703. }
  704. $dashboardHelp.html(`<a href="${resp_help}" target="_blank" class="layui-btn layui-btn-xs" style="background-color: white; color: black;border-radius: 5px;">使用帮助</a>`)
  705. } else {
  706. resp_version = '';
  707. resp_tips = [`<hr class="layui-border-cyan"><div class="layui-font-12" style="margin-bottom: 5px;">Muketool服务器连接失败,错误码:${response.status},可能是服务器正在维护或被攻击所致,稍后将尝试重新连接,如果长时间出现此异常请&nbsp;<a href="https://www.muketool.com" target="_blank" class="layui-btn layui-btn-xs layui-bg-red">点击此处</a>&nbsp;反馈。</div>`];
  708. resp_notifications = ['<hr class="layui-border-cyan"><div class="layui-font-12" style="margin-bottom: 5px;">服务器连接失败时自动搜题功能将不可用,其他功能正常,请耐心等待修复......</div>'];
  709. resp_update = 'https://www.muketool.com';
  710. resp_help = 'https://www.muketool.com/';
  711. }
  712. },
  713. onerror: function (error) {
  714. resp_version = '';
  715. resp_tips = [`<hr class="layui-border-cyan"><div class="layui-font-12" style="margin-bottom: 5px;">Muketool服务器连接失败,可能是服务器正在维护或被攻击所致,稍后将尝试重新连接,如果长时间出现此异常请&nbsp;<a href="https://www.muketool.com" target="_blank" class="layui-btn layui-btn-xs layui-bg-red">点击此处</a>&nbsp;反馈。</div>`];
  716. resp_notifications = ['<hr class="layui-border-cyan"><div class="layui-font-12" style="margin-bottom: 5px;">服务器连接失败时自动搜题功能将不可用,其他功能正常,请耐心等待修复......</div>'];
  717. resp_update = 'https://www.muketool.com';
  718. resp_help = 'https://www.muketool.com/';
  719. console.log('出现错误2');
  720. console.error('服务器超时,正在重试...' + JSON.stringify(error));
  721. }
  722. });
  723. setInterval(function () {
  724. $dashboardTips.html(resp_tips[Math.floor(Math.random() * resp_tips.length)]);
  725. $dashboardNotifications.html(resp_notifications[Math.floor(Math.random() * resp_notifications.length)]);
  726. }, 20000);
  727. }
  728.  
  729. function switchToNormal() {
  730. clearInterval(setting.loop);
  731. delete setting.loop;
  732. let $mt_dashboard = _self.top.$('#mt-dashboard');
  733. $('#mt-dashboard-setting', $mt_dashboard).hide();
  734. $('#mt-table-tips', $mt_dashboard).hide();
  735. $('#mt-dashboard-history tr', $mt_dashboard).not(':first').remove();
  736. $('#mt-dashboard-history', $mt_dashboard).hide();
  737. $('#mt-dashboard-status', $mt_dashboard).html('<i class="layui-icon layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop"></i>&nbsp;<span class="layui-font-13" style="font-weight: bold;">正在自动执行相关任务,请喝杯茶耐心等待......</span>');
  738. }
  739.  
  740. function switchToAnswering() {
  741. clearInterval(setting.loop);
  742. delete setting.loop;
  743. let $mt_dashboard = _self.top.$('#mt-dashboard');
  744. $('#mt-dashboard-setting', $mt_dashboard).show();
  745. $('#mt-table-tips', $mt_dashboard).show();
  746. $('#mt-dashboard-history tr', $mt_dashboard).not(':first').remove();
  747. $('#mt-dashboard-history', $mt_dashboard).show();
  748. setting.work ? $('#mt-dashboard-status', $mt_dashboard).html('<i class="layui-icon layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop"></i>&nbsp;<span class="layui-font-13" style="font-weight: bold;">正在拼命搜索试题答案中,您可在下方查看详情......</span>') : $('#mt-dashboard-status', $mt_dashboard).html('<i class="layui-icon layui-icon-pause"></i>&nbsp;<span class="layui-font-13" style="font-weight: bold;">自动搜题已关闭,您可在下方重新开启</span>');
  749. setting.search_history ? $('#mt-dashboard-history', $mt_dashboard).show() : '';
  750. setting.work ? $('#mt-setting-button-1', $mt_dashboard).html('<i class="layui-icon layui-icon-ok"></i>自动答题已开启') : $('#mt-setting-button-1', $mt_dashboard).html('<i class="layui-icon layui-icon-close"></i>自动答题已关闭');
  751. setting.auto_submit ? $('#mt-setting-button-2', $mt_dashboard).html('<i class="layui-icon layui-icon-ok"></i>自动提交已开启') : $('#mt-setting-button-2', $mt_dashboard).html('<i class="layui-icon layui-icon-close"></i>自动提交已关闭');
  752. setting.search_history ? $('#mt-setting-button-4', $mt_dashboard).html('<i class="layui-icon layui-icon-down"></i>搜题记录已显示') : $('#mt-setting-button-4', $mt_dashboard).html('<i class="layui-icon layui-icon-right"></i>搜题记录已隐藏');
  753. setting.search_history ? $('#mt-table-tips', $mt_dashboard).html('温馨提示:点击下方表格中的文字可直接复制~~') : $('#mt-table-tips', $mt_dashboard).html('搜题历史记录已隐藏,您可在上方重新开启');
  754. }
  755.  
  756. function filterImg(dom) {
  757. return $(dom).clone().find('img[src]').replaceWith(function () {
  758. return $('<p></p>').text('<img src="' + $(this).attr('src') + '">');
  759. }).end().find('iframe[src]').replaceWith(function () {
  760. return $('<p></p>').text('<iframe src="' + $(this).attr('src') + '"></irame>');
  761. }).end().text().trim();
  762. }
  763.  
  764. function skipQuestion() {
  765. const originOpen = XMLHttpRequest.prototype.open;
  766. XMLHttpRequest.prototype.open = function (_, url) {
  767. if (url.indexOf('richvideo/initdatawithviewerV2') > -1) {
  768. this.addEventListener("readystatechange", function () {
  769. if (this.readyState === 4) {
  770. Object.defineProperty(this, "responseText", {
  771. writable: true,
  772. });
  773. this.responseText = JSON.stringify([]);
  774. }
  775. });
  776. }
  777. originOpen.apply(this, arguments);
  778. };
  779. }