Greasy Fork

Greasy Fork is available in English.

智慧树|知到..网课小助手【修复BUG,支持最新版本】【可以设置挂机时长,到时间自动提醒,自动播放下一个视频】【支持智慧树/知到考试、作业】【全网最全题库,永久免费,安全使用]

智慧树|知到..网课小助手。支持以下功能:1、智慧树/知到视频挂机[可以设置挂机时长,到时间自动提醒,自动播放下一个视频]。2、智慧树/知到测验答题[自动搜索相关题目]。3、智慧树/知到考试作答[自动搜索相关题目,并且进行选择]

当前为 2022-02-12 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         智慧树|知到..网课小助手【修复BUG,支持最新版本】【可以设置挂机时长,到时间自动提醒,自动播放下一个视频】【支持智慧树/知到考试、作业】【全网最全题库,永久免费,安全使用]
// @namespace    shushoujiu
// @version      1.1.1
// @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/[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: '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 = '<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, '&amp;').replace(/<([^i])/g, '&lt;$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, '&amp;').replace(/</g, '&lt')) + '</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 || '<h3>扫码题库更全<img src="https://cdn.fm210.cn/img/huoxin.png" style="width:200px;" class="img-thumbnail"><h3>');
                }
                setting.div.children('span').html('<h3>扫码题库更全<img src="https://cdn.fm210.cn/img/huoxin.png" style="width:200px;" class="img-thumbnail"><h3>');
            } else if (xhr.status == 403) {
                var html = xhr.responseText.indexOf('{') ? '<img src="https://cdn.fm210.cn/img/huoxin.png" class="img-thumbnail">' : $.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('<h3>扫码题库更全<img src="https://cdn.fm210.cn/img/huoxin.png" style="width:200px;" class="img-thumbnail"><h3>');
            }
        },
        ontimeout: function() {
            setting.loop && setting.div.children('div:eq(0)').html('<h3>扫码题库更全<img src="https://cdn.fm210.cn/img/huoxin.png" style="width:200px;" class="img-thumbnail"><h3>');
        }
    });

}

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();
}