Greasy Fork

Greasy Fork is available in English.

🥇优学院小助手(2022/09/30更新)|视频-章节测试-作业考试查题(三合一)|自动挂机|答题收录

优学院小助手,用于课件视频+课后作业+考试界面辅助答题(非自动答题)。

当前为 2022-09-30 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         🥇优学院小助手(2022/09/30更新)|视频-章节测试-作业考试查题(三合一)|自动挂机|答题收录
// @namespace    http://tampermonkey.net/
// @version      1.1.5
// @description  优学院小助手,用于课件视频+课后作业+考试界面辅助答题(非自动答题)。
// @author       Miss.
// @match        https://utest.ulearning.cn/*
// @match        https://*.ulearning.cn/*/homework.do*
// @match        https://ua.ulearning.cn/learnCourse/learnCourse.html?*
// @grant        unsafeWindow
// @grant        GM_setClipboard
// @grant        GM_xmlhttpRequest
// @run-at       document-end
// @connect      fm90.cn
// ==/UserScript==

(function () {
    "use strict";
    //属性
    const set = {
    get_answer: "http://fm90.cn/fuck/cha1.php",
    upload_data: "http://fm90.cn/fuck/upload.php",
    heartbeat: "http://fm90.cn/fuck/server.php",
    Dealagging: false,
    left: 0,
    top: 0,
    uid: -1, //后期加入
    token: null, //后期加入
    timestamp: -1,
};
    //工具包
    const Util = {
        post_form: function (url, data, onload, onerror) {
            Util.post(url, data, onload, onerror, { "Content-Type": "application/x-www-form-urlencoded" });
        },
        post: function (url, data, onload, onerror, headers) {
            let data_form = new Deal();
            for (let value in data) {
                data_form.append(value, data[value]);
            }
            GM_xmlhttpRequest({
                method: "POST",
                url: url,
                headers: headers,
                data: data_form.text,
                onload: onload,
                onerror: onerror,
            });
        },
        get: function (url, data, onload, onerror) {
            let data_form = new Deal();
            for (let value in data) {
                data_form.append(value, data[value]);
            }
            GM_xmlhttpRequest({
                method: "GET",
                url: url + "?" + data_form.text,
                onload: onload,
                onerror: onerror,
            });
        },
        upload_api: function (data, send) {
            if (set.token == -1) {
                setTimeout(Util.upload_api, 1000, data, true);
                if (send === true) {
                    return;
                }
            }
            Util.post_form(set.upload_data, {
                token: "" + set.token,
                data: JSON.stringify(data),
            });
        },
        upload_paper: function (paper, pid, eid) {
            Util.upload_api({ op: 4,eid: eid, pid: pid, paper: paper });
        },
        upload_answer: function (answer, pid, eid) {
            Util.upload_api({ op: 5,eid: eid, pid: pid, answer: answer });
        },
        upload_title: function (title, quetype, quetxt) {
            Util.upload_api({ op: 6, type: quetype, title: title ,cont: quetxt });
        },
        get_answer: function (question, quetype, td) {
            Util.get(set.get_answer, { question: question,type: quetype }, function (xhr) {
                if (xhr.status == 200) {
                    try {
                        let data = JSON.parse(xhr.responseText);
                        if (data.code == 1) {
                            td.innerText = data.data[0].answer;
                            td.addEventListener("click", function () {
                                GM_setClipboard(data.answer);
                            });
                            return;
                        }
                        else if (data.code == 0) {
                            td.innerText = "无答案(已回传服务器)";
                            return 0;
                        }
                    }
                    catch (e) { }
                }
                td.innerText = "服务器错误";
            }, function () {
                td.innerText = "服务器错误";
            });
        },
    };
    // 优学院
    const youxueyuan = {
        $startBtn: null,  // 开始按钮
        $stopBtn: null,   // 暂停按钮
        $rateText: null, //倍速
        timer: null,      // 定时器

        // 初始化
        init() {
            this.$startBtn = $('<td class="td_width td_center"><button style="background-color: #84f584; border-radius: 10px;">开始视频</button></td>');
            
            this.$stopBtn = $('<td class="td_width td_center"><button style="background-color: #84f584; border-radius: 10px;">暂停视频</button></td>');
            
            this.$rateText = $('<td class="td_width td_center" style="display:table-cell;width: 50px;">倍速:<input id="rate" type="text" value="6.00" style="width: 58px;"></td>');
            
            let $erviceMask = $('<tr></tr>');
            $('#get_answer').parent().parent().parent().append($erviceMask);
            $erviceMask.append(this.$startBtn).append(this.$stopBtn).append(this.$rateText);
            $('#hide_show').click();
            $('#get_answer').hide();
            $('#hide_show').hide();
            this.$stopBtn.hide();
            this.bindEvent();
            // 初始化日志管理器
            log.init();
        },

        // 绑定事件
        bindEvent() {
            this.$startBtn.click(() => {
                this.logic();
                this.timer = setInterval(() => { this.logic() }, 1500);
                this.$startBtn.hide();
                this.$stopBtn.show();
            });
            this.$stopBtn.click(() => {
                clearInterval(this.timer);
                this.$stopBtn.hide();
                this.$startBtn.show();
                // 暂停视频播放
                if ($(".file-media").length > 0) {
                    let $allVideos = $(".file-media");
                    for (let i = 0; i < $allVideos.length; i++) {
                        if ($('.mejs__button.mejs__playpause-button button').eq(i).attr('title') == '暂停') {
                            $('.mejs__button.mejs__playpause-button button')[i].click();
                            $('.mejs__button.mejs__volume-button button')[i].click();
                        }
                    }
                }
                // 显示日志
                log.showLogs();
            })
        },

        // 视频主逻辑
        logic() {
            // 如果页面中弹出了框框
            if ($('.modal.fade.in').length > 0) {
                switch ($('.modal.fade.in').attr('id')) {
                    case 'statModal': {
                        $("#statModal .btn-hollow").eq(-1).click();
                        break;
                    }
                    case 'alertModal': {
                        if ($("#alertModal .btn-hollow").length > 0) {
                            $("#alertModal .btn-hollow").eq(-1).click();
                        }
                        else {
                            $("#alertModal .btn-submit").click();
                        }
                        break;
                    }
                    default: {
                        log.addLog('出现了未知对话框');
                    }
                }
                return;
            }

            // 如果页面中有视频
            if ($(".file-media").length > 0) {
                let $allVideos = $(".file-media");
                let i = 0;
                for (; i < $allVideos.length; i++) {
                    // 这个视频还没有看完并且不是播放状态
                    if (!$("[data-bind='text: $root.i18nMessageText().finished']").get(i)) {
                        let _rate = document.getElementById("rate").value;
                        // 视频不是播放状态
                        if ($('.mejs__button.mejs__playpause-button button').eq(i).attr('title') == '播放') {
                            $(".mejs__speed-selector-input")[i * 4].value = parseFloat(_rate);
                            $(".mejs__speed-selector-input")[i * 4].click();
                            $('.mejs__button.mejs__speed-button button')[i].innerText = _rate+'x';
                            $('.mejs__button.mejs__playpause-button button')[i].click();
                            $('.mejs__button.mejs__volume-button button')[i].click();
                        }
                        break;
                    }
                }
                if (i == $allVideos.length) {
                    $('.next-page-btn.cursor').click();
                }
                return;
            }

            // 如果是做题界面
            if ($('.question-setting-panel').length > 0) {

                // 修正当前状态
                let $submitBtn = $('.question-operation-area button').eq(0);
                if ($submitBtn.text() == '重做') {
                    $submitBtn.click();
                    return;
                }

                // 获取当前页面 ID
                let parentId = $('.page-name.active').parent().attr('id').substring(4);

                // 开始同步答题
                let $questions = $('.question-element-node');
                for (let i = 0; i < $questions.length; i++) {
                    respondent._answer(parentId, $questions.eq(i));
                }

                // 提交答案
                $submitBtn.click();
                setTimeout(() => {
                    $('.next-page-btn.cursor').click();
                }, 300);
                sleep
                return;
            }

            // 下一页
            $('.next-page-btn.cursor').click();
        },
    }

    // 答题器
    const respondent = {
        parentId: null,      // 页面ID
        questionId: null,    // 当前解答问题的ID
        $questionNode: null, // 当前解答问题的根节点

        // 回答问题
        // @param parentId     页面ID
        // @param questionNode 问题根节点
        _answer(parentId, $questionNode, callback) {
            this.parentId = parentId;
            this.$questionNode = $questionNode;
            this.questionId = this.$questionNode.find('.question-wrapper').attr('id').substring(8);
            let questionType = $questionNode.find('.question-type-tag').text().trim();
            switch (questionType) {
                case '多选题': {
                    this._answerMultiSelect();
                    break;
                }
                case '单选题': {
                    this._answerSelect();
                    break;
                }
                case '判断题': {
                    this._answerJudge();
                    break;
                }
                case '填空题': {
                    this._answerInput();
                    break;
                }
                case '简答题': {
                    this._answerSimpleQuestion();
                    break;
                }
                case '综合题': {
                    break;
                }
                default: {
                    log.addLog('出现了未知题型');
                }
            }
            if (callback && typeof callback == 'function') callback();
        },

        // 解答多选题
        _answerMultiSelect() {
            // 多选题需要清空当前答案
            let $selected = this.$questionNode.find('.checkbox.selected');
            for (let i = 0; i < $selected.length; i++) {
                $selected.eq(i).click();
            }
            // 获取答案并选择
            let $emptySelected = this.$questionNode.find('.checkbox');
            let answerArray = this._syncGetAnswer().correctAnswerList;
            for (let i = 0; i < answerArray.length; i++) {
                let index = answerArray[i].charCodeAt() - 'A'.charCodeAt();
                $emptySelected.eq(index).click();
            }
        },

        // 解答单选题
        _answerSelect() {
            let $emptySelected = this.$questionNode.find('.checkbox');
            let answerArray = this._syncGetAnswer().correctAnswerList;
            for (let i = 0; i < answerArray.length; i++) {
                let index = answerArray[i].charCodeAt() - 'A'.charCodeAt();
                $emptySelected.eq(index).click();
            }
        },

        // 解答判断题
        _answerJudge() {
            let questionAnswer = this._syncGetAnswer().correctAnswerList[0];
            if (questionAnswer=="true") {
                this.$questionNode.find('.choice-btn.right-btn').click();
            }
            else {
                this.$questionNode.find('.choice-btn.wrong-btn').click();
            }
        },

        // 解答填空题
        _answerInput() {
            let $emptyInput = this.$questionNode.find('.blank-input');
            let inputAnswers = this._syncGetAnswer().correctAnswerList;
            for (let i = 0; i < inputAnswers.length; i++) {
                $emptyInput.eq(i).val(inputAnswers[i]);
            }
        },

        // 解答简答题
        _answerSimpleQuestion() {
            let $emptyInput = this.$questionNode.find('.form-control');
            let inputAnswers = this._syncGetAnswer().correctAnswerList;
            for (let i = 0; i < inputAnswers.length; i++) {
                let answerText = inputAnswers[i].replace(/【答案要点】/g, '');
                $emptyInput.eq(i).val(answerText);             
                $(document).ready(function(){$emptyInput.change();console.log("111-111")} );
                
            }
        },

        // 同步获取测试答案
        _syncGetAnswer() {
            let res_answer;
            $.ajaxSettings.async = false;
            $.get('https://api.ulearning.cn/questionAnswer/' + this.questionId + '?parentId=' + this.parentId,function(xhr){res_answer = xhr;})
            $.ajaxSettings.async = true;
            return res_answer;
        }
    }


    // 日志管理器
    const log = {
        logs: '',
        $modal: $(`
<div class="modal" id="alertModal" tabindex="-1" role="dialog" style="display: none;background-color:rgba(0,0,0,.5)">
    <div class="modal-dialog" role="document" style="width:800px;margin-top:20px">
        <div class="modal-content">
            <i class="iconfont close-btn log-close-btn" data-dismiss="modal" aria-label="Close"></i>
            <div class="modal-image">
                <img src="./img/incomplete.png">
            </div>
            <div class="modal-body">
                <div class="modal-info">
                    <h4>本次挂机出现了意外情况,请到脚本主页加QQ群反馈!</h4>
                    <div class="content log-content" style="text-align:left">
                    </div>
                </div>
                <div class="modal-operation">
                    <button class="btn-submit log-close-btn" type="button">我明白了</button>
                </div>
            </div>
        </div>
    </div>
</div>
`),
        // 初始化日志管理器
        init() {
            $('body').append(this.$modal);
            this.$modal.find('.log-close-btn').click(() => {
                this.$modal.hide();
            })
        },
        // 添加日志
        addLog(info) {
            this.logs += '<span>时间:' + new Date().toJSON() + ' 信息:' + info + '</span><br>';
        },
        // 显示所有日志信息
        showLogs() {
            if (this.logs) {
                this.$modal.find('.log-content').empty();
                this.$modal.find('.log-content').append($('<div>' + this.logs + '</div>'));
                this.$modal.show();
            }
        }
    }
    Re_Write();
    Set_Heart();
    Init();
    
//拦截
function Re_Write() {
    const open = unsafeWindow.XMLHttpRequest.prototype.open;
    unsafeWindow.XMLHttpRequest.prototype.open = function () {
        let url = arguments[1];
        if (url) {
            if (url.match(/getPaperForStudent/) && url.match(/examId=(\d+)/) && url.match(/paperId=(\d+)/)) {
                let examID = url.match(/examId=(\d+)/)[1];
                let paperID = url.match(/paperId=(\d+)/)[1];
                this.addEventListener('load', () => {
                    let data = JSON.parse(this.responseText);
                    Util.upload_paper(data, paperID, examID);
                });
            }
            else if (url.match(/getCorrectAnswer/) && url.match(/examId=(\d+)/) && url.match(/paperId=(\d+)/)) {
                let examID = url.match(/examId=(\d+)/)[1];
                let paperID = url.match(/paperId=(\d+)/)[1];
                this.addEventListener('load', () => {
                    let data = JSON.parse(this.responseText);
                    Util.upload_answer(data, paperID, examID);
                });
            }
        }
        return open.apply(this, arguments);
    };
}
//UI初始化
function Init() {
    if (!document.body) {
        setTimeout(Init, 100);
        return;
    }
    let style = document.createElement("style");
    style.innerHTML = `
    #answer_key {
        min-height: 22px;
        max-height: 250px;
        overflow: auto;
    }
    .td_center {
        text-align: center;
    }
    .td_left {
        text-align: left;
    }
    .td_right {
        text-align: right;
    }
    .td_width {
        width: 125px;
    }`;
    let div = document.createElement("div");
    let pageurl = window.location.href.split("?")[0];
    if(pageurl=="https://utest.ulearning.cn/"){
        div.setAttribute("style", "background-color: #4fc8db; position: fixed; top: 54px; right: 300px; width: 270px; opacity: 0.75; border-style: dotted; border-width: 3px;z-index:99999;");
    }
    else{
        div.setAttribute("style", "background-color: #4fc8db; position: fixed; top: 54px; left: 50px; width: 270px; opacity: 0.75; border-style: dotted; border-width: 3px;z-index:99999;");
    }
 
    div.innerHTML = `
    <h3 style="text-align: center;">Ulearning 小助手 </h3>
    <table style="border-collapse:separate; border-spacing:1px 6px;margin-bottom:2px;">
        <tbody>
            <tr>
                <td class="td_width td_center">
                    <button id="get_answer" style="background-color: #84f584; border-radius: 10px;">查询答案</button>
                </td>
                <td class="td_width td_center">
                    <button id="hide_show" style="background-color: #84f584; border-radius: 10px;">显示/隐藏答案</button>
                </td>
            </tr>
            <tr>
                <td class="td_width td_right">
                    服务器状态:
                </td>
                <td id="server_status" class="td_width td_left" style="font-color: blue;">
                    获取中..
                </td>
            </tr>
        </tbody>
    </table>
    <div id="answer_key" style="display: block;">
        <table border="1" id="answer_table">
            <tbody>
                <tr>
                    <th class="td_width td_center">题目</th>
                    <th class="td_width td_center">答案</th>
                </tr>
            </tbody>
        </table>
    </div>
    `;
    document.body.appendChild(style);
    document.body.appendChild(div);
    Bind();
    div.addEventListener("mousedown", function (e) {
        set.Dealagging = true;
        let mer = div.getBoundingClientRect();
        set.left = e.clientX - mer.left;
        set.top = e.clientY - mer.top;
    });
    div.addEventListener("mouseup", function () {
        set.Dealagging = false;
    });
    div.addEventListener("mousemove", function (e) {
        if (set.Dealagging) {
            let x = e.clientX - set.left;
            let y = e.clientY - set.top;
            div.style.left = x + "px";
            div.style.top = y + "px";
        }
    });
    let new_uri= window.location.href.split("?")[0];
    if(new_uri=="https://ua.ulearning.cn/learnCourse/learnCourse.html"){
        youxueyuan.init();
    }
}
//隐藏
function Bind() {
    let get_answer = document.querySelector("#get_answer");
    get_answer && (function () {
        get_answer.addEventListener("click", Get_Answer, false);
    })();
    let hide_show = document.querySelector("#hide_show");
    hide_show && (function () {
        hide_show.addEventListener("click", function () {
            let answer_key = document.querySelector("#answer_key");
            answer_key && (function () {
                answer_key.getAttribute("style") === "display: block;" && (function () {
                    answer_key.setAttribute("style", "display: none;");
                    return true;
                })() || (function () {
                    answer_key.setAttribute("style", "display: block;");
                })();
            })();
        }, false);
    })();
}
function Set_Heart() {
        setInterval(Heart, 20000);
}
//服务器状态
function Heart() {
    let server_status = document.querySelector("#server_status");
    if (server_status) {
        set.timestamp = new Date().getTime();
        Util.get(set.heartbeat, { token: "" + set.token, timestamp: "" + set.timestamp }, function (xhr) {
            try {
                let xhr_json = JSON.parse(xhr.responseText);
                if (xhr_json.code == 1) {
                    server_status.innerText = "正常";
                    return;
                }
            }
            catch (e) { }
            server_status.innerText = "异常";
        }, function () {
            server_status.innerText = "异常";
        });
    }
}
function Clear_Table() {
    let answer_table = document.querySelector("#answer_table");
    answer_table && (function () {
        while (answer_table.rows.length > 1) {
            answer_table.deleteRow(1);
        }
    })();
}
//题库
function Get_Answer() {
    Clear_Table();
    let question_area = document.querySelectorAll(".question-area");
    question_area && (function(){
        question_area.forEach(function (item) {
            item.childNodes.forEach(function (div) {
                if (div.className.indexOf("next-part") != -1) {
                    return;
                }
                switch (div.className) {
                    case "question-item":
                        way1(div);
                        break;
                    default:
                        way2(div);
                }
            });
        });
    })();
    let question_wrap = document.querySelectorAll("#questionWrap");
    question_area && (function(){
        question_wrap.forEach(function (item) {
            item.childNodes.forEach(function (div){
                switch (div.className) {
                    case "multiple-choices":
                        case "judge":
                        case "fill":
                        case "match":
                        case "sort":
                            way3(div);
                            break;
                        case "blankFill":
                        case "cloze":
                        default:
                            way2(div);
                }
            });
        });
    })();
}
//作业
function way3(div) {
    let index = div.querySelector(".position-rltv").firstChild.innerText;
    let title = re_text(div.querySelector(".position-rltv").lastChild);
    let quetype = div.firstChild.dataset.type;
    let title_text = title && title.innerText || "";
    let answer_table = document.querySelector("#answer_table");
    answer_table && (function () {
        let tr = answer_table.insertRow();
        let t = tr.insertCell();
        t.innerText = "【" + index.split(".")[0] + "】" + title_text;
        t.addEventListener("click", function () {
            GM_setClipboard(this.innerText);
        }, false);
        t = tr.insertCell();
        Util.get_answer(title_text, quetype, t);
    })();
}
function way2(div) {
//   英语答题类      待提供测试账号开发
//   英语答题类      待提供测试账号开发
//   英语答题类      待提供测试账号开发
}
//考试
function way1(div) {
    let qid = div.firstChild.__vue__.question.questionid;
    if (!qid) {
        return;
    }
    let index = div.firstChild.__vue__.question.index;
    let title = re_text(div.firstChild.__vue__.question.title);
    let quetype = div.firstChild.__vue__.question.type;
    let quetxt = "";
    let cho = div.firstChild.__vue__.question.choices;
    if(quetype==1||quetype==2){
        cho.forEach(function(item){quetxt+=item.text+"||";})
        quetxt = re_text(quetxt);
    }
    let answer_table = document.querySelector("#answer_table");
    answer_table && (function () {
        let tr = answer_table.insertRow();
        let t = tr.insertCell();
        t.innerText = "【" + index + "】" + title;
        t.addEventListener("click", function () {
            GM_setClipboard(this.innerText);
        }, false);
        t = tr.insertCell();
        let getcode = Util.get_answer(title, quetype, t);
        if(getcode==0){
            Util.upload_title(title, quetype, quetxt);
        }
    })();
}
//正则处理
function re_text(text) {
    text = text.replace(/<\/?.+?\/?>/g,'');
    text = text.replace(/\t/g, "");
    text = text.replace(/\n/g, "");
    text = text.replace(/\r/g, "");
    text = text.replace(/&.*?;/g, "");
    return $.trim(text.substr(0,text.length-2));
}
//未启用 
function sleep(d){
  for(var t = Date.now();Date.now() - t <= d;);
}

//处理类 
class Deal {
    constructor() {
        this.text = "";
        this.data = [];
    }
    append(k, v) {
        this.data.push(encodeURIComponent(k) + "=" + encodeURIComponent(v));
        this.text = this.data.join("&").replace(/%20/g, "+");
    }
}

})();