超星学习通网课助手[最全接口][最强答题][支持图片题]

接口自动提交功能可视化变更,自动挂机看尔雅MOOC,支持视频、音频、文档、图书自动完成,章节测验自动答题提交,支持自动切换任务点、挂机阅读时长、自动登录等,解除各类功能限制,开放自定义参数。

  1. // ==UserScript==
  2. // @name 超星学习通网课助手[最全接口][最强答题][支持图片题]
  3. // @namespace isoan
  4. // @version 1.2.1
  5. // @description 接口自动提交功能可视化变更,自动挂机看尔雅MOOC,支持视频、音频、文档、图书自动完成,章节测验自动答题提交,支持自动切换任务点、挂机阅读时长、自动登录等,解除各类功能限制,开放自定义参数。
  6. // @author chatijun
  7. // @match *://*.chaoxing.com/*
  8. // @match *://*.edu.cn/*
  9. // @match *://*.nbdlib.cn/*
  10. // @match *://*.hnsyu.net/*
  11. // @connect cx.icodef.com
  12. // @connect api.gochati.cn
  13. // @run-at document-end
  14. // @grant unsafeWindow
  15. // @grant GM_xmlhttpRequest
  16. // @grant GM_setClipboard
  17. // @license MIT
  18. // @original-script https://greasyfork.org/scripts/369625
  19. // @original-author wyn665817
  20. // @original-license MIT
  21. // ==/UserScript==
  22. // 设置修改后,需要刷新页面才会生效
  23. var queryapi = [
  24. {"url": "http://api.gochati.cn/jsapi.php","getIssueParam":"token=cxmooc&q=","keyParam":"da","method":"GET"},
  25. {"url": "http://cx.icodef.com/wyn-nb?v=2", "postIssueParam": "question", "keyParam": "data", "method": "POST"},
  26. ];
  27. var setting = {
  28. // 8E3 == 8000,科学记数法,表示毫秒数
  29. api: 1 //默认接口,在这里设置默认使用接口
  30. ,
  31. time: 8E3 // 默认响应速度为8秒,不建议小于3秒,减轻服务器响应压力
  32. ,
  33. review: 0 // 复习模式,完整挂机视频(音频)时长,支持挂机任务点已完成的视频和音频,默认关闭
  34. ,
  35. queue: 1 // 队列模式,开启后任务点逐一完成,关闭则单页面所有任务点同时进行,默认开启
  36. // 1代表开启,0代表关闭
  37. ,
  38. video: 1 // 视频支持后台、切换窗口不暂停,支持多视频,默认开启
  39. ,
  40. work: 1 // 自动答题功能(章节测验),作业需要手动开启查询,高准确率,默认开启
  41. ,
  42. audio: 1 // 音频自动播放,与视频功能共享vol和rate参数,默认开启
  43. ,
  44. book: 1 // 图书阅读任务点,非课程阅读任务点,默认开启
  45. ,
  46. docs: 1 // 文档阅读任务点,PPT类任务点自动完成阅读任务,默认开启
  47. // 本区域参数,上方为任务点功能,下方为独立功能
  48. ,
  49. jump: 1 // 自动切换任务点、章节、课程(需要配置course参数),默认开启
  50. ,
  51. read: '0' // 挂机课程阅读时间,单位是分钟,'65'代表挂机65分钟,请手动打开阅读页面,默认'0'分钟
  52. ,
  53. face: 0 // 解除面部识别(不支持二维码类面部采集),此功能仅为临时解除,默认关闭
  54. ,
  55. total: 0 // 显示课程进度的统计数据,在学习进度页面的上方展示,默认关闭
  56. // 仅开启video(audio)时,修改此处才会生效
  57. ,
  58. line: '公网1' // 视频播放的默认资源线路,此功能适用于系统默认线路无资源,默认'公网1'
  59. ,
  60. http: '标清' // 视频播放的默认清晰度,无效参数则使用系统默认清晰度,默认'标清'
  61. // 本区域参数,上方为video功能独享,下方为audio功能共享
  62. ,
  63. vol: '0' // 默认音量的百分数,设定范围:[0,100],'0'为静音,默认'0'
  64. ,
  65. rate: '1' // 视频播放默认倍率,参数范围0∪[0.0625,16],'0'为秒过,默认'1'倍
  66. // 仅开启work时,修改此处才会生效
  67. ,
  68. auto: 0 // 答题完成后自动提交,默认关闭
  69. ,
  70. none: 1 // 无匹配答案时执行默认操作,关闭后若题目无匹配答案则会暂时保存已作答的题目,默认开启
  71. ,
  72. scale: 0 // 富文本编辑器高度自动拉伸,用于文本类题目,答题框根据内容自动调整大小,默认关闭
  73. // 仅开启jump时,修改此处才会生效
  74. ,
  75. course: 0 // 当前课程完成后自动切换课程,仅支持按照根目录课程顺序切换,默认关闭
  76. ,
  77. lock: 1 // 跳过未开放(图标是锁)的章节,即闯关模式或定时发放的任务点,默认开启
  78. // 自动登录功能配置区
  79. ,
  80. school: '账号为手机号可以不修改此参数' // 学校/单位/机构码,要求完整有效可查询,例如'清华大学'
  81. ,
  82. username: '' // 学号/工号/借书证号(邮箱/手机号/账号),例如'2018010101',默认''
  83. ,
  84. password: '' // 密码,例如'123456',默认''
  85. ,
  86. notice: '' //默认通知
  87. },
  88. _self = unsafeWindow,
  89. url = location.pathname,
  90. top = _self;
  91. checkMCInfo();
  92. if (url != '/studyApp/studying' &&
  93. top != _self.top) document.domain =
  94. location.host.replace(/.+?\./, '');
  95. try
  96. {
  97. while (top != _self.top)
  98. {
  99. top = top.parent.document ? top
  100. .parent : _self.top;
  101. if (top.location.pathname ==
  102. '/mycourse/studentstudy') break;
  103. }
  104. }
  105. catch (err)
  106. {
  107. // console.log(err);
  108. top = _self;
  109. }
  110. var $ = _self.jQuery || top.jQuery,
  111. parent = _self == top ? self : _self
  112. .parent,
  113. Ext = _self.Ext || parent.Ext ||
  114. {},
  115. UE = _self.UE,
  116. vjs = _self.videojs;
  117. String.prototype.toCDB = function ()
  118. {
  119. return this.replace(/\s/g, '')
  120. .replace(/[\uff01-\uff5e]/g,
  121. function (str)
  122. {
  123. return String.fromCharCode(str
  124. .charCodeAt(0) - 65248);
  125. })
  126. .replace(/[“”]/g, '"')
  127. .replace(/[‘’]/g, "'")
  128. .replace(/。/g, '.');
  129. };
  130. setting.normal = ''; // ':visible'
  131. // setting.time += Math.ceil(setting.time * Math.random()) - setting.time / 2;
  132. setting.job = [':not(*)'];
  133. setting.video && setting.job.push(
  134. 'iframe[src*="/video/index.html"]');
  135. setting.work && setting.job.push(
  136. 'iframe[src*="/work/index.html"]');
  137. setting.audio && setting.job.push(
  138. 'iframe[src*="/audio/index.html"]');
  139. setting.book && setting.job.push(
  140. 'iframe[src*="/innerbook/index.html"]'
  141. );
  142. setting.docs && setting.job.push(
  143. 'iframe[src*="/ppt/index.html"]',
  144. 'iframe[src*="/pdf/index.html"]');
  145. setting.tip = !setting.queue || top !=
  146. _self && jobSort($ || Ext.query);
  147. if (url == '/mycourse/studentstudy')
  148. {
  149. _self.checkMobileBrowerLearn = $.noop;
  150. var classId = location.search.match(
  151. /cla[zs]{2}id=(\d+)/i)[1] || 0,
  152. courseId = _self.courseId ||
  153. location.search.match(
  154. /courseId=(\d+)/i)[1] || 0;
  155. setting.lock || $('#coursetree')
  156. .on('click',
  157. '[onclick*=void], [href*=void]',
  158. function ()
  159. {
  160. _self.getTeacherAjax(courseId,
  161. classId, $(this)
  162. .parent()
  163. .attr('id')
  164. .slice(3));
  165. });
  166. }
  167. else if (url ==
  168. '/ananas/modules/video/index.html' &&
  169. setting.video)
  170. {
  171. if (setting.review) _self.greenligth =
  172. Ext.emptyFn;
  173. checkPlayer(_self.supportH5Video());
  174. }
  175. else if (url == '/work/doHomeWorkNew' ||
  176. url == '/api/work' || url ==
  177. '/work/addStudentWorkNewWeb')
  178. {
  179. if (!UE)
  180. {
  181. var len = ($ || Ext.query || Array)(
  182. 'font:contains(未登录)', document)
  183. .length;
  184. setTimeout(len == 1 ? top.location
  185. .reload : parent.greenligth,
  186. setting.time);
  187. }
  188. else if (setting.work)
  189. {
  190. setTimeout(relieveLimit, 0);
  191. beforeFind();
  192. }
  193. }
  194. else if (url ==
  195. '/ananas/modules/audio/index.html' &&
  196. setting.audio)
  197. {
  198. if (setting.review) _self.greenligth =
  199. Ext.emptyFn;
  200. _self.videojs = hookAudio;
  201. hookAudio.xhr = vjs.xhr;
  202. }
  203. else if (url ==
  204. '/ananas/modules/innerbook/index.html' &&
  205. setting.book && setting.tip)
  206. {
  207. setTimeout(function ()
  208. {
  209. _self.setting ? _self.top
  210. .onchangepage(_self
  211. .getFrameAttr('end')) :
  212. _self.greenligth();
  213. }, setting.time);
  214. }
  215. else if (url.match(
  216. /^\/ananas\/modules\/(ppt|pdf)\/index\.html$/
  217. ) && setting.docs && setting.tip)
  218. {
  219. setTimeout(function ()
  220. {
  221. _self.setting ? _self
  222. .finishJob() : _self
  223. .greenligth();
  224. }, setting.time);
  225. frameElement.setAttribute('download',
  226. 1);
  227. }
  228. else if (url == '/knowledge/cards')
  229. {
  230. $ && checkToNext();
  231. }
  232. else if (url.match(
  233. /^\/(course|zt)\/\d+\.html$/))
  234. {
  235. setTimeout(function ()
  236. {
  237. +setting.read && _self
  238. .sendLogs && $(
  239. '.course_section:eq(0) .chapterText'
  240. )
  241. .click();
  242. }, setting.time);
  243. }
  244. else if (url ==
  245. '/ztnodedetailcontroller/visitnodedetail'
  246. )
  247. {
  248. setting.read *= 60 / $(
  249. '.course_section')
  250. .length;
  251. setting.read && _self.sendLogs &&
  252. autoRead();
  253. }
  254. else if (url == '/mycourse/stu')
  255. {
  256. console.log(url)
  257. if (document.querySelector(
  258. 'body > div.box > div.Header > div > a'
  259. ) !== null)
  260. {
  261. backToOld();
  262. }
  263. }
  264. else if (url ==
  265. '/mycourse/studentcourse')
  266. {
  267. var gv = location.search.match(
  268. /d=\d+&/g);
  269. setting.total && $('<a>',
  270. {
  271. href: '/moocAnalysis/chapterStatisticByUser?classI' +
  272. gv[1] + 'courseI' + gv[0] +
  273. 'userId=' + _self.getCookie(
  274. '_uid') + '&ut=s',
  275. target: '_blank',
  276. title: '点击查看章节统计',
  277. style: 'margin: 0 25px;',
  278. html: '本课程共' + $('.icon')
  279. .length + '节,剩余' + $(
  280. 'em:not(.openlock)')
  281. .length + '节未完成'
  282. })
  283. .appendTo('.zt_logo')
  284. .parent()
  285. .width('auto');
  286. }
  287. else if (url.match(
  288. /^\/visit\/(courses|interaction)$/
  289. ))
  290. {
  291. setting.face && $('.zmodel')
  292. .on('click',
  293. '[onclick^=openFaceTip]',
  294. DisplayURL);
  295. }
  296. else if (location.host.match(
  297. /^passport2/))
  298. {
  299. setting.username && getSchoolId();
  300. }
  301. else if (location.hostname ==
  302. 'i.mooc.chaoxing.com')
  303. {
  304. _self.layui.use('layer', function ()
  305. {
  306. this.layer.open(
  307. {
  308. content: '拖动进度条、倍速播放、秒过会导致不良记录!',
  309. title: '超星网课助手提示',
  310. btn: '我已知悉',
  311. offset: 't',
  312. closeBtn: 0
  313. });
  314. });
  315. }
  316. else if (url ==
  317. '/widget/pcvote/goStudentVotePage')
  318. {
  319. $(':checked')
  320. .click();
  321. $('.StudentTimu')
  322. .each(function (index)
  323. {
  324. var ans = _self.questionlist[
  325. index].answer;
  326. $(':radio, :checkbox', this)
  327. .each(function (num)
  328. {
  329. ans[num].isanswer && this
  330. .click();
  331. });
  332. $(':text', this)
  333. .val(function (num)
  334. {
  335. return $(ans[num].content)
  336. .text()
  337. .trim();
  338. });
  339. });
  340. }
  341. else if (url ==
  342. '/work/selectWorkQuestionYiPiYue')
  343. {
  344. submitAnswer(getIframe()
  345. .parent(), $.extend(true, [],
  346. parent._data));
  347. }
  348. function getIframe(tip, win, job)
  349. {
  350. if (!$) return Ext.get(frameElement ||
  351. [])
  352. .parent()
  353. .child('.ans-job-icon') || Ext
  354. .get([]);
  355. do {
  356. win = win ? win.parent : _self;
  357. job = $(win.frameElement)
  358. .prevAll('.ans-job-icon');
  359. } while (!job.length && win.parent
  360. .frameElement);
  361. return tip ? win : job;
  362. }
  363. function jobSort($)
  364. {
  365. var fn = $.fn ? [getIframe(1),
  366. 'length'
  367. ] : [self, 'dom'],
  368. sel = setting.job.join(
  369. ', :not(.ans-job-finished) > .ans-job-icon' +
  370. setting.normal + ' ~ ');
  371. if ($(sel, fn[0].parent.document)[
  372. 0] == fn[0].frameElement)
  373. return true;
  374. if (!getIframe()[fn[1]] || getIframe()
  375. .parent()
  376. .is('.ans-job-finished'))
  377. return null;
  378. setInterval(function ()
  379. {
  380. $(sel, fn[0].parent.document)[
  381. 0] == fn[0].frameElement &&
  382. fn[0].location.reload();
  383. }, setting.time);
  384. }
  385. function checkPlayer(tip)
  386. {
  387. _self.videojs = hookVideo;
  388. hookVideo.xhr = vjs.xhr;
  389. Ext.isSogou = Ext.isIos = Ext
  390. .isAndroid = false;
  391. var data = Ext.decode(_self.config(
  392. 'data')) ||
  393. {};
  394. delete data.danmaku;
  395. data.doublespeed = 1;
  396. frameElement.setAttribute('data', Ext
  397. .encode(data));
  398. if (tip) return;
  399. _self.supportH5Video = function ()
  400. {
  401. return true;
  402. };
  403. alert('此浏览器不支持html5播放器,请更换浏览器');
  404. }
  405. function relieveLimit()
  406. {
  407. if (setting.scale) _self
  408. .UEDITOR_CONFIG.scaleEnabled =
  409. false;
  410. $.each(UE.instants, function ()
  411. {
  412. var key = this.key;
  413. this.ready(function ()
  414. {
  415. this.destroy();
  416. UE.getEditor(key);
  417. });
  418. });
  419. }
  420. function hookAudio()
  421. {
  422. _self.alert = console.log;
  423. var config = arguments[1];
  424. config.plugins.studyControl
  425. .enableSwitchWindow = 1;
  426. config.plugins.seekBarControl
  427. .enableFastForward = 1;
  428. if (!setting.queue) delete config
  429. .plugins.studyControl;
  430. var player = vjs.apply(this,
  431. arguments),
  432. a =
  433. '<a href="https://d0.ananas.chaoxing.com/download/' +
  434. _self.config('objectid') +
  435. '" target="_blank">',
  436. img =
  437. '<img src="https://d0.ananas.chaoxing.com/download/e363b256c0e9bc5bd8266bf99dd6d6bb" style="margin: 6px 0 0 6px;">';
  438. player.volume(Math.round(setting
  439. .vol) / 100 || 0);
  440. player.playbackRate(setting.rate >
  441. 16 || setting.rate < 0.0625 ? 1 :
  442. setting.rate);
  443. Ext.get(player.controlBar.addChild(
  444. 'Button')
  445. .el_)
  446. .setHTML(a + img + '</a>')
  447. .dom.title = '下载音频';
  448. player.on('loadeddata', function ()
  449. {
  450. setting.tip && this.play()
  451. .catch(Ext.emptyFn);
  452. });
  453. player.one('firstplay', function ()
  454. {
  455. setting.rate === '0' && config
  456. .plugins.seekBarControl
  457. .sendLog(this.children_[0],
  458. 'ended', Math.floor(this
  459. .cache_.duration));
  460. });
  461. player.on('ended', function ()
  462. {
  463. Ext.fly(frameElement)
  464. .parent()
  465. .addCls('ans-job-finished');
  466. });
  467. return player;
  468. }
  469. function beforeFind()
  470. {
  471. setting.regl = parent.greenligth || $
  472. .noop;
  473. if ($.type(parent._data) == 'array')
  474. return setting.regl();
  475. setting.div = $(
  476. '<div style="border: 2px dashed rgba(255,12,0,0.7); width: 330px; position: fixed; top: 0; right: 0; z-index: 99999; background-color: rgba(255,250,110,0.6); overflow-x: auto;">' +
  477. '<span style="font-size: medium;"></span>' +
  478. '<div style="font-size: medium;">正在搜索答案...</div>' +
  479. '<button style="margin-right: 10px;">暂停答题</button>' +
  480. '<button style="margin-right: 10px;">' +
  481. (setting.auto ? '关闭自动提交' :
  482. '开启自动提交') + '</button>' +
  483. '<button style="margin-right: 10px;">重新查询</button>' +
  484. '<button>折叠面板</button>' +
  485. '<button>切换接口</button>' +
  486. '<div style="max-height: 300px; overflow-y: auto;">' +
  487. '<table border="1" style="font-size: 12px;">' +
  488. '<thead>' +
  489. '<tr>' +
  490. '<th style="width: 25px; min-width: 25px;">题号</th>' +
  491. '<th style="width: 60%; min-width: 130px;">题目(点击可复制)</th>' +
  492. '<th style="min-width: 130px;">答案(点击可复制)</th>' +
  493. '</tr>' +
  494. '</thead>' +
  495. '<tfoot style="display: none;">' +
  496. '<tr>' +
  497. '<th colspan="3">答案提示框 已折叠</th>' +
  498. '</tr>' +
  499. '</tfoot>' +
  500. '<tbody>' +
  501. '<tr>' +
  502. '<td colspan="3" style="display: none;"></td>' +
  503. '</tr>' +
  504. '</tbody>' +
  505. '</table>' +
  506. '</div>' +
  507. '</div>'
  508. )
  509. .appendTo('body')
  510. .on('click', 'button, td',
  511. function ()
  512. {
  513. var len = $(this)
  514. .prevAll('button')
  515. .length;
  516. var user_setting = JSON.parse(
  517. getMCInfo("MC_user_setting")
  518. );
  519. if (this.nodeName == 'TD')
  520. {
  521. $(this)
  522. .prev()
  523. .length && GM_setClipboard(
  524. $(this)
  525. .text());
  526. }
  527. else if (!$(this)
  528. .siblings()
  529. .length)
  530. {
  531. $(this)
  532. .parent()
  533. .text('正在搜索答案...');
  534. setting.num++;
  535. }
  536. else if (len === 0)
  537. {
  538. if (setting.loop)
  539. {
  540. clearInterval(setting.loop);
  541. delete setting.loop;
  542. len = ['已暂停搜索', '继续答题'];
  543. }
  544. else
  545. {
  546. setting.loop = setInterval(
  547. findAnswer, setting.time
  548. );
  549. len = ['正在搜索答案...', '暂停答题'];
  550. }
  551. setting.div.children(
  552. 'div:eq(0)')
  553. .html(function ()
  554. {
  555. return $(this)
  556. .data('html') || len[
  557. 0];
  558. })
  559. .removeData('html');
  560. $(this)
  561. .html(len[1]);
  562. }
  563. else if (len == 1)
  564. {
  565. setting.auto = !setting.auto;
  566. $(this)
  567. .html(setting.auto ?
  568. '关闭自动提交' : '开启自动提交');
  569. //save data
  570. setMCInfo(user_setting.api,
  571. setting.auto, 30);
  572. }
  573. else if (len == 2)
  574. {
  575. parent.location.reload();
  576. }
  577. else if (len == 3)
  578. {
  579. setting.div.find(
  580. 'tbody, tfoot')
  581. .toggle();
  582. }
  583. else if (len == 4)
  584. {
  585. setting.api < queryapi
  586. .length - 1 ? setting.api +=
  587. 1 : setting.api = 0;
  588. $(this)
  589. .html('切换接口,当前接口:' + setting
  590. .api);
  591. //save data
  592. setMCInfo(setting.api,
  593. user_setting.auto, 30);
  594. //重新请求
  595. clearInterval(setting.loop);
  596. delete setting.loop;
  597. setting.loop = setInterval(
  598. findAnswer, setting.time);
  599. }
  600. })
  601. .find('table, td, th')
  602. .css('border', '1px solid')
  603. .end();
  604. setting.lose = setting.num = 0;
  605. setting.data = parent._data = [];
  606. setting.over =
  607. '<button style="margin-right: 10px;">跳过此题</button>';
  608. setting.curs = $(
  609. 'script:contains(courseName)', top
  610. .document)
  611. .text()
  612. .match(/courseName:\'(.+?)\'|$/)[
  613. 1] || $('h1')
  614. .text()
  615. .trim() || '无';
  616. setting.loop = setInterval(findAnswer,
  617. setting.time);
  618. var tip = (
  619. {
  620. undefined: '任务点排队中',
  621. null: '等待切换中'
  622. })[setting.tip];
  623. tip && setting.div.children(
  624. 'div:eq(0)')
  625. .data('html', tip)
  626. .siblings('button:eq(0)')
  627. .click();
  628. }
  629. function findAnswer()
  630. {
  631. let user_setting = JSON.parse(
  632. getMCInfo("MC_user_setting"));
  633. setting.api = user_setting.api;
  634. if (setting.num >= $('.TiMu')
  635. .length)
  636. {
  637. var arr = setting.lose ? [
  638. '共有 <font color="red">' +
  639. setting.lose +
  640. '</font> 道题目待完善(已深色标注)',
  641. saveThis
  642. ] : ['答题已完成', submitThis];
  643. setting.div.children('div:eq(0)')
  644. .data('html', arr[0])
  645. .siblings('button:eq(0)')
  646. .hide()
  647. .click();
  648. return setTimeout(arr[1], setting
  649. .time);
  650. }
  651. var $TiMu = $('.TiMu')
  652. .eq(setting.num),
  653. question = filterImg($TiMu.find(
  654. '.Zy_TItle:eq(0) .clearfix'))
  655. .replace(/^【.*?】\s*/, '')
  656. .replace(/\s*(\d+\.\d+分)$/, ''),
  657. type = $TiMu.find(
  658. 'input[name^=answertype]:eq(0)')
  659. .val() || '-1';
  660. GM_xmlhttpRequest(
  661. {
  662. method: queryapi[setting.api]
  663. .method,
  664. url: queryapi[setting.api]
  665. .method === "GET" ? queryapi[
  666. setting.api].url + "?" +
  667. queryapi[setting.api]
  668. .getIssueParam +
  669. encodeURIComponent(question) :
  670. queryapi[setting.api].url,
  671. headers:
  672. {
  673. 'Content-type': 'application/x-www-form-urlencoded'
  674. },
  675. data: 'course=' +
  676. encodeURIComponent(setting
  677. .curs) + '&' + queryapi[
  678. setting.api]
  679. .postIssueParam + '=' +
  680. encodeURIComponent(question) +
  681. '&type=' + type,
  682. timeout: setting.time,
  683. onload: function (xhr)
  684. {
  685. if (!setting.loop)
  686. {}
  687. else if (xhr.status ==
  688. 200)
  689. {
  690. var obj = $.parseJSON(xhr
  691. .responseText) ||
  692. {};
  693. if (obj.answer)
  694. {}
  695. else obj.answer = obj
  696. .data || obj.da;
  697. obj.code = obj.code ==
  698. null ? 1 : obj.code;
  699. if ((obj.code == 1) || (
  700. obj.code == 0) || obj
  701. .tm)
  702. {
  703. setting.div.children(
  704. 'div:eq(0)')
  705. .text('正在搜索答案...');
  706. var td =
  707. '<td style="border: 1px solid;',
  708. data = String(obj
  709. .answer)
  710. .replace(/&/g,
  711. '&amp;')
  712. .replace(/<(?!img)/g,
  713. '&lt;');
  714. obj.data = /^http/.test(
  715. data) ?
  716. '<img src="' + data +
  717. '">' : obj.answer;
  718. $(
  719. '<tr>' +
  720. td +
  721. ' text-align: center;">' +
  722. $TiMu.find(
  723. '.Zy_TItle:eq(0) i'
  724. )
  725. .text()
  726. .trim() + '</td>' +
  727. td +
  728. '" title="点击可复制">' +
  729. (question.match(
  730. '<img') ?
  731. question :
  732. question.replace(
  733. /&/g, '&amp;')
  734. .replace(/</g,
  735. '&lt')) +
  736. '</td>' +
  737. td +
  738. '" title="点击可复制">' +
  739. (/^http/.test(
  740. data) ? obj
  741. .answer : '') +
  742. data + '</td>' +
  743. '</tr>'
  744. )
  745. .appendTo(setting.div
  746. .find('tbody'))
  747. .css(
  748. 'background-color',
  749. fillAnswer($TiMu
  750. .find('ul:eq(0)')
  751. .find('li'), obj,
  752. type) ? '' :
  753. 'rgba(0, 150, 136, 0.6)'
  754. );
  755. setting.data[setting
  756. .num++] = {
  757. code: obj.code > 0 ?
  758. 1 : 0,
  759. question: question,
  760. option: obj.data,
  761. type: Number(type)
  762. };
  763. }
  764. else
  765. {
  766. setting.div.children(
  767. 'div:eq(0)')
  768. .html(obj.data ||
  769. setting.over +
  770. '服务器繁忙,正在重试...(或者切换接口)'
  771. );
  772. }
  773. obj.msg = (obj.extra ||
  774. setting.notice || '')
  775. obj.msg +=
  776. '<br/>一起完善题库吧!请在提交后重新打开题目页面,等待题目加载完成即可!';
  777. setting.div.children(
  778. 'span')
  779. .html(obj.msg);
  780. }
  781. else if (xhr.status ==
  782. 403 || xhr.status == 444
  783. )
  784. {
  785. var html = xhr
  786. .responseText.indexOf(
  787. '{') ?
  788. '请求过于频繁,建议稍后再试或尝试切换接口' :
  789. $.parseJSON(xhr
  790. .responseText)
  791. .data;
  792. setting.div.children(
  793. 'div:eq(0)')
  794. .data('html', html)
  795. .siblings(
  796. 'button:eq(0)')
  797. .click();
  798. }
  799. else
  800. {
  801. setting.div.children(
  802. 'div:eq(0)')
  803. .html(setting.over +
  804. '服务器异常,正在重试...(或者切换接口)'
  805. );
  806. }
  807. },
  808. ontimeout: function ()
  809. {
  810. setting.loop && setting.div
  811. .children('div:eq(0)')
  812. .html(setting.over +
  813. '服务器超时,正在重试...(或者切换接口)'
  814. );
  815. }
  816. });
  817. }
  818. function DisplayURL()
  819. {
  820. _self.WAY.box.hide();
  821. var $li = $(this)
  822. .closest('li');
  823. $.get('/visit/goToCourseByFace',
  824. {
  825. courseId: $li.find(
  826. 'input[name=courseId]')
  827. .val(),
  828. clazzId: $li.find(
  829. 'input[name=classId]')
  830. .val()
  831. }, function (data)
  832. {
  833. $li.find(
  834. '[onclick^=openFaceTip]')
  835. .removeAttr('onclick')
  836. .attr(
  837. {
  838. target: '_blank',
  839. href: $(data)
  840. .filter('script:last')
  841. .text()
  842. .match(/n\("(.+?)"/)[1]
  843. });
  844. alert('本课程已临时解除面部识别');
  845. }, 'html');
  846. }
  847. function getSchoolId()
  848. {
  849. var school = /^1\d{10}$/.test(setting
  850. .username) ? '' : setting.school;
  851. if (!isNaN(school)) return setTimeout(
  852. toLogin, setting.time, school);
  853. if (school == '账号为手机号可以不修改此参数')
  854. return alert('请修改school参数');
  855. $.getJSON('/org/searchUnis?filter=' +
  856. encodeURI(school) + '&product=44',
  857. function (data)
  858. {
  859. if (!data.result) return alert(
  860. '学校查询错误');
  861. var msg = $.grep(data.froms,
  862. function (value)
  863. {
  864. return value.name ==
  865. school;
  866. })[0];
  867. msg ? setTimeout(toLogin,
  868. setting.time, msg.schoolid
  869. ) : alert('学校名称不完整');
  870. });
  871. }
  872. function goCourse(url)
  873. {
  874. GM_xmlhttpRequest(
  875. {
  876. method: 'GET',
  877. url: url,
  878. onload: function (xhr)
  879. {
  880. $.globalEval(
  881. 'location.href = "' + $(
  882. '.articlename a[href]',
  883. xhr.responseText)
  884. .attr('href') + '";');
  885. }
  886. });
  887. }
  888. function filterImg(dom)
  889. {
  890. return $(dom)
  891. .clone()
  892. .find('img[src]')
  893. .replaceWith(function ()
  894. {
  895. return $('<p></p>')
  896. .text('<img src="' + $(this)
  897. .attr('src') + '">');
  898. })
  899. .end()
  900. .find('iframe[src]')
  901. .replaceWith(function ()
  902. {
  903. return $('<p></p>')
  904. .text('<iframe src="' + $(
  905. this)
  906. .attr('src') + '"></irame>'
  907. );
  908. })
  909. .end()
  910. .text()
  911. .trim();
  912. }
  913. function setMCInfo(api, auto, exdays)
  914. {
  915. var d = new Date();
  916. d.setTime(d.getTime() + (exdays * 24 *
  917. 60 * 60 * 1000));
  918. var expires = "expires=" + d
  919. .toGMTString();
  920. document.cookie = "MC_user_setting=" +
  921. JSON.stringify(
  922. {
  923. api,
  924. auto
  925. }) + "; " + expires + ";path=/;";
  926. }
  927. function getMCInfo(name)
  928. {
  929. name = name + "=";
  930. var ca = document.cookie.split(';');
  931. for (var i = 0; i < ca.length; i++)
  932. {
  933. var c = ca[i].trim();
  934. if (c.indexOf(name) == 0)
  935. {
  936. return document.cookie = c
  937. .substring(name.length, c
  938. .length);
  939. }
  940. }
  941. return "";
  942. }
  943. function checkMCInfo()
  944. {
  945. var user_setting = getMCInfo(
  946. "MC_user_setting");
  947. if (user_setting != "")
  948. {
  949. //parse json data
  950. user_setting = JSON.parse(
  951. user_setting);
  952. setting.api = user_setting.api;
  953. setting.auto = user_setting.auto;
  954. }
  955. else
  956. {
  957. setMCInfo(0, 0, 30);
  958. }
  959. }
  960. function fillAnswer($li, obj, type)
  961. {
  962. var $input = $li.find(
  963. ':radio, :checkbox'),
  964. str = String(obj.data)
  965. .toCDB() || new Date()
  966. .toString(),
  967. data = str.split(/#|\x01|\|/),
  968. opt = obj.opt || str,
  969. state = setting.lose;
  970. // $li.find(':radio:checked').prop('checked', false);
  971. obj.code > 0 && $input.each(function (
  972. index)
  973. {
  974. if (this.value == 'true')
  975. {
  976. data.join()
  977. .match(
  978. /(^|,)(正确|是|对|√|T|ri)(,|$)/
  979. ) && this.click();
  980. }
  981. else if (this.value ==
  982. 'false')
  983. {
  984. data.join()
  985. .match(
  986. /(^|,)(错误|否|错|×|F|wr)(,|$)/
  987. ) && this.click();
  988. }
  989. else
  990. {
  991. var tip = filterImg($li.eq(
  992. index)
  993. .find('.after'))
  994. .toCDB() || new Date()
  995. .toString();
  996. Boolean($.inArray(tip, data) +
  997. 1 || (type == '1' && str
  998. .indexOf(tip) + 1)) ==
  999. this.checked || this
  1000. .click();
  1001. }
  1002. })
  1003. .each(function ()
  1004. {
  1005. if (!/^A?B?C?D?E?F?G?$/.test(
  1006. opt)) return false;
  1007. Boolean(opt.match(this
  1008. .value)) == this.checked ||
  1009. this.click();
  1010. });
  1011. if (type.match(/^[013]$/))
  1012. {
  1013. $input.is(':checked') || (setting
  1014. .none ? ($input[Math.floor(Math
  1015. .random() * $input.length
  1016. )] || $())
  1017. .click() : setting.lose++);
  1018. }
  1019. else if (type.match(
  1020. /^(2|[4-9]|1[08])$/))
  1021. {
  1022. data = String(obj.data)
  1023. .split(/#|\x01|\|/);
  1024. str = $li.end()
  1025. .find('textarea')
  1026. .each(function (index)
  1027. {
  1028. index = (obj.code > 0 && data[
  1029. index]) || '';
  1030. UE.getEditor(this.name)
  1031. .setContent(index.trim());
  1032. })
  1033. .length;
  1034. (obj.code > 0 && data.length ==
  1035. str) || setting.none || setting
  1036. .lose++;
  1037. }
  1038. else
  1039. {
  1040. setting.none || setting.lose++;
  1041. }
  1042. return state == setting.lose;
  1043. }
  1044. function saveThis()
  1045. {
  1046. if (!setting.auto) return setTimeout(
  1047. saveThis, setting.time);
  1048. setting.div.children('button:lt(3)')
  1049. .hide()
  1050. .eq(1)
  1051. .click();
  1052. _self.alert = console.log;
  1053. $('#tempsave')
  1054. .click();
  1055. setting.regl();
  1056. }
  1057. function toLogin(fid)
  1058. {
  1059. GM_xmlhttpRequest(
  1060. {
  1061. method: 'GET',
  1062. url: '/api/login?name=' +
  1063. setting.username + '&pwd=' +
  1064. setting.password +
  1065. '&schoolid=' + fid +
  1066. '&verify=0',
  1067. onload: function (xhr)
  1068. {
  1069. var obj = $.parseJSON(xhr
  1070. .responseText) ||
  1071. {};
  1072. obj.result ? location.href =
  1073. decodeURIComponent($(
  1074. '#ref, #refer_0x001')
  1075. .val()) : alert(obj
  1076. .errorMsg || 'Error');
  1077. }
  1078. });
  1079. }
  1080. function submitAnswer($job, data)
  1081. {
  1082. $job.removeClass('ans-job-finished');
  1083. data = data.length ? $(data) : $(
  1084. '.TiMu')
  1085. .map(function ()
  1086. {
  1087. var title = filterImg($(
  1088. '.Zy_TItle .clearfix',
  1089. this));
  1090. return {
  1091. question: title.replace(
  1092. /^【.*?】\s*/, ''),
  1093. type: (
  1094. {
  1095. 单选题: 0,
  1096. 多选题: 1,
  1097. 填空题: 2,
  1098. 判断题: 3
  1099. })[title.match(
  1100. /^【(.*?)】|$/)[1]]
  1101. };
  1102. });
  1103. data = $.grep(data.map(function (
  1104. index)
  1105. {
  1106. var $TiMu = $('.TiMu')
  1107. .eq(index);
  1108. if (!($.isPlainObject(this) &&
  1109. this.type < 4 && $TiMu
  1110. .find('.fr')
  1111. .length))
  1112. {
  1113. return false;
  1114. }
  1115. else if (this.type == 2)
  1116. {
  1117. var $ans = $TiMu.find(
  1118. '.Py_tk, .Py_answer')
  1119. .eq(0);
  1120. if (!$TiMu.find('.cuo')
  1121. .length && this.code)
  1122. {
  1123. return false;
  1124. }
  1125. else if (!$ans.find('.cuo')
  1126. .length)
  1127. {
  1128. this.option = $ans.find(
  1129. '.clearfix')
  1130. .map(function ()
  1131. {
  1132. return $(this)
  1133. .text()
  1134. .trim();
  1135. })
  1136. .get()
  1137. .join('#') || '无';
  1138. }
  1139. else if (this.code)
  1140. {
  1141. this.code = -1;
  1142. }
  1143. else
  1144. {
  1145. return false;
  1146. }
  1147. }
  1148. else if (this.type == 3)
  1149. {
  1150. var ans = $TiMu.find(
  1151. '.font20:last')
  1152. .text();
  1153. if ($TiMu.find('.cuo')
  1154. .length)
  1155. {
  1156. this.option = (
  1157. {
  1158. '√': '错误',
  1159. '×': '正确'
  1160. })[ans] || '无';
  1161. }
  1162. else if (!this.code)
  1163. {
  1164. this.option = (
  1165. {
  1166. '√': '正确',
  1167. '×': '错误'
  1168. })[ans] || '无';
  1169. }
  1170. else
  1171. {
  1172. return false;
  1173. }
  1174. }
  1175. else
  1176. {
  1177. var text = $TiMu.find(
  1178. '.Py_answer > span:eq(0)'
  1179. )
  1180. .text();
  1181. if ($TiMu.find('.dui')
  1182. .length && this.code && !
  1183. /^A?B?C?D?E?F?G?$/.test(
  1184. this.option))
  1185. {
  1186. return false;
  1187. }
  1188. else if ($TiMu.find('.dui')
  1189. .length || text.match(
  1190. '正确答案'))
  1191. {
  1192. text = text.match(
  1193. /[A-G]/gi) || [];
  1194. this.option = $.map(text,
  1195. function (value)
  1196. {
  1197. return filterImg(
  1198. $TiMu.find(
  1199. '.fl:contains(' +
  1200. value +
  1201. ') + a'));
  1202. })
  1203. .join('#') || '无';
  1204. this.key = text.join('');
  1205. }
  1206. else if (this.code)
  1207. {
  1208. this.code = -1;
  1209. }
  1210. else
  1211. {
  1212. return false;
  1213. }
  1214. }
  1215. return this;
  1216. }), function (value)
  1217. {
  1218. return value && value.option !=
  1219. '无';
  1220. });
  1221. setting.curs = $(
  1222. 'script:contains(courseName)', top
  1223. .document)
  1224. .text()
  1225. .match(/courseName:\'(.+?)\'|$/)[
  1226. 1] || $('h1')
  1227. .text()
  1228. .trim() || '无';
  1229. $job.addClass('ans-job-finished');
  1230. }
  1231. function toNext()
  1232. {
  1233. var $cur = $('#cur' + $(
  1234. '#chapterIdid')
  1235. .val()),
  1236. $tip = $('span.currents ~ span'),
  1237. sel = setting.review ? 'html' :
  1238. '.blue';
  1239. if (!$cur.has(sel)
  1240. .length && $tip.length) return $tip
  1241. .eq(0)
  1242. .click();
  1243. $tip = $(
  1244. '.roundpointStudent, .roundpoint')
  1245. .parent();
  1246. $tip = $tip.slice($tip.index($cur) +
  1247. 1)
  1248. .not(':has(' + sel + ')');
  1249. $tip.not(setting.lock ?
  1250. ':has(.lock)' : 'html')
  1251. .find('span')
  1252. .eq(0)
  1253. .click();
  1254. $tip.length || setting.course &&
  1255. switchCourse();
  1256. }
  1257. function switchCourse()
  1258. {
  1259. GM_xmlhttpRequest(
  1260. {
  1261. method: 'GET',
  1262. url: '/visit/courses/study?isAjax=true&fileId=0&debug=',
  1263. headers:
  1264. {
  1265. 'Referer': location.origin +
  1266. '/visit/courses',
  1267. 'X-Requested-With': 'XMLHttpRequest'
  1268. },
  1269. onload: function (xhr)
  1270. {
  1271. var list = $('h3 a[target]',
  1272. xhr.responseText)
  1273. .map(function ()
  1274. {
  1275. return $(this)
  1276. .attr('href');
  1277. }),
  1278. index = list.map(
  1279. function (index)
  1280. {
  1281. return this.match(top
  1282. .courseId) &&
  1283. index;
  1284. })
  1285. .filter(function ()
  1286. {
  1287. return $.isNumeric(
  1288. this);
  1289. })[0] + 1 || 0;
  1290. setting.course = list[
  1291. index] ? goCourse(list[
  1292. index]) : 0;
  1293. }
  1294. });
  1295. }
  1296. function hookVideo()
  1297. {
  1298. _self.alert = console.log;
  1299. var config = arguments[1],
  1300. line = Ext.Array.filter(Ext.Array
  1301. .map(config.playlines, function (
  1302. value, index)
  1303. {
  1304. return value.label == setting
  1305. .line && index;
  1306. }),
  1307. function (value)
  1308. {
  1309. return Ext.isNumber(value);
  1310. })[0] || 0,
  1311. http = Ext.Array.filter(config
  1312. .sources,
  1313. function (value)
  1314. {
  1315. return value.label == setting
  1316. .http;
  1317. })[0];
  1318. config.playlines.unshift(config
  1319. .playlines[line]);
  1320. config.playlines.splice(line + 1, 1);
  1321. config.plugins
  1322. .videoJsResolutionSwitcher.default =
  1323. http ? http.res : 360;
  1324. config.plugins.studyControl
  1325. .enableSwitchWindow = 1;
  1326. config.plugins.timelineObjects.url =
  1327. '/richvideo/initdatawithviewer?';
  1328. config.plugins.seekBarControl
  1329. .enableFastForward = 1;
  1330. if (!setting.queue) delete config
  1331. .plugins.studyControl;
  1332. // config.preload = setting.tip ? 'auto' : 'none';
  1333. var player = vjs.apply(this,
  1334. arguments),
  1335. a =
  1336. '<a href="https://d0.ananas.chaoxing.com/download/' +
  1337. _self.config('objectid') +
  1338. '" target="_blank">',
  1339. img =
  1340. '<img src="https://d0.ananas.chaoxing.com/download/e363b256c0e9bc5bd8266bf99dd6d6bb" style="margin: 6px 0 0 6px;">';
  1341. player.volume(Math.round(setting
  1342. .vol) / 100 || 0);
  1343. Ext.get(player.controlBar.addChild(
  1344. 'Button')
  1345. .el_)
  1346. .setHTML(a + img + '</a>')
  1347. .dom.title = '下载视频';
  1348. player.on('loadstart', function ()
  1349. {
  1350. setting.tip && this.play()
  1351. .catch(Ext.emptyFn);
  1352. this.playbackRate(setting.rate >
  1353. 16 || setting.rate <
  1354. 0.0625 ? 1 : setting.rate);
  1355. });
  1356. player.one(['loadedmetadata',
  1357. 'firstplay'
  1358. ], function ()
  1359. {
  1360. setting.two = setting.rate ===
  1361. '0' && setting.two < 1;
  1362. setting.two && config.plugins
  1363. .seekBarControl.sendLog(this
  1364. .children_[0], 'ended', Math
  1365. .floor(this.cache_.duration)
  1366. );
  1367. });
  1368. player.on('ended', function ()
  1369. {
  1370. Ext.fly(frameElement)
  1371. .parent()
  1372. .addCls('ans-job-finished');
  1373. });
  1374. return player;
  1375. }
  1376. function autoRead()
  1377. {
  1378. $('html, body')
  1379. .animate(
  1380. {
  1381. scrollTop: $(document)
  1382. .height() - $(window)
  1383. .height()
  1384. }, Math.round(setting.read) * 1E3,
  1385. function ()
  1386. {
  1387. $('.nodeItem.r i')
  1388. .click();
  1389. })
  1390. .one('click', '#top', function (
  1391. event)
  1392. {
  1393. $(event.delegateTarget)
  1394. .stop();
  1395. });
  1396. }
  1397. function submitThis()
  1398. {
  1399. if (!setting.auto)
  1400. {}
  1401. else if (!$('.Btn_blue_1:visible')
  1402. .length)
  1403. {
  1404. setting.div.children('button:lt(3)')
  1405. .hide()
  1406. .eq(1)
  1407. .click();
  1408. return setting.regl();
  1409. }
  1410. else if ($('#confirmSubWin:visible')
  1411. .length)
  1412. {
  1413. var btn = $('#tipContent + * > a')
  1414. .offset() ||
  1415. {
  1416. top: 0,
  1417. left: 0
  1418. },
  1419. mouse = document.createEvent(
  1420. 'MouseEvents');
  1421. btn = [btn.left + Math.ceil(Math
  1422. .random() * 46), btn.top +
  1423. Math.ceil(Math.random() * 26)
  1424. ];
  1425. mouse.initMouseEvent('click', true,
  1426. true, document.defaultView, 0,
  1427. 0, 0, btn[0], btn[1], false,
  1428. false, false, false, 0, null);
  1429. _self.event = $.extend(true,
  1430. {},
  1431. mouse);
  1432. delete _self.event.isTrusted;
  1433. _self.form1submit();
  1434. }
  1435. else
  1436. {
  1437. $('.Btn_blue_1')[0].click();
  1438. }
  1439. setTimeout(submitThis, Math.ceil(
  1440. setting.time * Math.random()) *
  1441. 2);
  1442. }
  1443. function checkToNext()
  1444. {
  1445. var $tip = $(setting.job.join(', '),
  1446. document)
  1447. .prevAll('.ans-job-icon' + setting
  1448. .normal);
  1449. setInterval(function ()
  1450. {
  1451. $tip.parent(
  1452. ':not(.ans-job-finished)')
  1453. .length || setting.jump &&
  1454. toNext();
  1455. }, setting.time);
  1456. }