// ==UserScript== // @name 🌳🌳智慧树|知到网课小助手【支持最新版本】【2022年更新】【可以设置挂机时长,到时间自动提醒,自动播放下一个视频】【支持智慧树/知到考试、作业】【全网最全题库,永久免费,安全使用] // @namespace shushoujiu // @version 2.0.0 // @description 🌳🌳智慧树|知到网课小助手。支持以下功能:1、智慧树/知到视频挂机[可以设置挂机时长,到时间自动提醒,自动播放下一个视频]。2、智慧树/知到测验答题[自动搜索相关题目]。3、智慧树/知到考试作答[自动搜索相关题目,并且进行选择] // @author shushoujiu // @match *://*.zhihuishu.com/* // @connect cx.icodef.com // @run-at document-end // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_setClipboard // @grant GM_setValue // @resource css https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css // @license MIT // @original-script https://greasyfork.org/scripts/380506 // @original-author wyn665817 // @original-license MIT // @downloadURL none // ==/UserScript== // 设置修改后,需要刷新或重新打开网课页面才会生效 var setting = { // 5E3 == 5000,科学记数法,表示毫秒数 time: 5E3 // 默认响应速度为5秒,不建议小于3秒 // 1代表开启,0代表关闭 ,video: 0 // 视频支持课程、见面课,默认关闭 ,work: 1 // 自动答题功能,支持章测试、考试,高准确率,默认开启 ,jump: 0 // 自动切换视频,支持课程、见面课,默认关闭 ,habit: '0' // 限制共享课视频挂机时长,单位是分钟,如需挂机习惯分,可以修改参数为'30',默认不限制 // 仅开启video时,修改此处才会生效 ,line: '流畅' // 视频播放的默认线路,可选参数:['高清', '流畅', '校内'],默认'流畅' ,vol: '0' // 默认音量的百分数,设定范围:[0,100],'0'为静音,默认'0' ,speed: '1.5' // 进度统计速率,高倍率可以快速完成任务点,设定范围:(0,+∞),默认'1.5'倍 // 上方参数支持在页面改动,下方参数仅支持代码处修改 ,que: 0 // 屏蔽视频时间点对应的节试题,取消屏蔽则自动切换为模拟点击关闭弹题,默认关闭 ,danmu: 0 // 见面课弹幕,关闭后在网页中无法手动开启,默认关闭 // 仅开启work时,修改此处才会生效 ,none: 0 // 无匹配答案时执行默认操作,默认关闭 ,hide: 0 // 不加载答案搜索提示框,键盘↑和↓可以临时移除和加载,默认关闭 ,api: [{'url':'http://cx.icodef.com/wyn-nb?v=3','method':'POST'}] }, _self = unsafeWindow, url = location.pathname, $ = _self.jQuery, vjsC = _self.vjsComponent; GM_addStyle(GM_getResourceText("css")); 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.time += Math.ceil(setting.time * Math.random()) - setting.time / 2; setting.queue = setting.curs = []; if (!$) { } else if (url == '/live/vod_room.html') { courseFn(0); } else if (url == '/videoStudy.html') { var xhr = _self.XMLHttpRequest.prototype; courseFn(1, xhr.open, setting.habit * 6E4); } else if (url == '/portals_h5/2clearning.html') { courseFn(2); } else if (url.match('/sourceLearning')) { courseFn(3); } else if (location.hostname.match('examh5')) { setTimeout(relieveLimit, 100, document); if (location.hash.match(/dohomework|doexamination/) && setting.work) beforeFind(); $(window).on('hashchange', function() { setting.work && location.reload(); }); } else if (url == '/shareCourse/questionDetailPage') { setTimeout(relieveLimit, 100, document); $('textarea[oncut]').each(function() { setTimeout(relieveLimit, 100, this); }); } function courseFn(tip, open, habit) { setting.jump && setInterval(checkToNext, setting.time); habit && setTimeout(totalTime, setting.time, habit); if (!setting.video) return; // _self.PlayerUtil.debugMode = true; setting.tip = tip; _self.vjsComponent = vjsComponent; $(document).on('click', '.definiLines b', function() { setting.line = ({xiaonei: '校内', line1gq: '高清', line1bq: '流畅'})[this.classList[0]]; }).on('mouseup click', function() { if (!_self.PlayerStarter.playerArray[0]) return; setting.vol = _self.PlayerStarter.playerArray[0].player.cache_.volume * 100; }).on('click', '.speedList div', function() { setting.speed = $(this).attr('rate'); }); if (setting.tip != 1) return; setting.que ? xhr.open = function(type, url, async) { if (url.match('/loadVideoPointerInfo')) type = 'GET'; return open.call(this, type, url, async); } : setInterval(doTest, 1E3); } function vjsComponent(obj) { var options = obj.options, line = $.map(options.sourceSrc.lines, function(value) { return value.lineName.replace('标准', '高清'); }), vol = setting.vol > 100 ? 100 : Math.round(setting.vol); options.volume = vol > 0 ? vol / 100 : 0; options.autostart = true; setting.speed = setting.speed > 0 ? +setting.speed : 1; options.rate = $.inArray(setting.speed, [1, 1.25, 1.5]) < 0 ? options.rate : setting.speed; setting.tip && obj.callback.playbackRate(setting.speed); options.chooseLine = $.inArray(setting.line, line) + 1 || options.chooseLine + 1; options.src = options.sourceSrc.lines[--options.chooseLine].lineUrl || options.src; if (!setting.danmu) { obj.defOptions.control.danmuBtn = false; delete options.control.danmuBtn; } obj.player.on('loadstart', function() { this.loop(true); this.play(); $('.speedBox span').text('X ' + setting.speed); }); vjsC.call(this, obj); } function totalTime(habit) { var obj = _self.PlayerStarter.playerArray[0]; if (obj) habit -= obj.player.paused() ? 0 : setting.time; if (habit >= 0) return setTimeout(totalTime, setting.time, habit); obj.player.pause(); var $tips = $('.dialog-tips').eq(0).clone().css('z-index', 3000).appendTo('.video-study').show(), html = '
已达到挂机限制时间
'; $tips.find('.el-dialog__title').text('智慧树网课助手提示').next().remove(); $tips.find('.el-dialog__footer').before(html).find('button').click(function() { $tips.remove(); }).find('span').text('明白了'); } function checkToNext() { if (setting.habit < 0) return; var $tip = $('.video, .lessonItem, .file-item'); if ($('.current_play .time_icofinish').length) { $tip.slice($tip.index($('.current_play')) + 1).not(':has(.time_icofinish)').eq(0).click(); } else if ($('.lessonItemActive .finish').length) { // _self.PlayerStarter.playerArray[0].callback.playerNext(); $tip.slice($tip.index($('.lessonItemActive')) + 1).not(':has(.finish)').eq(0).click(); } else if (url.match('vod_room')) { $('.current_player:contains("100%") + li').click(); // $('.finish_tishi').hasClass('disNo') || console.log('签到已完成'); } else if ($('.active .icon-finish').length) { $tip.slice($tip.index($('.active')) + 1).not(':has(.icon-finish)').eq(0).click(); } } function doTest() { if (!$('.dialog-test').length) { } else if (setting.queue.length) { $(setting.queue.shift()).parent().click(); } else if (!$('.item-topic.active').length) { $('.topic-item').eq(0).click(); } else if ($('.error').length) { var tip = $('.answer span').text().match(/[A-Z]/g) || []; if (tip.length == 1) return $('.topic-option-item:contains(' + tip[0] + ')').click(); $('.topic-option-item').each(function() { $.inArray($(this).text().slice(0, 1), tip) < 0 == $(this).hasClass('active') && setting.queue.push(this); }); } else if ($('.btn-next:enabled').length) { $('.btn-next:enabled').click(); } else { $('.dialog-test .btn').click(); _self.PlayerStarter.playerArray[0].player.play(); } } function relieveLimit(doc) { if (!doc.oncut && !doc.onselectstart) return setTimeout(relieveLimit, 100, doc); doc.oncontextmenu = doc.onpaste = doc.oncopy = doc.oncut = doc.onselectstart = null; } function beforeFind() { setting.div = $( '
' + '' + '

正在搜索答案...

' + '' + '' + '' + '' + '
' + '

' + '' + '   ' + '' + '' + '
' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
题号题目(点击可复制)答案(点击可复制)
答案提示框 已折叠
' + '
' + '

' ).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 (len === 0) { if (setting.loop) { clearInterval(setting.loop); delete setting.loop; len = [false, '

已赞停搜索

', '继续答题']; } else { setting.loop = setInterval(findAnswer, setting.time); len = [true, '

正在搜索答案...

', '暂停答题']; } setting.div.find('input').attr('disabled', len[0]); setting.div.children('div:eq(0)').html(function() { return $(this).data('html') || len[1]; }).removeData('html'); $(this).html(len[2]); } else if (len == 1) { location.reload(); } else if (len == 2) { setting.div.find('tbody, tfoot').toggle(); } else if (len == 3) { var $li = $('.el-scrollbar__wrap li'), $tip = $li.filter('.white, .yellow').eq(0); $tip.click().length ? setting.div.children('div:last').scrollTop(function() { var $tr = $('tbody tr', this).has('td:nth-child(1):contains(' + $tip.text() + ')'); if (!$tr.length) return arguments[1]; return $tr.offset().top - $tr.parents('table').offset().top; // $tr[0].offsetTop }) : $(this).hide(); } }).on('change', 'input', function() { setting[this.name] = this.value.match(/^\d+$/) ? parseInt(this.value) - 1 : -1; if (!this.value) setting[this.name] = this.name == 'num' ? 0 : undefined; }).detach(setting.hide ? '*' : 'html'); setting.type = { 单选题: 1, 多选题: 2, 填空题: 3, 问答题: 4, '分析题/解答题/计算题/证明题': 5, '阅读理解(选择)/完型填空': 9, 判断题: 14 }; setting.lose = setting.num = setting.small = 0; $(document).keydown(function(event) { if (event.keyCode == 38) { setting.div.detach(); } else if (event.keyCode == 40) { setting.div.appendTo('body'); } }); // 作业考试文本破解 unsafeWindow.Element.prototype.attachShadow = undefined; setting.loop = setInterval(findAnswer, setting.time, true); setInterval(function() { $(setting.queue.shift()).parent().click(); }, 1E3); } function findAnswer(tip) { if (setting.queue.length) { return; } else if (tip && !$('.answerCard').length) { return setting.div.children('div:eq(0)').data('html', '非自动答题页面').siblings('button:eq(0)').click(); } else if (setting.max < 0 || setting.num < 0) { return setting.div.children('div:eq(0)').data('html', '范围参数应为 正整数').siblings('button:eq(0)').click(); } else if (setting.num >= $('.subject_stem').length || setting.num > setting.max) { // setting.div.children('button:eq(3)').toggle(!!setting.lose); tip = setting.lose ? '

共有 ' + setting.lose + ' 道题目未完成

' : '

答题已完成

'; return setting.div.children('div:eq(0)').data('html', tip).siblings('button:eq(0), form').hide().click(); } else if (!setting.curs.length) { setting.curs = $('.infoList span').map(function() { return $(this).text().trim(); }); if (!setting.curs.length) return; } var $TiMu = $('.subject_stem').eq(setting.num).parent(), $dom = $TiMu.find('.smallStem_describe').eq(setting.small).children('div').slice(1, -1), question = filterStyle($dom) || filterStyle($TiMu.find('.subject_describe')), type = $TiMu.find('.subject_type').text().match(/【(.+)】|$/)[1]; type = type ? setting.type[type] || 0 : -1; GM_xmlhttpRequest({ method: setting.api[0].method, url: setting.api[0].url, headers: { 'Content-type': 'application/x-www-form-urlencoded' }, data: 'question=' + encodeURIComponent(question), timeout: setting.time, onload: function(xhr) { if (!setting.loop) { } else if (xhr.status == 200) { var obj = $.parseJSON(xhr.responseText.replace(/^操作数据失败!/,'')) || {}; obj.answer = obj.data; if (obj.code) { setting.div.children('div:eq(0)').html('

正在搜索答案...

'); var answer = obj.answer.replace(/&/g, '&').replace(/<([^i])/g, '<$1'); obj.answer = /^http/.test(answer) ? '' : obj.answer; $( '' + '' + $TiMu.find('.subject_num').text().trim().replace('.', '') + '' + '' + (question.match('' + '' + (/^http/.test(answer) ? obj.answer : '') + answer + '' + '' ).appendTo(setting.div.find('tbody')).css('background-color', function() { $dom = $dom.length ? $dom.closest('.examPaper_subject') : $TiMu; if (fillAnswer($dom, obj, type)) return ''; setting.div.children('button:eq(3)').show(); return 'rgba(0, 150, 136, 0.6)'; }); setting.small = ++setting.small < $TiMu.find('.smallStem_describe').length ? setting.small : (setting.num++, 0); } else { setting.div.children('div:eq(0)').html(obj.answer || '

扫码题库更全

'); } setting.div.children('span').html('

扫码题库更全

'); } else if (xhr.status == 403) { var html = xhr.responseText.indexOf('{') ? '' : $.parseJSON(xhr.responseText).answer; setting.div.children('div:eq(0)').data('html', html).siblings('button:eq(0)').click(); } else { setting.div.children('div:eq(0)').html('

扫码题库更全

'); } }, ontimeout: function() { setting.loop && setting.div.children('div:eq(0)').html('

扫码题库更全

'); } }); } function fillAnswer($TiMu, obj, type) { var $div = $TiMu.find('.nodeLab'), str = String(obj.data).toCDB() || new Date().toString(), data = str.split(/#|\x01|\|/), state = setting.lose; // $div.find(':radio:checked').prop('checked', false); obj.code > 0 && $div.each(function() { var $input = $('input', this)[0], tip = filterStyle('.node_detail', this).toCDB() || new Date().toString(); if (tip.match(/^(正确|是|对|√|T|ri)$/)) { data.join().match(/(^|,)(正确|是|对|√|T|ri|right|true)(,|$)/) && setting.queue.push($input); } else if (tip.match(/^(错误|否|错|×|F|wr)$/)) { data.join().match(/(^|,)(错误|否|错|×|F|wr|wrong|false)(,|$)/) && setting.queue.push($input); } else if (type == 2) { Boolean($.inArray(tip, data) + 1 || str.indexOf(tip) + 1) == $input.checked || setting.queue.push($input); } else { $.inArray(tip, data) + 1 && setting.queue.push($input); } }); if (setting.queue.length) { } else if (/^(1|2|14)$/.test(type)) { var $input = $div.find('input'); $input.is(':checked') || (setting.none ? setting.queue.push($input[Math.floor(Math.random() * $input.length)]) : setting.lose++); } else if (/^[3-5]$/.test(type)) { data = String(obj.data).split(/#|\x01|\|/); str = $TiMu.find('textarea').each(function(index) { index = (obj.code > 0 && data[index]) || this.value || ''; this.value = index.trim(); // if (this.value == this._value) return true; this.dispatchEvent(new Event('input')); this.dispatchEvent(new Event('blur')); }).length; (obj.code > 0 && data.length == str) || setting.none || setting.lose++; } else { setting.none || setting.lose++; } return state == setting.lose; } function filterStyle(dom, that) { var $dom = $(dom, that).clone().find('style').remove().end(); return $dom.find('img[src]').replaceWith(function() { return $('

').text(''); }).end().text().trim(); }