【U校园答案显示】 自用版(推荐使用ScriptCat脚本猫)

U校园题目答案显示;不支持单元测试

当前为 2024-11-16 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         【U校园答案显示】 自用版(推荐使用ScriptCat脚本猫)
// @namespace    jayhyy
// @homepage     https://greasyfork.org/zh-CN/scripts/517254-u%E6%A0%A1%E5%9B%AD%E7%AD%94%E6%A1%88%E6%98%BE%E7%A4%BA-%E8%87%AA%E7%94%A8%E7%89%88-%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8scriptcat%E8%84%9A%E6%9C%AC%E7%8C%AB
// @version      1.4
// @description  U校园题目答案显示;不支持单元测试
// @author       jayhyy
// @match        *://ucontent.unipus.cn/_pc_default/pc.html?*
// @connect      *://ucontent.unipus.cn/*
// @connect      unipus.cn
// @grant        GM_xmlhttpRequest
// @run-at       document-end
// @require      https://lib.baomitu.com/jquery/3.6.0/jquery.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
// @license      MIT
// ==/UserScript==

$('head').append('<link href="https://lib.baomitu.com/layui/2.6.8/css/layui.css" rel="stylesheet" type="text/css" />');
$.getScript("https://lib.baomitu.com/layui/2.6.8/layui.js", function(data, status, jqxhr) {
    layui.use('element', function(){
        var element = layui.element;
    });
    layer.closeAll();
    show();
    showanswer();
});

// 感谢ssmjae提供的解密代码
function decryptContent(json) {
    if (json) {
        let r = json.content.slice(7)
        , o = CryptoJS.enc.Utf8.parse("1a2b3c4d" + json.k)
        , i = CryptoJS.enc.Hex.parse(r)
        , a = CryptoJS.enc.Base64.stringify(i)
        , contentJson = JSON.parse(CryptoJS.AES.decrypt(a, o, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.ZeroPadding
        }).toString(CryptoJS.enc.Utf8));
        json = contentJson;
        console.log(json);
    }
    return json;
}

var show = ()=>{
    layer.open({
        type: 1,
        area: ['500px', '600px'],
        offset: ['bottom', 'left'] ,// 距离底部和左侧
        id: 'msgt',
        closeBtn: 1,
        title: "U校园网课助手(答案显示,支持单选、多选、填空、简答、问答)",
        shade: 0,
        maxmin: true,
        anim: 2,
        content:'<div class="layui-collapse"><div class="layui-colla-item"><h2 class="layui-colla-title">公告</h2><div class="layui-colla-content layui-show">脚本已修复</div>'+
        '</div></div>'+
        '<div id="content"><ul></ul><table class="layui-table"> <colgroup> <col width="100"> <col> <col> </colgroup> <thead> <tr>  </tr> </thead> <tbody>  </tbody> </table></div></div></div>'
    });
}

let isShow = true
var showanswer = ()=>{
    if (isShow){
        let url = location.href
        let arr = url.split("/")
        let book = arr[arr.length-7]
        let unit = arr[arr.length-2]
        let answer = []
        GM_xmlhttpRequest({
            method: 'GET',
            url: 'https://ucontentapi.unipus.cn/course/api/content/'+book+'/'+unit+'/default/',
            headers: {
                'X-ANNOTATOR-AUTH-TOKEN': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJvcGVuX2lkIjoidHV4NkNCQVc4aGRrcnFZdzc5SEpEWDF2aTR5Z2ptcDUiLCJuYW1lIjoiIiwiZW1haWwiOiIiLCJhZG1pbmlzdHJhdG9yIjoiZmFsc2UiLCJleHAiOjE5MDI5NzAxNTcwMDAsImlzcyI6IlI0aG03RmxQOFdvS0xaMUNmTkllIiwiYXVkIjoiZWR4LnVuaXB1cy5jbiJ9.CwuQmnSmIuts3hHAMf9lT954rKHXUNkps-PfRJp0KnU'
            },
            timeout: 5000,
            onload: function(xhr) {
                if (xhr.status == 200) {
                    let el = '<tr class="layui-bg">' + '</td></tr>'
                    console.log('https://ucontentapi.unipus.cn/course/api/content/'+book+'/'+unit+'/default/')

                    console.log(xhr.responseText)
                    let obj = JSON.parse(xhr.responseText) || {};
                    let deObj = decryptContent(obj);
                    let keyList = Object.keys(deObj);
                    console.log(keyList)
                    Array.prototype.contains = function (obj) {
                        var index = this.length;
                        while (index--) {
                            if (this[index] === obj) {
                                return true;
                            }
                        }
                        return false;
                    }
                    // 选择题
                    if (keyList.contains('questions:questions')) {
                        let questionList = deObj['questions:questions'].questions;
                        let lineCount = 0; // 初始化行数计数器

                        for (let question of questionList) {
                            let result = '';
                            
                            if (question.answers) {
                                result += question.answers.join(' ');
                            }

                            // 在每一行前加上行号
                            lineCount++; // 增加行数
                            el = el + '<tr><td>第' + lineCount + '题: ' + result + question.analysis.html + '</td></tr>';
                        }

                        // 可选:在最后添加总行数统计
                        el = el + '<tr><td colspan="2">总题数: ' + lineCount + '</td></tr>';
                    }
                // 简答题
                if (keyList.contains('shortanswer:shortanswer')) {
                    let questionList = deObj['shortanswer:shortanswer'].questions;
                    let lineCount = 0; // 初始化行数计数器

                    for (let question of questionList) {
                        lineCount++; // 每处理一个题目,行数加 1
                        el = el + '<tr><td>第' + lineCount + '题: ' + deObj['shortanswer:shortanswer'].analysis.html + question.content.html + question.analysis.html + '</td></tr>';
                    }

                    // 可选:在最后添加总行数统计
                    el = el + '<tr><td colspan="2">总题数: ' + lineCount + '</td></tr>';
                }
                    // 填空题
                    if (keyList.contains('questions:scoopquestions')) {
                        let questionList = deObj['questions:scoopquestions'].questions;
                        let lineCount = 0; // 初始化行数计数器

                        for (let question of questionList) {
                            lineCount++; // 每处理一个题目,行数加 1

                            let result = '';
                            if (question.answers) {
                                result += question.answers.join(' ');
                            }

                            // 输出包含行号的 HTML 和复制按钮
                            el = el + '<tr><td>第' + lineCount + '题: ' + result + question.analysis.html + '</td>';
                            el += '<td><button class="layui-btn layui-btn-xs copy-btn" data-content="' + result + '">复制</button></td></tr>';
                        }

                        // 可选:在最后添加总行数统计
                        el = el + '<tr><td colspan="2">总题数: ' + lineCount + '</td></tr>';
                    }

                    // 为复制按钮添加事件监听
                    $(document).on('click', '.copy-btn', function() {
                        var content = $(this).data('content'); // 获取该按钮对应的内容
                        var textarea = document.createElement("textarea"); // 创建一个临时的textarea元素
                        textarea.value = content; // 将内容设置为textarea的值
                        document.body.appendChild(textarea); // 将textarea添加到DOM中
                        textarea.select(); // 选择textarea中的内容
                        document.execCommand("copy"); // 执行复制操作
                        document.body.removeChild(textarea); // 删除临时textarea

                        // 提示用户已复制
                        layer.msg('已复制: ' + content, {icon: 1});
                    });                // 短回答题
                if (keyList.contains('questions:shortanswer')) {
                    let questionList = deObj['questions:shortanswer'].questions;
                    let lineCount = 0; // 初始化行数计数器

                    for (let question of questionList) {
                        lineCount++; // 每处理一个题目,行数加 1

                        let result = '';
                        if (question.answers) {
                            result += question.answers.join(' ');
                        }

                        // 输出包含行号的 HTML
                        el = el + '<tr><td>第' + lineCount + '题: ' + result + question.analysis.html + '</td></tr>';
                    }

                    // 可选:在最后添加总行数统计
                    el = el + '<tr><td colspan="2">总题数: ' + lineCount + '</td></tr>';
                }
                    el = el + '<td>答案结束,如果没有答案,尝试刷新试试</td></td></tr>'
                    $("#content>table>tbody").append($(el));
                }
            }
        });
    }
    isShow = !isShow
}

var show = () => {
    layer.open({
        type: 1,
        area: ['500px', '600px'],
        offset: ['20%', '60%'], // 垂直居中,水平自动
        id: 'msgt',
        closeBtn: 1,
        title: "U校园网课助手(答案显示,支持单选、多选、填空、简答、问答)",
        shade: 0,
        maxmin: true,
        anim: 2,
        content: '<div class="layui-collapse"><div class="layui-colla-item"><h2 class="layui-colla-title">公告</h2><div class="layui-colla-content layui-show">脚本已修复</div>' +
            '</div></div>' +
            '<div id="content"><ul></ul><table class="layui-table"> <colgroup> <col width="100"> <col> <col> </colgroup> <thead> <tr>  </tr> </thead> <tbody>  </tbody> </table>' +
            // 添加刷新按钮
            '<button id="refresh-btn" class="layui-btn layui-btn-normal">一键刷新</button>' +
            '</div></div></div>',
        success: function(layero, index) {
            // 获取浏览器窗口的宽度和弹框的宽度
            var windowWidth = $(window).width();
            var layerWidth = $(layero).outerWidth();
            var layerHeight = $(layero).outerHeight();
            var topOffset = (window.innerHeight - layerHeight) / 2; // 垂直居中
            var rightOffset = windowWidth - layerWidth - 10; // 右侧10px边距

            // 设置弹框的位置,垂直居中,右对齐
            $(layero).css({
                'top': topOffset + 'px',
                'right': rightOffset + 'px'
            });
        }
    });

    // 为刷新按钮绑定点击事件
    $('#refresh-btn').click(function() {
        console.log('刷新页面');
        location.reload(); // 刷新页面
    });
}

$(document).ready(function() {
    // 页面加载完毕时初始化点击检查
    function autoClickConfirmButton() {
        var interval = setInterval(function() {
            var confirmButton = $("span[style*='font-size: 14px'][style*='text-transform: uppercase']");
            if (confirmButton.length > 0) {
                confirmButton.click(); // 自动点击
                console.log("已自动点击确定按钮");
                clearInterval(interval); // 点击后停止检查
            }
        }, 500); // 每500ms检查一次
    }

    // 初始时调用函数检查按钮
    autoClickConfirmButton();

    // 监听URL的变化,检测页面切换
    window.onhashchange = function() {
        console.log("页面切换 detected");
        $("#content>table>tbody").empty(); // 清空之前的内容
        showanswer(); // 重新加载答案
        autoClickConfirmButton(); // 每次页面切换后重新调用点击函数
    };
});


// 检查脚本是否有更新
function checkForUpdates() {
    GM_xmlhttpRequest({
        method: 'GET',
        url: 'https://update.greasyfork.org/scripts/517254/%E3%80%90U%E6%A0%A1%E5%9B%AD%E7%AD%94%E6%A1%88%E6%98%BE%E7%A4%BA%E3%80%91%20%E8%87%AA%E7%94%A8%E7%89%88.meta.js', // 获取脚本元数据
        onload: function(response) {
            const meta = response.responseText;
            const remoteVersion = /@version\s+([\d.]+)/.exec(meta)[1]; // 提取远程版本号
            const currentVersion = GM_info.script.version; // 当前脚本版本

            if (remoteVersion > currentVersion) {
                alert(`检测到新版本:${remoteVersion},请更新脚本!`);
                // 提供更新提醒或自动下载更新
                if (confirm("发现新版本,是否立即更新脚本?")) {
                    window.location.href = "https://update.greasyfork.org/scripts/517254/%E3%80%90U%E6%A0%A1%E5%9B%AD%E7%AD%94%E6%A1%88%E6%98%BE%E7%A4%BA%E3%80%91%20%E8%87%AA%E7%94%A8%E7%89%88.user.js"; // 自动跳转到更新链接
                }
            }
        },
        onerror: function() {
            console.log("无法检查更新,请稍后再试");
        }
    });
}

// 每隔一段时间检查一次更新(例如,每24小时检查一次)
setInterval(checkForUpdates, 86400000); // 24小时检查一次



window.onhashchange=()=>{
    $("#content>table>tbody").empty();
    showanswer();
}