Greasy Fork

Greasy Fork is available in English.

USACO Better!

USACO 优化

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         USACO Better!
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  USACO 优化
// @author       ZnPdCo
// @match        https://usaco.org/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=usaco.org
// @grant        unsafeWindow
// @connect      www2.deepl.com
// @connect      www.iflyrec.com
// @connect      m.youdao.com
// @connect      api.interpreter.caiyunai.com
// @connect      translate.google.com
// @connect      greasyfork.org
// @connect      *
// @grant        GM_xmlhttpRequest
// @grant        GM_info
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_addStyle
// @grant        GM_setClipboard
// @grant        GM_registerMenuCommand
// @require      https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
// @license      MIT
// ==/UserScript==

(function() {
    if(GM_getValue('translate') == undefined) {
        GM_setValue('translate', 'iflyrec');
    }
    GM_registerMenuCommand('使用 谷歌翻译' + (GM_getValue('translate') == 'gg' ? '√' : 'x'), function() {
        GM_setValue('translate', 'gg');
        location.reload();
    })
    GM_registerMenuCommand('使用 有道翻译' + (GM_getValue('translate') == 'youdao_mobile' ? '√' : 'x'), function() {
        GM_setValue('translate', 'youdao_mobile');
        location.reload();
    })
    GM_registerMenuCommand('使用 彩云翻译' + (GM_getValue('translate') == 'caiyun' ? '√' : 'x'), function() {
        GM_setValue('translate', 'caiyun');
        location.reload();
    })
    GM_registerMenuCommand('使用 deepl翻译' + (GM_getValue('translate') == 'deepl' ? '√' : 'x'), function() {
        GM_setValue('translate', 'deepl');
        location.reload();
    })
    GM_registerMenuCommand('使用 讯飞听见翻译' + (GM_getValue('translate') == 'iflyrec' ? '√' : 'x'), function() {
        GM_setValue('translate', 'iflyrec');
        location.reload();
    })

    //--谷歌翻译--start
    async function translate_gg(raw) {
        return new Promise((resolve, reject) => {
            const url = 'https://translate.google.com/m';
            const params = `tl=zh-CN&q=${encodeURIComponent(raw)}`;

            GM_xmlhttpRequest({
                method: 'GET',
                url: `${url}?${params}`,
                onload: function (response) {
                    const html = response.responseText;
                    const translatedText = $(html).find('.result-container').text();
                    resolve(translatedText);
                },
                onerror: function (response) {
                    reject("发生了未知的错误,请确认你是否能正常访问Google翻译,\n\n如果无法解决,请前往 http://greasyfork.icu/zh-CN/scripts/471106/feedback 反馈 请注意打码报错信息的敏感部分\n\n响应报文:" + JSON.stringify(response))
                }
            });
        });
    }
    //--谷歌翻译--end

    //--有道翻译m--start
    async function translate_youdao_mobile(raw) {
        const options = {
            method: "POST",
            url: 'http://m.youdao.com/translate',
            data: "inputtext=" + encodeURIComponent(raw) + "&type=AUTO",
            anonymous: true,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
                'Host': 'm.youdao.com',
                'Origin': 'http://m.youdao.com',
                'Referer': 'http://m.youdao.com/translate',
            }
        }
        return await BaseTranslate('有道翻译mobile', raw, options, res => /id="translateResult">\s*?<li>([\s\S]*?)<\/li>\s*?<\/ul/.exec(res)[1])
    }
    //--有道翻译m--end

    //--彩云翻译--start
    async function translate_caiyun_startup() {
        const browser_id = CryptoJS.MD5(Math.random().toString()).toString();
        sessionStorage.setItem('caiyun_id', browser_id);
        const options = {
            method: "POST",
            url: 'https://api.interpreter.caiyunai.com/v1/user/jwt/generate',
            headers: {
                "Content-Type": "application/json",
                "X-Authorization": "token:qgemv4jr1y38jyq6vhvi",
                "Origin": "https://fanyi.caiyunapp.com",
            },
            data: JSON.stringify({ browser_id }),
        }
        const res = await Request(options);
        sessionStorage.setItem('caiyun_jwt', JSON.parse(res.responseText).jwt);
    }

    async function translate_caiyun(raw) {
        const source = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm";
        const dic = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"].reduce((dic, current, index) => { dic[current] = source[index]; return dic }, {});
        // 解码
        const decodeUnicode = str => {
            const decoder = new TextDecoder();
            const data = Uint8Array.from(atob(str), c => c.charCodeAt(0));
            return decoder.decode(data);
        };
        const decoder = line => decodeUnicode([...line].map(i => dic[i] || i).join(""));
        const options = {
            method: "POST",
            url: 'https://api.interpreter.caiyunai.com/v1/translator',
            data: JSON.stringify({
                "source": raw.split('\n'),
                "trans_type": "auto2zh",
                "detect": true,
                "browser_id": sessionStorage.getItem('caiyun_id')
            }),
            headers: {
                "X-Authorization": "token:qgemv4jr1y38jyq6vhvi",
                "T-Authorization": sessionStorage.getItem('caiyun_jwt')
            }
        }
        return await BaseTranslate('彩云小译', raw, options, res => JSON.parse(res).target.map(decoder).join('\n'))
    }
    //--彩云翻译--end

    //--Deepl翻译--start
    function getTimeStamp(iCount) {
        const ts = Date.now();
        if (iCount !== 0) {
            iCount = iCount + 1;
            return ts - (ts % iCount) + iCount;
        } else {
            return ts;
        }
    }

    async function translate_deepl(raw) {
        const id = (Math.floor(Math.random() * 99999) + 100000) * 1000;
        const data = {
            jsonrpc: '2.0',
            method: 'LMT_handle_texts',
            id,
            params: {
                splitting: 'newlines',
                lang: {
                    source_lang_user_selected: 'auto',
                    target_lang: 'ZH',
                },
                texts: [{
                    text: raw,
                    requestAlternatives: 3
                }],
                timestamp: getTimeStamp(raw.split('i').length - 1)
            }
        }
        let postData = JSON.stringify(data);
        if ((id + 5) % 29 === 0 || (id + 3) % 13 === 0) {
            postData = postData.replace('"method":"', '"method" : "');
        } else {
            postData = postData.replace('"method":"', '"method": "');
        }
        const options = {
            method: 'POST',
            url: 'https://www2.deepl.com/jsonrpc',
            data: postData,
            headers: {
                'Content-Type': 'application/json',
                'Host': 'www2.deepl.com',
                'Origin': 'https://www.deepl.com',
                'Referer': 'https://www.deepl.com/',
            },
            anonymous: true,
            nocache: true,
        }
        return await BaseTranslate('Deepl翻译', raw, options, res => JSON.parse(res).result.texts[0].text)
    }

    //--Deepl翻译--end

    //--讯飞听见翻译--end
    async function translate_iflyrec(text) {
        const options = {
            method: "POST",
            url: 'https://www.iflyrec.com/TranslationService/v1/textTranslation',
            data: JSON.stringify({
                "from": "2",
                "to": "1",
                "contents": [{
                    "text": text,
                    "frontBlankLine": 0
                }]
            }),
            anonymous: true,
            headers: {
                'Content-Type': 'application/json',
                'Origin': 'https://www.iflyrec.com',
            },
            responseType: "json",
        };
        return await BaseTranslate('讯飞翻译', text, options, res => JSON.parse(res).biz[0].translateResult.replace(/\\n/g, "\n\n"));
    }
    //--讯飞听见翻译--end

    //--异步请求包装工具--start
    async function PromiseRetryWrap(task, options, ...values) {
        const { RetryTimes, ErrProcesser } = options || {};
        let retryTimes = RetryTimes || 5;
        const usedErrProcesser = ErrProcesser || (err => { throw err });
        if (!task) return;
        while (true) {
            try {
                return await task(...values);
            } catch (err) {
                if (!--retryTimes) {
                    console.warn(err);
                    return usedErrProcesser(err);
                }
            }
        }
    }

    async function BaseTranslate(name, raw, options, processer) {
        let errtext;
        const toDo = async () => {
            var tmp;
            try {
                const data = await Request(options);
                tmp = data.responseText;
                let result = await processer(tmp);
                return result;
            } catch (err) {
                errtext = tmp;
                throw {
                    responseText: tmp,
                    err: err
                }
            }
        }
        return await PromiseRetryWrap(toDo, { RetryTimes: 3, ErrProcesser: () => "翻译出错,请查看报错信息,并重试或更换翻译接口\n\n如果无法解决,请前往 http://greasyfork.icu/zh-CN/scripts/471106/feedback 反馈 请注意打码报错信息的敏感部分\n\n报错信息:" + errtext })
    }


    function Request(options) {
        return new Promise((reslove, reject) => GM_xmlhttpRequest({ ...options, onload: reslove, onerror: reject }))
    }

    async function show_translate_btn() {
        if($('#probtext-text').length) {
            $.ajax({
                type: "GET",
                url: location.href,
                async: false,
                success: function(data) {
                    window.data = data
                },
                error: function(xhr, statusText, error) {}
            });

            var origin_html = {};

            $('#probtext-text').html($(data).find('#probtext-text').html())
            var ele = $('#probtext-text').children()
            for(let i = 0; i < ele.length; i++) {
                if(ele.eq(i).html() == '' || ele.get(i).tagName == 'PRE' || ele.eq(i).html == 'SAMPLE INPUT:' || ele.eq(i).html == 'SAMPLE OUTPUT:') continue
                $(`<button style="margin-bottom:6px;" class="fanyi" id="fanyi-${i}" type="button">翻译</button>`).insertBefore(ele.eq(i))
                origin_html[i] = ele.eq(i).html()
            }

            MathJax.Hub.Queue(["Typeset", MathJax.Hub]);

            $(`.fanyi`).click(async function(e) {
                var fanyi_id = parseInt($(e.target).attr("id").replace('fanyi-', ''));
                var text = origin_html[fanyi_id]
                var texts = text.split('$$')
                var res = ""
                var tex = [], btex = []
                var tex2res = '😭', btex2res = '😁'
                for(let i = 0; i < texts.length; i++) {
                    if(i % 2 == 0) res += texts[i];
                    else btex.push(texts[i]), res += btex2res;
                }
                text = res
                texts = text.split('$')
                res = ""
                for(let i = 0; i < texts.length; i++) {
                    if(i % 2 == 0) res += texts[i];
                    else tex.push(texts[i]), res += tex2res;
                }
                text = res

                if($(`#result-${fanyi_id}`).length == 0)
                    $(`<div align="left" id="result-${fanyi_id}" class="problem-text mathjax" style="width:750px; padding-top:10px;"></div>`).insertAfter(e.target)
                $(`#result-${fanyi_id}`).html('正在翻译……请稍后……');

                if(GM_getValue('translate') == 'gg') text = await translate_gg(text)
                if(GM_getValue('translate') == 'youdao_mobile') text = await translate_youdao_mobile(text)
                if(GM_getValue('translate') == 'caiyun') text = await translate_caiyun(text)
                if(GM_getValue('translate') == 'deepl') text = await translate_deepl(text)
                if(GM_getValue('translate') == 'iflyrec') text = await translate_iflyrec(text)

                texts = text.split(btex2res)
                res = ""
                for(let i = 0; i < texts.length; i++) {
                    res += texts[i];
                    if(i < btex.length) res += '$$' + btex[i] + '$$'
                }
                text = res
                texts = text.split(tex2res)
                res = ""
                for(let i = 0; i < texts.length; i++) {
                    res += texts[i];
                    if(i < tex.length) res += '$' + tex[i] + '$'
                }
                text = res

                $(`#result-${fanyi_id}`).html(text);
                MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
            })
        }
    }
    show_translate_btn();
})();