// ==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如果无法解决,请前往 https://greasyfork.org/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如果无法解决,请前往 https://greasyfork.org/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();
})();