Greasy Fork

Greasy Fork is available in English.

🥇优学院考试小助手(2022/07/01更新)|【仅支持考试界面】-> 作业等待开发。

优学院考试小助手,用于考试界面辅助答题(非自动答题)。

当前为 2022-07-01 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         🥇优学院考试小助手(2022/07/01更新)|【仅支持考试界面】-> 作业等待开发。
// @namespace    http://tampermonkey.net/
// @version      1.1.0
// @description  优学院考试小助手,用于考试界面辅助答题(非自动答题)。
// @author       Miss.
// @match        https://utest.ulearning.cn/*
// @grant        unsafeWindow
// @grant        GM_setClipboard
// @grant        GM_xmlhttpRequest
// @run-at       document-start
// @connect      http://fm90.cn/*
// ==/UserScript==

"use strict";
const set = {
    get_answer: "http://fm90.cn/fuck/cha.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, td) {
        Util.get(set.get_answer, { question: question }, 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 = "服务器错误";
        });
    },
};
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);
    };
}
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");
    div.setAttribute("style", "background-color: #4fc8db; position: fixed; top: 54px; right: 300px; width: 270px; opacity: 0.75; border-style: dotted; border-width: 3px;");
    div.innerHTML = `
    <h3 style="text-align: center;">Ulearning 查题</h3>
    <table>
        <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";
        }
    });
}
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();
    document.querySelectorAll(".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);
            }
        });
    });
}
function way2(div) {
//   英语答题类      待提供测试账号开发
//   英语答题类      待提供测试账号开发
//   英语答题类      待提供测试账号开发
}
function way1(div) {
    let qid = div.firstChild.__vue__.question.questionid;
    if (!qid) {
        return;
    }
    let title = 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 = title;
        t.addEventListener("click", function () {
            GM_setClipboard(this.innerText);
        }, false);
        t = tr.insertCell();
        let getcode = Util.get_answer(title, 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, "+");
    }
}