// ==UserScript==
// @name OpenJudge Better!
// @namespace http://tampermonkey.net/
// @version 0.14.0
// @description 优化OpenJudge
// @author Andy_hpy
// @match http://*.openjudge.cn/*
// @icon http://static.openjudge.cn/styles/favicon.ico?1467854438.ico
// @grant GM_setClipboard
// @grant GM_xmlhttpRequest
// @grant GM_notification
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// @grant GM_getResourceText
// @grant GM_getResourceURL
// @grant GM_info
// @grant unsafeWindow
// @require https://cdn.jsdelivr.net/npm/jsencrypt@3.3.1/bin/jsencrypt.min.js
// @resource feedback https://scriptcat.org/zh-CN/script-show-page/3870/issue
// @resource script https://scriptcat.org/scripts/code/3870/OpenJudge%20Better!.user.js
// @run-at document-start
// ==/UserScript==
var feedbackUrl = "https://scriptcat.org/zh-CN/script-show-page/3870/issue";
var scriptUrl = "https://scriptcat.org/scripts/code/3870/OpenJudge%20Better!.user.js";
function generateCustomSalt(length = 16) {
const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let salt = '';
for (let i = 0; i < length; i++) {
salt += charset.charAt(Math.floor(Math.random() * charset.length));
}
return salt;
}
function encryptMorePara(publicKey, content, salt) {
var crypt = new JSEncrypt();
crypt.setPublicKey(publicKey);
return crypt.encrypt(salt + content);
}
function encrypt(content) {
if (content == null || content == undefined) {
return encryptMorePara(GM_getValue("publicKey"), "", GM_getValue("salt"));
}
return encryptMorePara(GM_getValue("publicKey"), content, GM_getValue("salt"));
}
function decryptMorePara(privateKey, content, salt) {
var crypt = new JSEncrypt();
crypt.setPrivateKey(privateKey);
var newcontent = crypt.decrypt(content);
if (newcontent == null || newcontent == undefined) {
newcontent = "";
}
if (salt && newcontent.indexOf(salt) == 0) {
return newcontent.substring(salt.length)
}
return newcontent;
}
function decrypt(content) {
if (content == null || content == undefined) {
return decryptMorePara(GM_getValue("privateKey"), "", GM_getValue("salt"));
}
return decryptMorePara(GM_getValue("privateKey"), content, GM_getValue("salt"));
}
function addcss() {
GM_addStyle(`
.lfe-caption {
color: gray;
font-size: .875em;
}
.lform-size-small {
font-size: .875em;
padding: .1px .5em;
border-radius: 4px;
border: 1px solid rgb(51,152,219);
color: rgb(51,152,219);
float: right;
background: white;
}
.lform-size-small:hover {
background: rgb(234,244,251);
}
.lfe-code {
font-family: var(--lfe-code-font, monospace);
font-size: .875em;
background-color: #fafafa;rgb(51,152,219);
border: 1px solid #e8e8e8;
border-radius: 2px;
margin: 0;
padding: .375em .5em;
overflow: auto;
}
.io-sample-block {
flex: 1 1 0;
min-width: 280px;
margin: .5em .25em
}
.io-sample-block::after {
content: "";
display: table;
clear: both;
}
.io-sample {
display: flex;
flex-flow: row wrap;
}
button, [type="button"] {
-webkit-appearance: button;
}
.btn {
float: right;
height: 30px;
background-color: rgb(96, 165, 250);
color: white;
margin: 10px;
border: 1px solid rgb(96, 165, 250);
border-radius: 4px;
cursor: pointer;
}
.btn:hover {
background-color:rgba(96, 165, 250, 0.8);
}
.text {
float: left;
margin: 5px;
font-size: 20px;
}
.modal {
display: none;
position: fixed;
z-index: 9999;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.4);
pointer-events: auto;
}
.modal-content {
background-color: #fefefe;
margin: 10% auto;
padding: 20px;
height: 305px;
border-radius: 4px;
border: 1px solid #888;
width: 50%;
}
.check-box {
float: right !important;
margin: 5px;
height: 20px;
width: 20px;
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
.card {
background-color: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
border-radius: 4px;
margin-bottom: 10px;
margin-left: 30px;
margin-right: 30px;
height: 30px;
padding-left: 30px;
padding-right: 30px;
padding-top: 10px;
padding-bottom: 10px;
}
.in-card {
border: none;
height: 30px;
}
.my-li {
float: right;
color: rgba(0, 0, 0, 0);
}
.my-li:hover {
background: rgba(0, 0, 0, 0) !important;
}
.like-btn {
cursor: pointer;
}
.like-list {
max-height: 120px;
height: 120px;
width: 600px;
overflow-y: auto;
font-size: 18px;
display: flex;
flex-wrap: wrap;
gap: 12px;
padding: 0;
margin: 2px 0;
border-color: rgb(228, 228, 228);
border-width: 2px;
}
.like-list-item {
flex: 1 1 calc(50% - 12px);
min-width: 200px;
width: 550px;
background: #f8f9fa;
border-radius: 8px;
padding: 15px;
box-sizing: border-box;
margin: 10px;
cursor: pointer;
}
`);
}
function getSampleIn() {
try {
var element = document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-content > dd:nth-child(8) > pre");
if (!element) {
console.warn("未找到样例输入元素");
return [];
}
var str = element.innerHTML;
if (!str || str.trim().length === 0) {
return [];
}
const pattern = /(?:样例输入\d*|Sample Input \d*|输入#\d*|【输入#\d*】|\[输入#\d*\]|样例输出\d*|Sample Output \d*|输出#\d*|【输出#\d*】|\[输出#\d*\])\s*\n(?:[-=_]+\s*\n)?([\s\S]*?)(?=\s*(?:样例输入\d*|Sample Input \d*|输入#\d*|【输入#\d*】|\[输入#\d*\]|样例输出\d*|Sample Output \d*|输出#\d*|【输出#\d*】|\[输出#\d*\]|$))/gi;
const blocks = [];
let match;
while ((match = pattern.exec(str)) !== null) {
let content = match[1] || "";
if (match[0].match(/(?:样例输入\d*|Sample Input \d*|输入#\d*|【输入#\d*】|\[输入#\d*】)/i)) {
content = content.replace(/^[-=_]+\s*\n/, '');
content = content.replace(/^\s+|\s+$/g, '');
if (content) {
blocks.push(content);
}
}
}
if (blocks.length === 0) {
const content = str.replace(/^\s+|\s+$/g, '');
if (content) {
blocks.push(content);
}
}
return blocks;
} catch (error) {
console.error("获取样例输入时出错:", error);
return [];
}
}
function getSampleOut() {
try {
var element = document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-content > dd:nth-child(10) > pre");
if (!element) {
console.warn("未找到样例输出元素");
return [];
}
var str = element.innerHTML;
if (!str || str.trim().length === 0) {
return [];
}
const pattern = /(?:样例输入\d*|Sample Input \d*|输入#\d*|【输入#\d*】|\[输入#\d*\]|样例输出\d*|Sample Output \d*|输出#\d*|【输出#\d*】|\[输出#\d*\])\s*\n(?:[-=_]+\s*\n)?([\s\S]*?)(?=\s*(?:样例输入\d*|Sample Input \d*|输入#\d*|【输入#\d*】|\[输入#\d*\]|样例输出\d*|Sample Output \d*|输出#\d*|【输出#\d*】|\[输出#\d*\]|$))/gi;
const blocks = [];
let match;
while ((match = pattern.exec(str)) !== null) {
let content = match[1] || "";
if (match[0].match(/(?:样例输出\d*|Sample Output \d*|输出#\d*|【输出#\d*】|\[输出#\d*】)/i)) {
content = content.replace(/^[-=_]+\s*\n/, '');
content = content.replace(/^\s+|\s+$/g, '');
if (content) {
blocks.push(content);
}
}
}
if (blocks.length === 0) {
const content = str.replace(/^\s+|\s+$/g, '');
if (content) {
blocks.push(content);
}
}
return blocks;
} catch (error) {
console.error("获取样例输出时出错:", error);
return [];
}
}
function writePassword(password) {
checkRSAAndFixed();
GM_setValue("密码", encrypt(password));
}
function lookPassword() {
checkRSAAndFixed();
return decrypt(GM_getValue("密码", ""));
}
function initKeyAndSalt() {
var crypt = new JSEncrypt({ default_key_size: 2048 });
GM_setValue("privateKey", crypt.getPrivateKey());
GM_setValue("publicKey", crypt.getPublicKey());
GM_setValue("salt", generateCustomSalt());
}
function checkRSAAndFixed() {
const privateKey = GM_getValue("privateKey", undefined);
const publicKey = GM_getValue("publicKey", undefined);
const salt = GM_getValue("salt", undefined);
if ((!(publicKey && (publicKey.includes('-----BEGIN PUBLIC KEY-----')))) ||
(!(privateKey && (privateKey.includes('-----BEGIN RSA PRIVATE KEY-----') || privateKey.includes('-----BEGIN PRIVATE KEY-----')))) ||
(!(salt))) {
initKeyAndSalt();
var newPassword = prompt("出了一点问题,请重新输入您的OpenJudge密码:");
writePassword(newPassword);
}
}
function getProblemId() {
return document.querySelector("#pagebody > div > div.problem-statistics.col-3 > dl > dd:nth-child(2)").innerHTML;
}
function getTime(){
var num, parent = document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-params");
if (parent.children.length === 6) {
num = 4;
} else {
num = 2;
}
var time = document.querySelector(`#pagebody > div > div.problem-page.col-9 > dl.problem-params > dd:nth-child(${num})`).innerHTML;
return parseInt(time) + 1000;
}
function getMemory() {
var num, parent = document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-params");
if (parent.children.length === 6) {
num = 6;
} else {
num = 4;
}
var Memory = document.querySelector(`#pagebody > div > div.problem-page.col-9 > dl.problem-params > dd:nth-child(${num})`).innerHTML;
return parseInt(Memory) / 1024;
}
function getContestName() {
return document.querySelector("#header > div > div.contest-title-tab > h2:nth-child(3)").innerHTML;
}
function getContestId() {
return location.href.split('/')[3];
}
function getProblemIdInContest() {
return location.href.split('/')[4];
}
function TRemoveElement(element) {
if (element) element.remove();
}
function addTitle() {
var place = document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-content > dd:nth-child(6)");
var title = document.createElement("dt");
title.innerHTML = '输入输出样例';
place.after(title);
}
function copyToClipboard(text, element) {
try {
GM_setClipboard(text, 'text');
if (element) {
const originalText = element.textContent;
element.textContent = '复制成功';
setTimeout(() => {
element.textContent = originalText;
}, 500);
}
} catch (err) {
console.error('复制失败:', err);
if (element) {
element.textContent = '复制失败';
}
}
}
function addSample(inarray, outarray) {
var place = document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-content > dd:nth-child(6)");
for (let i = 0; i < inarray.length; i++) {
var div = document.createElement('div');
var inputdiv = document.createElement('div');
var outputdiv = document.createElement('div');
var inputp = document.createElement('p');
var outputp = document.createElement('p');
var inputbtn = document.createElement('button');
var outputbtn = document.createElement('button');
var inputdata = document.createElement('pre');
var outputdata = document.createElement('pre');
inputdata.className = 'lfe-code';
outputdata.className = 'lfe-code';
inputdata.innerText = inarray[i];
outputdata.innerText = outarray[i];
inputbtn.className = 'lform-size-small';
outputbtn.className = 'lform-size-small';
inputbtn.setAttribute('type', 'button');
outputbtn.setAttribute('type', 'button');
inputbtn.innerHTML = '复制';
outputbtn.innerHTML = '复制';
inputbtn.className = 'lform-size-small';
outputbtn.className = 'lform-size-small';
inputp.innerHTML = '输入 #' + (i + 1) + '';
outputp.innerHTML = '输出 #' + (i + 1) + '';
inputp.className = 'lfe-caption';
outputp.className = 'lfe-caption';
inputdiv.className = 'io-sample-block';
outputdiv.className = 'io-sample-block';
div.className = 'io-sample';
div.appendChild(inputdiv);div.appendChild(outputdiv);
inputdiv.appendChild(inputp);inputdiv.appendChild(inputdata);
inputp.appendChild(inputbtn);
outputdiv.appendChild(outputp);outputdiv.appendChild(outputdata);
outputp.appendChild(outputbtn);
place.after(div);
place = div;
inputbtn.addEventListener('click', function () {
const code = inarray[i];
copyToClipboard(code, this);
});
outputbtn.addEventListener('click', function () {
const code = outarray[i];
copyToClipboard(code, this);
});
}
}
function removeElements() {
Promise.all([
TRemoveElement(document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-content > dt:nth-child(7)")),
TRemoveElement(document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-content > dd:nth-child(7)")),
TRemoveElement(document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-content > dt:nth-child(7)")),
TRemoveElement(document.querySelector("#pagebody > div > div.problem-page.col-9 > dl.problem-content > dd:nth-child(7)"))
]);
}
function addbtn(inarray, outarray) {
const cphBtn = document.createElement('button');
cphBtn.className = 'btn';
cphBtn.href = 'javascript:void(0)';
cphBtn.innerHTML = '传送至CPH';
var tests=[];
for (let i = 0; i < inarray.length; i++) {
tests.push({'input': inarray[i], 'output': outarray[i]});
}
cphBtn.addEventListener('click', function() {
const cphData = {
name: `${getContestId()} ${getProblemIdInContest()} ${getProblemId()}`,
group: `${getContestName()} ${getContestId()}`,
url: window.location.href,
memoryLimit: getMemory(),
timeLimit: getTime(),
tests: tests,
testType: "single",
input: { type: "stdin" },
output: { type: "stdout" }
};
Promise.all([
sendToCPH(cphData)
]);
});
document.querySelector("#topMenu > ul").after(cphBtn);
}
function sendToCPH(data) {
var url = 'http://localhost:';
if (GM_getValue('CPH端口下拉框') == 'custom') {
url += GM_getValue('CPH自定义端口');
} else {
url += GM_getValue('CPH端口下拉框');
}
url += '/';
GM_xmlhttpRequest({
method: 'POST',
url: url,
headers: {
'Content-Type': 'application/json'
},
data: JSON.stringify(data),
onload: function(response) {
console.log(response);
if (response.statusText !== "Accepted" && response.statusText !== "OK" && response.status !== 200) {
alert(`错误\nCPH插件返回错误: ${response.statusText || '无响应'}`);
}
},
onerror: function(error) {
alert('传送失败\n请检查是否打开软件或插件');
},
ontimeout: function() {
alert('传送超时\n请检查软件或插件是否运行');
}
});
}
function changeSampleAndAddCphBtn(isChangSample, isAddCphBtn) {
var inarray = getSampleIn(), outarray = getSampleOut();
if (isChangSample) {
Promise.all([
removeElements(),
addSample(inarray, outarray),
addTitle()
]);
}
if (isAddCphBtn) {
Promise.all([
addbtn(inarray, outarray)
]);
}
}
function inProblemPage() {
var pattern = /^http[s]?:\/\/[^\.]*\.openjudge\.cn\/[^\/]+\/\S+\/(\?lang=\S+)?$/g;
var url = location.href;
if (pattern.test(url) && document.querySelector("#mainNav > li:nth-child(1)").className === "current") {
Promise.all([
changeSampleAndAddCphBtn(GM_getValue("优化样例"), (GM_getValue("CPH端口下拉框") !== ""))
]);
}
}
function addContent(modalContent) {
var enter=document.createElement('br');
var div1=document.createElement('div');
div1.className='card';
var text1=document.createElement('p');
text1.innerHTML='优化样例';
text1.className='text';
var checkbox1=document.createElement('input');
checkbox1.type='checkbox';
checkbox1.className='check-box';
checkbox1.id='change-sample';
div1.appendChild(text1);
div1.appendChild(checkbox1);
modalContent.appendChild(div1);
var div2=document.createElement('div');
div2.className='card';
div2.style.height='60px';
var div21=document.createElement('div');
div21.className='in-card';
var text21=document.createElement('p');
text21.innerHTML='CPH端口';
text21.className='text';
var select2=document.createElement('select');
select2.id='cph-port-select';
select2.style.float='right';
select2.innerHTML=`
`;
var div22=document.createElement('div');
div22.className='in-card';
var text22=document.createElement('p');
text22.innerHTML='端口';
text22.className='text';
var input2=document.createElement('input');
input2.type='number';
input2.id='cph-port';
input2.style.float="right";
div21.appendChild(text21);
div21.appendChild(select2);
div22.appendChild(text22);
div22.appendChild(input2);
div2.appendChild(div21);
div2.appendChild(div22);
modalContent.appendChild(div2);
var div3=document.createElement('div');
div3.className='card';
var div31=document.createElement('div');
div31.className='in-card';
var text31=document.createElement('p');
text31.innerHTML='自动登录';
text31.className='text';
var checkbox31=document.createElement('input');
checkbox31.type='checkbox';
checkbox31.className='check-box';
checkbox31.id='auto-login';
var div32=document.createElement('div');
div32.className='in-card';
var text32=document.createElement('p');
text32.innerHTML='账号';
text32.className='text';
var checkbox32=document.createElement('input');
checkbox32.type='string';
checkbox32.className='check-box';
checkbox32.id='name';
checkbox32.size=20;
checkbox32.style.width='300px';
checkbox32.placeholder='电子邮箱';
var div33=document.createElement('div');
div33.className='in-card';
var text33=document.createElement('p');
text33.innerHTML='密码';
text33.className='text';
var checkbox33=document.createElement('input');
checkbox33.type='password';
checkbox33.className='check-box';
checkbox33.id='password';
checkbox33.size=20;
checkbox33.style.width='300px';
checkbox33.placeholder='密码';
div3.style.height='90px';
div31.appendChild(text31);
div31.appendChild(checkbox31);
div32.appendChild(text32);
div32.appendChild(checkbox32);
div33.appendChild(text33);
div33.appendChild(checkbox33);
div3.appendChild(div31);
div3.appendChild(div32);
div3.appendChild(div33);
modalContent.appendChild(div3);
var btn1=document.createElement('button');
var btn2=document.createElement('button');
btn2.className='btn';
btn2.innerHTML='保存';
btn1.className='btn';
btn1.innerHTML='重置所有配置';
btn1.addEventListener('click', function(){
let result = confirm('确定重置所有配置?');
if (result) {
const keys = GM_listValues();
console.log(keys);
keys.forEach(key => GM_deleteValue(key));
initGM();
location.reload();
}
});
btn2.addEventListener('click', function() {
let result = confirm('确定保存?');
if (result) {
save();
location.reload();
}
});
modalContent.appendChild(btn1);
modalContent.appendChild(btn2);
}
function save() {
var checkbox1 = document.querySelector("#change-sample");
var select2 = document.querySelector("#cph-port-select");
var input2 = document.querySelector("#cph-port");
var checkbox3 = document.querySelector("#auto-login");
var input31 = document.querySelector("#name");
var input32 = document.querySelector("#password");
GM_setValue("优化样例", checkbox1.checked);
GM_setValue("CPH端口下拉框", select2.value);
GM_setValue("CPH自定义端口", input2.value);
GM_setValue("自动登录", checkbox3.checked);
GM_setValue("账号", input31.value);
writePassword(input32.value);
}
function initCheckbox() {
var checkbox1 = document.querySelector("#change-sample");
var select2 = document.querySelector("#cph-port-select");
var input2 = document.querySelector("#cph-port");
var checkbox3 = document.querySelector("#auto-login");
var input31 = document.querySelector("#name");
var input32 = document.querySelector("#password");
checkbox1.checked = GM_getValue('优化样例');
select2.value = GM_getValue("CPH端口下拉框");
input2.value = GM_getValue("CPH自定义端口");
checkbox3.checked = GM_getValue('自动登录');
input31.value = GM_getValue('账号');
input32.value = lookPassword();
}
function close(modal) {
var checkbox1 = document.querySelector("#change-sample");
var select2 = document.querySelector("#cph-port-select");
var input2 = document.querySelector("#cph-port");
var checkbox3 = document.querySelector("#auto-login");
var input31 = document.querySelector("#name");
var input32 = document.querySelector("#password");
var flag = checkbox1.checked === GM_getValue("优化样例") &&
select2.value == GM_getValue("CPH端口下拉框") &&
input2.value == GM_getValue("CPH自定义端口") &&
checkbox3.checked === GM_getValue("自动登录") &&
input31.value === GM_getValue("账号") &&
input32.value === lookPassword();
if (!flag) {
let result = confirm('配置已更改,是否保存?');
if (result) {
save();
location.reload();
}
}
modal.style.display="none";
}
function addSetBtn(place) {
var modal=document.createElement('div');
var modalContent=document.createElement('div');
modal.className='modal';
modalContent.className='modal-content';
modalContent.innerHTML=`×`;
addContent(modalContent);
modal.appendChild(modalContent);
document.querySelector("html > body").appendChild(modal);
Promise.all([
initCheckbox()
]);
var setbtn=document.createElement('button');
setbtn.className = 'btn';
setbtn.href = 'javascript:void(0)';
setbtn.innerHTML = 'OpenJudge Better! 设置';
setbtn.addEventListener('click', function() {
modal.style.display="block";
Promise.all([
initCheckbox()
]);
});
document.getElementById('close').addEventListener('click', function() {
Promise.all([
close(modal)
]);
});
var div=document.createElement('div');
div.appendChild(setbtn);
place.after(div);
}
function addSetBtnInHomePage () {
Promise.all([
addSetBtn(document.querySelector("#topsearch"))
]);
}
function autoLogin() {
document.querySelector("#email").value = GM_getValue("账号");
document.querySelector("#password").value = lookPassword();
document.querySelector("#main > form > div.user-login > p:nth-child(2) > button").click();
console.log(document.querySelector("#main > form > div.user-login > p:nth-child(2) > button").addEventListener);
}
function autoLoginInHomePage() {
if (document.querySelector("#userMenu > li:nth-child(4) > a").innerHTML === "登入") {
location.href = `http://openjudge.cn/auth/login?url=${location.href}`;
}
}
function autoLoginInOtherPage() {
if (document.querySelector("#userToolbar > li:nth-child(1) > a").innerHTML === "登入") {
location.href = `http://openjudge.cn/auth/login?url=${location.href}`;
}
}
function addLikeList() {
var place = document.querySelector("#main");
const list = JSON.parse(GM_getValue("likeList"), "[]");
var div1 = document.createElement("div");
var div2 = document.createElement("div");
var ul = document.createElement("ul");
var p = document.createElement("p");
p.innerHTML = "收藏列表";
p.style.marginBottom = "0";
p.style.fontSize = "17px";
p.style.fontWeight = "bold";
div1.className = "like-list";
for (const {url, name} of list) {
var li = document.createElement("li");
li.innerHTML = `${name}`;
li.className = 'like-list-item';
li.addEventListener('click', function() {
location.href = url;
});
ul.appendChild(li);
}
div1.appendChild(ul);
div2.appendChild(p);
div2.appendChild(div1);
place.appendChild(div2);
}
function inAllPage() {
var pattern = /^http[s]?:\/\/openjudge\.cn\S*$/;
var url = location.href;
if (pattern.test(url)) {
var pattern2 = /^http[s]?:\/\/openjudge\.cn\/?$/;
if (pattern2.test(url) && GM_getValue("likeList") !== "[]") {
document.querySelector("#main > div.contest-running").style.height = "90px";
Promise.all([
addLikeList()
]);
}
Promise.all([
addSetBtnInHomePage()
]);
if (GM_getValue("自动登录")) {
Promise.all([
autoLoginInHomePage(),
]);
}
} else {
if (GM_getValue("自动登录")) {
Promise.all([
autoLoginInOtherPage()
]);
}
}
}
function initGM() {
if (!GM_getValue("优化样例")) {
GM_setValue("优化样例", false);
}
if (!GM_getValue("CPH端口下拉框")) {
GM_setValue("CPH端口下拉框", "");
}
if (!GM_getValue("CPH自定义端口")) {
GM_setValue("CPH自定义端口", "");
}
if (!GM_getValue("自动登录")) {
GM_setValue("自动登录", false);
}
if (!GM_getValue("账号")) {
GM_setValue("账号", "");
}
if (!GM_getValue("密码")) {
GM_setValue("密码", "");
initKeyAndSalt();
}
if (!GM_getValue("likeList")) {
GM_setValue("likeList", JSON.stringify([]));
}
}
function Login() {
if (GM_getValue("自动登录")) {
var parttern = /^http[s]?:\/\/[^\s\.]*\.cn\/auth\/login((\?url=\S+)?|\/?)$/, url = location.href;
if (parttern.test(url)) {
const match = url.match(/url=([^&\s]+)/i);
var str;
if (match) {
str = match[1];
} else {
str = "http://openjudge.cn/";
}
GM_setValue("登录后要回到的界面", str);
autoLogin();
}
}
}
function autoReload() {
setTimeout(() => {
if (document.querySelector("#main\\\" > p > a").innerText == 'Waiting') {
document.querySelector("#main\\\" > p > a").click();
}
}, 750);
}
function inSolutionPage() {
var parttern = /^http[s]?:\/\/[^\.]+\.openjudge\.cn\/[^\/]+\/solution\/\d+\/$/, url = location.href;
if (parttern.test(url)) {
autoReload();
}
}
function addLikeBtn(place) {
console.log(place);
function getUrl() {
return location.href.match(/^([^\/]*\/){0,3}[^\/]*(?=\/|$)/)[0] + '\/';
}
function getName() {
return document.querySelector("#header > div > div.contest-title-tab > h2:nth-child(3)").innerHTML;
}
function getItems() {
return JSON.parse(GM_getValue("likeList", "[]"));
}
function addItem(newItem) {
const currentArray = JSON.parse(GM_getValue("likeList", "[]"));
currentArray.push(newItem);
GM_setValue("likeList", JSON.stringify(currentArray));
}
function findItems(criteria) {
const currentArray = JSON.parse(GM_getValue("likeList", "[]"));
return currentArray.find(item =>
Object.keys(criteria).every(key =>
item[key] === criteria[key]
)
);
}
function removeItems(criteria) {
let items = JSON.parse(GM_getValue("likeList", "[]"));
const initialCount = items.length;
items = items.filter(item =>
!Object.keys(criteria).every(key =>
criteria[key] === "" ||
item[key] === criteria[key]
)
);
const removedCount = initialCount - items.length;
if (removedCount > 0) {
GM_setValue("likeList", JSON.stringify(items));
}
return removedCount;
}
var span = document.createElement("span");
span.innerHTML = `
`;
place.after(span);
const icon = document.getElementById('favoriteIcon');
const url = getUrl(), name = getName();
function filled(isFilled) {
icon.querySelector('path').setAttribute('fill', isFilled ? '#FFD700' : 'none');
icon.querySelector('path').setAttribute('stroke', isFilled ? '#FFA500' : '#666');
}
let isFilled = false;
if (findItems({url, name})) {
isFilled = !isFilled;
filled(isFilled);
}
icon.addEventListener('click', () => {
isFilled = !isFilled;
filled(isFilled);
if (isFilled) {
addItem({url, name});
} else {
removeItems({url, name});
}
});
}
function inContestPage() {
var pattern = /^http[s]?:\/\/[^\.]+\.openjudge\.cn\/[^\/]+\/(\S+)?$/, url = location.href;
if (pattern.test(url) && document.querySelector("#header > div > div.contest-title-tab > span:nth-child(4)")) {
console.log("contest Page");
addLikeBtn(document.querySelector("#header > div > div.contest-title-tab > span:nth-child(4)"));
} else if (pattern.test(url)) {
addLikeBtn(document.querySelector("#header > div > div.contest-title-tab > h2:nth-child(3)"));
}
}
function addCommand() {
GM_registerMenuCommand("反馈", function(){
window.open(feedbackUrl);
});
}
function compareVersion(version1 = "0", version2 = "0") {
const v1Array = version1.split(".").map(Number);
const v2Array = version2.split(".").map(Number);
const length = Math.max(v1Array.length, v2Array.length);
for (let i = 0; i < length; i++) {
const diff = (v1Array[i] || 0) - (v2Array[i] || 0);
if (diff) return Math.sign(diff);
}
return 0;
}
function extractVersion(scriptContent) {
const versionMatch = scriptContent.match(/\/\/ @version\s+([^\n]+)/);
return versionMatch ? versionMatch[1].trim() : null;
}
function UpdateTo_0_14_0() {
var password = GM_getValue("密码", "");
initKeyAndSalt();
writePassword(password);
}
function checkVersionAndUpdate() {
if (GM_getValue("NowVersion", undefined) == undefined) {
GM_setValue("NowVersion", GM_info.script.version);
}
if (compareVersion(GM_getValue("NowVersion"), "0.14.0") == -1 && compareVersion(GM_info.script.version, "0.14.0") >= 0 && GM_getValue("version0.14.0", false) == false) {
console.log("Update to 0.14.0");
GM_setValue("version0.14.0", true);
UpdateTo_0_14_0();
}
if (compareVersion(GM_info.script.version, extractVersion(GM_getResourceText("script"))) == -1) {
if(confirm(`有新版本,是否更新(版本号:${extractVersion(GM_getResourceText("script"))})`)) {
window.open(scriptUrl);
}
}
}
function main() {
Promise.all([
addCommand(),
Login(),
inSolutionPage(),
inContestPage(),
initGM(),
addcss(),
inProblemPage(),
inAllPage()
]);
}
function goBack() {
if (GM_getValue("登录后要回到的界面")) {
var Url = GM_getValue("登录后要回到的界面");
GM_deleteValue("登录后要回到的界面");
if (location.href != Url) {
location.href = Url;
}
}
}
function waitHtmlAndWorkMain() {
const wait = setInterval(() => {
const place = document.querySelector("html");
if (place) {
clearInterval(wait);
main();
}
}, 500);
}
(function() {
'use strict';
checkVersionAndUpdate()
Promise.all([
goBack(),
waitHtmlAndWorkMain()
]);
})();