vjudge++

为vJudge设置背景,并汉化部分界面

目前为 2023-08-17 提交的版本。查看 最新版本

// ==UserScript==
// @name         vjudge++
// @namespace    vjudge-plus-v2
// @version      1.8.4b6
// @description  为vJudge设置背景,并汉化部分界面
// @author       axototl (original by Suntra)
// @match        https://vjudge.net/*
// @noframes
// @icon         https://vjudge.net/favicon.ico
// @license      AGPLv3 or later
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// @run-at       document-end
// ==/UserScript==

// license text: https://www.gnu.org/licenses/agpl-3.0.txt

let config = {experimental: false, debug: false};

function dbgopt(...txt) {
    if(config.debug) console.debug(txt.join(' '));
}

function getVal(key, def) {
    let gg = GM_getValue(key);
    if (gg === '' || gg === undefined) {
        GM_setValue(key, def);
        gg = def;
    }
    return gg;
}

function reloader() {
    alert("设置成功,刷新生效");
    if (!navigator.onLine) {
        alert("离线状态,无法重加载。\n修改无法即刻生效");
        return;
    }
    location.reload();
}

// 获取环境配置(不得异步处理) -Begin-
(() => {
    config.experimental = getVal("experimental", false);
    config.debug = getVal("debug", true);
    config.ads = getVal("ads", true);
    function reg_command(name, prompts, need_reload = true) {
        let flag = true;
        GM_registerMenuCommand(prompts[config[name] | 0], () => {
            if(flag) {
                config[name] = !config[name];
                GM_setValue(name, config[name]);
                flag = false;
            }
            if (need_reload) reloader();
        })
    }
    // 设置实验性功能
    reg_command("experimental", ["× 点击启用实验性功能(界面汉化等)", "✔ 点击关闭实验性功能"]);
    // 设置debug
    reg_command("debug", ["已禁用 debug 输出", "已启用debug输出"], false);
    reg_command("ads", ["× 屏蔽广告(点击启用)", "✔ 屏蔽广告(点击禁用)"]);
    // 在基于 Blink 浏览器上检测是否为正常返回
    if (navigator.userAgent.includes("Chrome") && performance.getEntries()[0].responseStatus != 200) return;

    // 设置背景
    config.back = getVal("background", "https://cdn.luogu.com.cn/images/bg/fe/Day_And_Night_1.jpg");
    GM_registerMenuCommand("设置背景URL", () => {
        config.back = window.prompt("请输入背景URL", config.back);
        GM_setValue("background", config.back);
        reloader();
    });

    // 设置文字颜色
    config.col = getVal("col", "#b93e3e");
    const tester = /^#([0-9a-f]{3,4}|[0-9a-f]{6})$/i;
    function getColor(t) {
        do {
            tmp = window.prompt("请输入颜色的Hexcode\n(比如#b93e3e)\n建议选择背景主色调的反差色", t);
        } while (!tester.test(t));
        return t;
    }
    GM_registerMenuCommand("设置文字颜色", () => {
        GM_setValue("col", getColor(config.col));
        reloader();
    });
    config.collink = getVal("collink", "#ff4c8c");
    GM_registerMenuCommand("设置链接背景颜色", () => {
        GM_setValue("collink", getColor(config.collink));
        reloader();
    });
})();
// 获取环境配置 -End-

// 界面美化程序 -Begin-
(async () => {
    document.body.innerHTML = "<div style='height: 60px'></div>" + document.body.innerHTML; // 防止顶栏和页面内容重叠
    // User defined style
    GM_addStyle("body {background: url("+config.back+") no-repeat center top fixed;background-size: 100% 100%;-moz-background-size: 100% 100%;color: "+config.col+";}"+
        "a:focus, a:hover, .active {&:not(.nav-link){color: "+config.collink+" !important;text-decoration: underline;}}");
    // Global Style
    GM_addStyle(
        ".navbar {border-radius:0rem;background-color: rgba(0,0,0,65%) !important;position: fixed;top: 0;left: 0;z-index: 1000;width: 100%;}"+
        "scrollbar-width: none"+
        ".card-block, .card, .list-group-item, .btn-secondary, .page-link, .page-item.disabled .page-link, .dropdown-menu {background-color: rgba(255,255,255,65%)!important;}"+
        ".modal-content {background-color: rgba(255,255,255,90%);}"+
        ".form-control {background-color: rgba(255,255,255,50%);}"+
        ".tab-content {background-color: rgba(255,255,255,50%);border: 2px solid #eceeef;border-radius: 0.25rem;padding: 20px;}"+
        "table {background-color: rgba(255,255,255,70%);border-radius: 0.25rem;}"
    );
    document.querySelector("body > div.body-footer").innerHTML += '<p style="color: #3fb98b">Theme powered by vjudge++ (original <a href="https://gf.qytechs.cn/scripts/448801">vjudge+</a>)</p>';
})();
// 界面美化程序 -End-

(async () => {
    if (!config.ads) return;
    let arr = document.querySelectorAll(".social, #prob-ads, #img-support");
    for (let x of arr) x.remove();
})(); // 广告移除

// 界面汉化程序 -Begin-
(() => {
    if (!config.experimental) return;

    const basicTranslateTable = {
        "#nav-problem > a": "问题列表",
        "#nav-status > a": "提交记录",
        "#nav-contest > a": "比赛",
        "#nav-workbook > a": "题单",
        "#nav-user > a": "用户",
        "#nav-group > a": "小组",
        "#nav-comment > a": "留言板",
        ".login": "登录(不可用)",
        ".register": "注册(不可用)",
        ".logout": "登出",
        ".user-dropdown > a:nth-child(1)": "个人主页",
        ".update-profile": "更新个人信息",
        ".message": "消息"
    };

    const basicDynTransTable = {
        ".previous > a": "上一页",
        ".next > a": "下一页",
        "#filter": "应用过滤器", // 无法工作
        "#reset": "重置过滤器", // 无法工作
    };
    const loginBoxTranslate = {
        "#loginModalLabel": "登录(不可用)",
        "#btn-forget-password": "忘记密码",
        "#btn-login": "登录(不可用)",
        ".btn[data-dismiss]": "取消"
    };

    const registerBoxTrans = {
        "#registerModalLabel": "注册(不可用)",
        "[for=register-username]": "用户名\n(必填)",
        "[for=register-password]": "密码\n(必填)",
        "[for=register-repeat-password]": "重复密码\n(必填)",
        "[for=register-nickname]": "昵称\n(可修改)",
        "[for=register-school]": "学校",
        "[for=register-email]": "邮箱\n(必填)",
        "[for=register-introduction]": "自我介绍",
        "[for=register-captcha]": "验证码\n(必填)",
        "#btn-register": "注册(不可用)",
        ".btn[data-dismiss]": "取消"
    };

    const updateProfileTrans = {
        "#updateModalLabel": "更新个人信息",
        "[for=update-username]": "用户名",
        "[for=update-orig-password]": "原密码(必填)",
        "[for=update-password]": "新密码\n(可选)",
        "[for=update-repeat-password]": "重复新密码",
        "[for=update-nickname]": "昵称",
        "[for=update-school]": "学校",
        "[for=update-captcha]": "验证码",
        "[for=update-email]": "邮箱",
        "[for=update-introduction]": "个人简介",
        "#btn-update-profile": "更新",
        ".btn[data-dismiss]": "取消"
    };

    function upd_trans(tr, flag = false) {
        for (let prop in tr) {
            let k = document.querySelector(prop);
            if (null != k)
                if (flag && k.childNodes.length >= 1) k.childNodes[0].data = tr[prop];
                else {
                    k.innerText = tr[prop];
                }
            else dbgopt(prop, "is null");
        }
    }

    function dynamic_trans(table, triggerDOM = null) {
        let ev = "click";
        if (null == triggerDOM)
            ev = "load", triggerDOM = window;
        triggerDOM.addEventListener(ev, () => setTimeout(() => upd_trans(table), 200));

    }

    function reg_box_trans(triggerElem_selector, table) {
        let s = document.querySelector(triggerElem_selector);
        if (null != s) dynamic_trans(table, s);
        else dbgopt(triggerElem_selector, "is null");
    }

    (async () => {
        document.querySelector(".navbar-brand").childNodes[2].data = " 首页";
        upd_trans(basicTranslateTable);
        reg_box_trans(".login", loginBoxTranslate);
        reg_box_trans(".register", registerBoxTrans);
        reg_box_trans(".update-profile", updateProfileTrans);
        dynamic_trans(basicDynTransTable);
    })(); //基本汉化

    // 静态内容汉化
    /* -Begin- */
    const staticTransTable = {
        "/": [{
            "#index-intro > div > div > p": "Vritual Judge(以下简称vj)并不是一个真实的在线评测网站(以下简称OJ),\
而是整合了各大OJ平台的题目形成的虚拟OJ平台。你提交的所有代码都会被发回原平台进行评测。\n\
vj可以让你轻松开展比赛,不再为测试数据发愁\n\n\
目前我们支持以下平台的题库:"
        }, 0],
        "/problem": [{
            "[data-category=all]": "全部问题",
            "[data-category=solved]": "已解决问题",
            '[data-category=favorites]': "收藏的问题",
            "[data-category=attempted]": "未通过/正在评测的问题"
        }, 1],
        "/status": [{
            "[data-owner=all]": "所有提交",
            "[data-owner=mine]": "我的提交",
            ".username": "用户名",
            ".oj": "测评平台",
            ".prob_num": "问题编号",
            ".status": "状态",
            ".runtime": "运行时长",
            ".memory": "运行内存",
            ".length": "代码长度",
            ".language": "语言",
            ".date": "提交时间"
        }, 1],
    };
    (async () => {
        for (const path in staticTransTable) {
            if (path == location.pathname) {
                const tr = staticTransTable[path]
                upd_trans(tr[0], tr[1]);
                break;
            }
        }
    })();
    /* -End- */



})();
// 界面汉化程序 -End-

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址