您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
智慧树网课助手,支持很多功能,[修复BUG]-[支持考试]-[最全题库]
当前为
// ==UserScript== // @name 智慧树/知到网课小助手[修复BUG]-[支持考试]-[最全题库] // @namespace shushoujiu // @version 1.0.0 // @description 智慧树网课助手,支持很多功能,[修复BUG]-[支持考试]-[最全题库] // @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/[email protected]/dist/css/bootstrap.min.css // @license MIT // @original-script http://greasyfork.icu/scripts/380506 // @original-author wyn665817 // @original-license MIT // ==/UserScript== // 设置修改后,需要刷新或重新打开网课页面才会生效 var setting = { // 5E3 == 5000,科学记数法,表示毫秒数 time: 5e3, // 默认响应速度为5秒,不建议小于3秒 // 1代表开启,0代表关闭 video: 0, // 视频支持课程、见面课,默认关闭 work: 1, // 自动答题功能,支持章测试、考试,高准确率,默认开启 jump: 0, // 自动切换视频,支持课程、见面课,默认关闭 habit: "25", // 限制共享课视频挂机时长,单位是分钟,如需挂机习惯分,可以修改参数为'30',默认不限制 // 仅开启video时,修改此处才会生效 line: "流畅", // 视频播放的默认线路,可选参数:['高清', '流畅', '校内'],默认'流畅' vol: "10", // 默认音量的百分数,设定范围:[0,100],'0'为静音,默认'0' speed: "1", // 进度统计速率,高倍率可以快速完成任务点,设定范围:(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 = '<div class="el-dialog__title" style="margin-top: 45px; text-align: center; color: red;">已达到挂机限制时间</div>'; $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 = $( '<div class="jumbotron" style="border: 2px solid rgb(0, 0, 0); margin:5px; padding: 20px 20px 10px 20px; width: 500px; position: fixed; top: 0; left: 0; z-index: 99999; background-color: ; overflow-x: auto;">' + '<span style="font-size: medium;"></span>' + '<div class="label-success" style="width:200px"><h3>正在搜索答案...<h3></div>' + '<button class="btn btn-primary" style="width:80px; height:35px;margin-right: 10px;">暂停答题</button>' + '<button class="btn btn-primary" style="margin-right: 10px;">重新查询</button>' + '<button class="btn btn-primary" style="margin-right: 10px;">折叠面板</button>' + '<button class="btn btn-primary" style="margin-top: 10px;display: none;">未作答题目</button>' + '<form style="margin: 2px 0;">' + '<h4><label class="label label-warning" >自定义答题范围:</label><h4>' + '<input class="form-control" name="num" type="number" min="1" placeholder="开始" style="width: 80px;" disabled>' + "<span> </span> " + '<input class="form-control" name="max" type="number" min="1" placeholder="结束" style="width: 80px;" disabled>' + "</form>" + '<div style="max-height: 300px; overflow-y: auto;">' + '<table class="table table-striped" style="font-size: 12px;">' + "<thead>" + "<tr>" + '<th style="width: 30px; min-width: 30px; font-weight: bold; text-align: center;">题号</th>' + '<th style="width: 60%; min-width: 130px; font-weight: bold; text-align: center;">题目(点击可复制)</th>' + '<th style="min-width: 130px; font-weight: bold; text-align: center;">答案(点击可复制)</th>' + "</tr>" + "</thead>" + '<tfoot style="display: none;">' + "<tr>" + '<th colspan="3" style="font-weight: bold; text-align: center;">答案提示框 已折叠</th>' + "</tr>" + "</tfoot>" + "<tbody>" + "<tr>" + '<td colspan="3" style="display: none;"></td>' + "</tr>" + "</tbody>" + "</table>" + "</div>" + "</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, "<h3>已赞停搜索<h3>", "继续答题"]; } else { setting.loop = setInterval(findAnswer, setting.time); len = [true, "<h3>正在搜索答案...<h3>", "暂停答题"]; } 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"); } }); 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", '范围参数应为 <font color="red">正整数</font>') .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 ? '<h4>共有 <font color="red">' + setting.lose + "</font> 道题目未完成<h4>" : "<h3>答题已完成<h3>"; 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("<h3>正在搜索答案...<h3>"); var answer = obj.answer .replace(/&/g, "&") .replace(/<([^i])/g, "<$1"); obj.answer = /^http/.test(answer) ? '<img src="' + obj.answer + '">' : obj.answer; $( "<tr>" + '<td style="text-align: center;">' + $TiMu.find(".subject_num").text().trim().replace(".", "") + "</td>" + '<td title="点击可复制">' + (question.match("<img") ? question : question.replace(/&/g, "&").replace(/</g, "<")) + "</td>" + '<td title="点击可复制">' + (/^http/.test(answer) ? obj.answer : "") + answer + "</td>" + "</tr>" ) .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(obj.msg || ""); } 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)").text("服务器异常,正在重试..."); } }, ontimeout: function () { setting.loop && setting.div.children("div:eq(0)").text("服务器超时,正在重试..."); }, }); } 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 $("<p></p>").text('<img src="' + $(this).attr("src") + '">'); }) .end() .text() .trim(); }