Codeforces Better!

Codeforces界面汉化、题目翻译,markdown视图,一键复制题目

Stan na 10-05-2023. Zobacz najnowsza wersja.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

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

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         Codeforces Better!
// @namespace    https://greasyfork.org/users/747162
// @version      1.02
// @description  Codeforces界面汉化、题目翻译,markdown视图,一键复制题目
// @author       北极小狐
// @match        https://codeforces.com/*
// @connect      m.youdao.com
// @connect      www2.deepl.com
// @grant        GM_xmlhttpRequest
// @icon         https://www.google.com/s2/favicons?sz=64&domain=codeforces.com
// @require      https://cdn.bootcdn.net/ajax/libs/turndown/7.1.1/turndown.min.js
// @license      MIT
// ==/UserScript==
// 样式
function loadCssCode(code){
    var style = document.createElement('style');
    style.type = 'text/css';
    style.rel = 'stylesheet';
    style.appendChild(document.createTextNode(code));
    var head = document.getElementsByTagName('head')[0];
    head.appendChild(style);
}
loadCssCode(`
span.mdViewContent {
    white-space: pre-wrap;
}
.translate-problem-statement {
    white-space: pre-wrap;
    border: 1px dashed #00aeeccc;
    border-radius: 0.3rem;
    padding: 5px;
    margin: 5px 0px;
}
.html2md-panel {
    display: flex;
    justify-content: flex-end;
}
button.html2mdButton {
    height: 3vh;
    width: 3vh;
}
button.html2mdButton {
    cursor: pointer;
    background-color: #e6e6e6;
    color: #727378;
    height: 3vh;
    width: auto;
    font-size: 1.3vh;
    border-radius: 0.3rem;
    border: none;
    padding: 1px 5px;
    margin: 5px;
    box-shadow: 0 0 1px #0000004d;
}
button.html2mdButton.copied {
    background-color: #07e65196;
    color: #104f2b;
}
button.html2mdButton.html2md-view.mdViewed {
    background-color: #ff980057;
    color: #5a3a0c;
}
button.translated {
    cursor: not-allowed;
    background-color: #2a6dc296;
    color: #fffdfd;
}
`);
// 汉化替换
(function() {
    // 设置语言为zh
    var htmlTag = document.getElementsByTagName("html")[0];
    htmlTag.setAttribute("lang", "zh-CN");

    // 定义classData,存放元素的class名和对应的替换规则
    const classData = {
        '.menu-list.main-menu-list': [
            { match: 'Help', replace: '帮助' },
            { match: 'Calendar', replace: '日历' },
            { match: 'Edu', replace: '培训' },
            { match: 'Rating', replace: '积分榜' },
            { match: 'Groups', replace: '团体' },
            { match: 'Problemset', replace: '题单' },
            { match: 'Gym', replace: '训练营(过去的大型比赛)' },
            { match: 'Contests', replace: '比赛' },
            { match: 'Catalog', replace: '指南目录' },
            { match: 'Top', replace: '热门' },
            { match: 'Home', replace: '主页' },
        ],
        '.caption.titled': [
            { match: 'Pay attention', replace: '注意' },
            { match: 'Top rated', replace: '积分排行' },
            { match: 'Top contributors', replace: '贡献者排行' },
            { match: 'Find user', replace: '查找用户' },
            { match: 'Recent actions', replace: '最近热帖' },
            { match: 'Training filter', replace: '过滤筛选' },
            { match: 'Find training', replace: '搜索比赛/问题' },
            { match: 'Virtual participation', replace: '什么是虚拟参赛' },
            { match: 'Contest materials', replace: '比赛相关资料' },
            { match: 'Settings', replace: '设置' },
            { match: 'Clone Contest to Mashup', replace: 'Clone比赛到组合混搭' },
            { match: 'Submit', replace: '提交' },
        ],
        '.personal-sidebar ': [
            { match: 'Contribution', replace: '贡献' },
            { match: 'Settings', replace: '设置' },
            { match: 'Blog', replace: '博客' },
            { match: 'Teams', replace: '队伍' },
            { match: 'Submissions', replace: '提交' },
            { match: 'Talks', replace: '私信' },
            { match: 'Contests', replace: '比赛' },
        ],
        '.contest-state-phase': [
            { match: 'Before contest', replace: '即将进行的比赛' },
        ],
        '.act-item': [
            { match: 'Add to favourites', replace: '添加到收藏' },
            { match: 'Submit', replace: '提交' },
        ],
        '.datatable': [
            { match: 'Virtual participation', replace: '参加虚拟重现赛' },
            { match: 'Enter', replace: '进入' },
            { match: 'Final standings', replace: '榜单' },
            { match: 'School/University/City/Region Championship', replace: '学校/大学/城市/区域比赛' },
            { match: 'Official School Contest', replace: '官方学校比赛' },
            { match: 'Training Contest', replace: '训练赛' },
            { match: 'Training Camp Contest', replace: '训练营比赛' },
            { match: 'Official ICPC Contest', replace: 'ICPC官方比赛' },
            { match: 'Official International Personal Contest', replace: '官方国际个人赛' },
            { match: 'China', replace: '中国' },
            { match: 'Statements', replace: '题目描述' },
            { match: 'in Chinese', replace: '中文' },
            { match: 'Trainings', replace: '训练' },
            { match: 'Prepared by', replace: '编写人' },
            { match: 'Current or upcoming contests', replace: '当前或即将举行的比赛' },
            { match: 'Past contests', replace: '过去的比赛' },
            { match: 'Exclusions', replace: '排除' },
            { match: 'Before start', replace: '还有' },
            { match: 'Before registration', replace: '报名还有' },
            { match: 'Until closing ', replace: '结束报名' },
            { match: 'Register', replace: '报名' },
            { match: 'Registration completed', replace: '已报名' },
            { match: 'Questions about problems', replace: '关于题目的提问' },
        ],
        '.ask-question-link': [
            { match: 'Ask a question', replace: '提一个问题' },
        ],
        '.contests-table': [
            { match: 'Contest history', replace: '比赛历史' },
        ],
        '.roundbox.sidebox.borderTopRound ': [
            { match: 'Season:', replace: '时间范围(年度)' },
            { match: 'Contest type', replace: '比赛类型' },
            { match: 'ICPC region', replace: 'ICPC地区' },
            { match: 'Contest format', replace: '比赛形式' },
            { match: 'Duration, hours', replace: '持续时间(小时)' },
            { match: 'Order by', replace: '排序方式' },
            { match: 'Secondary order by', replace: '次要排序方式' },
            { match: 'Hide, if participated', replace: '隐藏我参与过的' },
            { match: 'Hide excluded gyms', replace: '隐藏排除的比赛' },
            { match: 'Register now', replace: '现在报名' },
            { match: 'Show tags for unsolved problems', replace: '显示未解决问题的标签' },
            { match: 'Hide solved problems', replace: '隐藏已解决的问题' },
        ],
        '.icon-eye-close.icon-large': [
            { match: 'Add to exclusions', replace: '添加到排除列表' },
        ],
        '._ContestFilterExclusionsManageFrame_addExclusionLink': [
            { match: 'Add to exclusions for gym contests filter', replace: '添加训练营过滤器的排除项' },
        ],
        '.roundbox.sidebox.sidebar-menu.borderTopRound ': [
            { match: 'Announcement', replace: '公告' },
            { match: 'Statements', replace: '统计报表' },
            { match: 'Tutorial', replace: '题解' },
        ],
        '.second-level-menu ': [
            { match: 'Problems', replace: '问题' },
            { match: 'Submit Code', replace: '提交代码' },
            { match: 'My Submissions', replace: '我的提交' },
            { match: 'Status', replace: '状态' },
            { match: 'Standings', replace: '榜单' },
            { match: 'Custom Invocation', replace: '自定义调试' },
            { match: 'Common standings', replace: '全部排行' },
            { match: 'Friends standings', replace: '只看朋友' },
            { match: 'Submit', replace: '提交' },
            { match: 'Custom test', replace: '自定义测试' },
            { match: 'Blog', replace: '博客' },
            { match: 'Teams', replace: '队伍' },
            { match: 'Submissions', replace: '提交' },
            { match: 'Groups', replace: '团体' },
            { match: 'Contests', replace: '比赛' },
            { match: '问题etting', replace: '参与编写的问题' },
            { match: 'Gym', replace: '训练营' },
            { match: 'Mashups', replace: '组合混搭' },
            { match: 'Posts', replace: '帖子' },
            { match: 'Comments', replace: '回复' },
            { match: 'Main', replace: '主要' },
            { match: 'Settings', replace: '设置' },
            { match: 'Lists', replace: '列表' },
        ],
        '.topic-toggle-collapse': [
            { match: 'Expand', replace: '展开' },
        ],
        '.topic-read-more': [
            { match: 'Full text and comments', replace: '阅读全文/评论' },
        ],
        '.toggleEditorCheckboxLabel': [
            { match: 'Switch off editor', replace: '关闭编辑器语法高亮' },
        ],
        '.content-with-sidebar': [
            { match: 'Notice', replace: '注意' },
            { match: 'virtual participation', replace: '虚拟参与' },
            { match: 'Registration for the contest', replace: '比赛报名' },
            { match: 'Terms of agreement', replace: '协议条款' },
            { match: 'Take part', replace: '参与' },
            { match: 'as individual participant', replace: '作为个人参与者' },
            { match: 'as a team member', replace: '作为团队成员' },
            { match: 'Virtual start time', replace: '虚拟开始时间' },
            { match: 'Complete problemset', replace: '完整的问题集' },
        ],
        '.submit': [
            { match: 'Registration for the contest', replace: '比赛报名' },
        ],
        '.table-form': [
            { match: 'Problem', replace: '题目' },
            { match: 'Language', replace: '语言' },
            { match: 'Source code', replace: '源代码' },
            { match: 'Or choose file', replace: '或者选择文件' },
            { match: 'Choose file', replace: '选择文件' },
        ],
    };

    // 将所有 class 名与之符合的元素的 text 中包含的匹配的文字均替换为对应的文字
    for (const className in classData) {
        const elements = document.querySelectorAll(className);
        elements.forEach((element) => {
            let html = element.outerHTML; // 获取元素的 html 代码
            const parent = element.parentNode;
            const childIndex = Array.from(parent.children).indexOf(element);
            let matched = false; // 标记该元素是否匹配了规则
            classData[className].forEach((rule) => {
                if (html.match(new RegExp(rule.match, 'g'))) {
                    // 如果匹配成功,则将 matched 设置为 true
                    matched = true;
                    html = html.replace(new RegExp(rule.match, 'g'), rule.replace); // 将其中匹配的文字替换为对应的文字
                    const temp = document.createElement('div'); // 创建临时元素
                    temp.innerHTML = html.trim();
                    const newElement = element.cloneNode(true);
                    newElement.innerHTML = temp.firstChild.innerHTML;
                    parent.replaceChild(newElement, parent.children[childIndex]); // 替换元素
                }
            });
        });
    }
})();

// 题目翻译
window.onload = function() {
    let turndownService = new TurndownService();

    turndownService.keep(['del']);

    // **处理规则**
    // 忽略sample-tests
    turndownService.addRule('ignore-sample-tests', {
        filter: function(node) {
            return node.classList.contains('sample-tests')|| node.classList.contains('header');
        },
        replacement: function (content, node) {
            return "";
        }
    });

    // remove <script> math
    turndownService.addRule('remove-script', {
        filter: function (node, options) {
            return node.tagName.toLowerCase() == "script" && node.type.startsWith("math/tex");
        },
        replacement: function (content, node) {
            return "";
        }
    });

    // inline math
    turndownService.addRule('inline-math', {
        filter: function (node, options) {
            return node.tagName.toLowerCase() == "span" && node.className == "MathJax";
        },
        replacement: function (content, node) {
            return "$ " + $(node).next().text() + " $";
        }
    });

    // block math
    turndownService.addRule('block-math', {
        filter: function (node, options) {
            return node.tagName.toLowerCase() == "div" && node.className == "MathJax_Display";
        },
        replacement: function (content, node) {
            return "\n$$\n" + $(node).next().text() + "\n$$\n";
        }
    });

    // **题干**
    // 添加按钮
    $("div[class='problem-statement']").each(function() {
        $(this).children(':eq(1)').before(
            "<div class='html2md-panel'> <button class='html2mdButton html2md-view1'>MarkDown视图</button> <button class='html2mdButton html2md-cb1'>Copy</button> <button class='html2mdButton translateButton1'>翻译</button> </div>"
        );
    });


    $(".html2md-cb1").click(function() {
        let target = $(this).parent().next().get(0);
        if (!target.markdown){
            target.markdown = turndownService.turndown($(target).html());
        }
        const textarea = document.createElement('textarea');
        textarea.value = target.markdown;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
        $(this).addClass("copied");
        $(this).text("Copied");
        // 更新复制按钮文本
        setTimeout(() => {
            $(this).removeClass("copied");
            $(this).text("Copy");
        }, 2000);
    });

    $(".html2md-view1").click(function() {
        let target = $(this).parent().next().get(0);
        if (target.viewmd) {
            target.viewmd = false;
            $(this).text("MarkDown视图");
            $(this).removeClass("mdViewed");
            $(target).html(target.original_html);
        } else {
            target.viewmd = true;
            if (!target.original_html)
                target.original_html = $(target).html();
            if (!target.markdown)
                target.markdown = turndownService.turndown($(target).html());
            $(this).text("原始内容");
            $(this).addClass("mdViewed");
            $(target).html(`<span class="mdViewContent" oninput="$(this).parent().get(0).markdown=this.value;" style="width:auto; height:auto;"> ${target.markdown} </span>`);
        }
    });
    $(".translateButton1").click(function() {
        let target = $(this).parent().next().get(0);
        if (!target.markdown){
            target.markdown = turndownService.turndown($(target).html());
        }
        const textarea = document.createElement('textarea');
        textarea.value = target.markdown;
        // 翻译处理
        var element_node = $("div.problem-statement").children(':eq(2)').get(0);
        translateProblemStatement(textarea.value, element_node);
        //
        $(this).addClass("translated");
        $(this).text("已翻译");
        $(this).prop("disabled",true);
    });
    // **Input**
    // 添加按钮
    $("div[class='input-specification']").each(function() {
        $(this).children(':eq(1)').before(
            "<div class='html2md-panel'> <button class='html2mdButton html2md-view2'>MarkDown视图</button> <button class='html2mdButton html2md-cb2'>Copy</button> <button class='html2mdButton translateButton2'>翻译</button> </div>"
        );
    });


    $(".html2md-cb2").click(function() {
        let RelTarget = $(this).parent().parent().get(0);
        let target = $(RelTarget).clone(); // 创建副本
        $(target).children(':first').remove(); // 删除前两个元素(标题和按钮面板)
        $(target).children(':first').remove();
        if (!target.markdown){
            target.markdown = turndownService.turndown($(target).html());
        }
        const textarea = document.createElement('textarea');
        textarea.value = target.markdown;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
        $(this).addClass("copied");
        $(this).text("Copied");
        // 更新复制按钮文本
        setTimeout(() => {
            $(this).removeClass("copied");
            $(this).text("Copy");
        }, 2000);
        $(target).remove();
    });

    $(".html2md-view2").click(function() {
        let target = $(this).parent().parent().get(0);
        // 临时删除前两个子元素(标题和按钮面板)
        var removedChildren = $(this).parent().parent().children().eq(0).add($(this).parent().parent().children().eq(1)).detach();
        //
        if (target.viewmd) {
            target.viewmd = false;
            $(this).text("MarkDown视图");
            $(this).removeClass("mdViewed");
            $(target).html(target.original_html);
        } else {
            target.viewmd = true;
            if (!target.original_html)
                target.original_html = $(target).html();
            if (!target.markdown)
                target.markdown = turndownService.turndown($(target).html());
            $(this).text("原始内容");
            $(this).addClass("mdViewed");
            $(target).html(`<span class="mdViewContent oninput="$(this).parent().get(0).markdown=this.value;" style="width:auto; height:auto;"> ${target.markdown} </span>`);
        }
        // 恢复删除的元素
        $(".input-specification").prepend(removedChildren);
    });
    $(".translateButton2").click(function() {
        let RelTarget = $(this).parent().parent().get(0);
        let target = $(RelTarget).clone(); // 创建副本
        $(target).children(':first').remove(); // 删除前两个元素(标题和按钮面板)
        $(target).children(':first').remove();
        if (!target.markdown){
            target.markdown = turndownService.turndown($(target).html());
        }
        const textarea = document.createElement('textarea');
        textarea.value = target.markdown;
        // 翻译处理
        var element_node = $("div.input-specification").get(0);
        translateProblemStatement(textarea.value, element_node);
        //
        $(this).addClass("translated");
        $(this).text("已翻译");
        $(this).prop("disabled",true);
        $(target).remove();
    });
    // **Output**
    // 添加按钮
    $("div[class='output-specification']").each(function() {
        $(this).children(':eq(1)').before(
            "<div class='html2md-panel'> <button class='html2mdButton html2md-view3'>MarkDown视图</button> <button class='html2mdButton html2md-cb3'>Copy</button> <button class='html2mdButton translateButton3'>翻译</button> </div>"
        );
    });


    $(".html2md-cb3").click(function() {
        let RelTarget = $(this).parent().parent().get(0);
        let target = $(RelTarget).clone(); // 创建副本
        $(target).children(':first').remove(); // 删除前两个元素(标题和按钮面板)
        $(target).children(':first').remove();
        if (!target.markdown){
            target.markdown = turndownService.turndown($(target).html());
        }
        const textarea = document.createElement('textarea');
        textarea.value = target.markdown;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
        $(this).addClass("copied");
        $(this).text("Copied");
        // 更新复制按钮文本
        setTimeout(() => {
            $(this).removeClass("copied");
            $(this).text("Copy");
        }, 2000);
        $(target).remove();
    });

    $(".html2md-view3").click(function() {
        let target = $(this).parent().parent().get(0);
        // 临时删除前两个子元素(标题和按钮面板)
        var removedChildren = $(this).parent().parent().children().eq(0).add($(this).parent().parent().children().eq(1)).detach();
        //
        if (target.viewmd) {
            target.viewmd = false;
            $(this).text("MarkDown视图");
            $(this).removeClass("mdViewed");
            $(target).html(target.original_html);
        } else {
            target.viewmd = true;
            if (!target.original_html)
                target.original_html = $(target).html();
            if (!target.markdown)
                target.markdown = turndownService.turndown($(target).html());
            $(this).text("原始内容");
            $(this).addClass("mdViewed");
            $(target).html(`<span class="mdViewContent" oninput="$(this).parent().get(0).markdown=this.value;" style="width:auto; height:auto;"> ${target.markdown} </span>`);
        }
        // 恢复删除的元素
        $(".output-specification").prepend(removedChildren);
    });
    $(".translateButton3").click(function() {
        let RelTarget = $(this).parent().parent().get(0);
        let target = $(RelTarget).clone(); // 创建副本
        $(target).children(':first').remove(); // 删除前两个元素(标题和按钮面板)
        $(target).children(':first').remove();
        if (!target.markdown){
            target.markdown = turndownService.turndown($(target).html());
        }
        const textarea = document.createElement('textarea');
        textarea.value = target.markdown;
        // 翻译处理
        var element_node = $("div.output-specification").get(0);
        translateProblemStatement(textarea.value, element_node);
        //
        $(this).addClass("translated");
        $(this).text("已翻译");
        $(this).prop("disabled",true);
        $(target).remove();
    });
};


// 翻译处理
async function translateProblemStatement(text, element_node){
    let id = Math.floor(Date.now() / 1000);
    // 替换latex公式
    let matches = text.match(/\$(.*?)\$/g);
    let replacements = {};
    try{
        for (let i = 0; i < matches.length; i++) {
            let match = matches[i];
            text = text.replace(match, `【${i + 1}】`);
            replacements[`【${i + 1}】`] = match;
        }
    }catch(e){}
    text = text.replace(/\\/g, "");
    // 翻译
    let translatedText = await translate_youdao_mobile(text);
    // 还原latex公式
    try{
        for (let i = 0; i < matches.length; i++) {
            let match = matches[i];
            let replacement = replacements[`【${i + 1}】`];
            translatedText = translatedText.replace(`【${i + 1}】`, replacement);
        }
    }catch(e){}
    translatedText = translatedText.replace(/\$/g, "$$$$$$"); // 使符合mathjx的转换语法
    const translateDiv = document.createElement('div');
    // 创建元素并放在element_node的后面
    translateDiv.setAttribute('id', id);
    translateDiv.classList.add('translate-problem-statement');
    const spanElement = document.createElement('span');
    translateDiv.textContent = translatedText;
    translateDiv.appendChild(spanElement);
    element_node.insertAdjacentElement('afterend', translateDiv);
    // 渲染Latex
    MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById(id)]);
}

//--有道翻译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"
        }
    }
    return await BaseTranslate('有道翻译mobile',raw,options,res=>/id="translateResult">\s*?<li>([\s\S]*?)<\/li>\s*?<\/ul/.exec(res)[1])
}
//--有道翻译m--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': 'www.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

//--异步请求包装工具--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.log(err);
                return usedErrProcesser(err);
            }
        }
    }
}

async function BaseTranslate(name,raw,options,processer){
    const toDo = async ()=>{
        var tmp;
        try{
            const data = await Request(options);
            tmp = data.responseText;
            const result = await processer(tmp);
            if(result)sessionStorage.setItem(name+'-'+raw,result);
            return result
        }catch(err){
            throw {
                responseText: tmp,
                err: err
            }
        }
    }
    return await PromiseRetryWrap(toDo,{RetryTimes:3,ErrProcesser:()=>"翻译出错"})
}

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

//--异步请求包装工具--end