// ==UserScript== // @name CodeForces Plus VScode CPH // @namespace http://tampermonkey.net/ // @version 0.1.0 // @author Andy_hpy // @icon https://codeforces.com/codeforces.org/s/46083/favicon-32x32.png // @description 将 CodeForces 题目测试用例发送到VS Code的CPH插件 // @match https://codeforces.com/contest/*/problem/* // @match https://codeforces.com/problemset/problem/*/* // @match https://codeforces.com/gym/*/problem/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect localhost // @run-at document-start // ==/UserScript== async function addcss() { GM_addStyle(` .cgh-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; } .cgh-btn:hover { background-color:rgba(96, 165, 250, 0.8); } .cgh-panel { font-size: initial; float: initial; cursor: initial; border: none; margin: 0px; line-height: initial; text-transform: none; display: flex; justify-content: flex-end; align-items: center; gap: 6px; padding: 5px 0px !important; }`); } async function addbtn() { document.querySelector("#pageContent > div.diff-popup").insertAdjacentHTML('afterend', `
`); const cphBtn = document.querySelector("#cgh-to-cph"); cphBtn.addEventListener('click', async function () { let input = [], output = [], test = []; document.querySelectorAll(".input > pre").forEach(pre => { let sample = ''; pre.childNodes.forEach(item => { sample += item.textContent + "\n"; }); if (sample.endsWith('\n')) { sample = sample.slice(0, -1); } input.push(sample); }); document.querySelectorAll(".output > pre").forEach(pre => { let sample = ''; pre.childNodes.forEach(item => { sample += item.textContent + "\n"; }); if (sample.endsWith('\n')) { sample = sample.slice(0, -1); } output.push(sample); }); for (let i = 0; i < Math.min(input.length, output.length); i++) { test.push({ 'input': input[i], 'output': output[i] }); } let name = 'CF'; name += location.href.split('/')[4] + location.href.split('/')[6]; let time = parseFloat( document.querySelector("#pageContent > div.problemindexholder > div.ttypography > div > div.header > div.time-limit") .textContent .replace(/[^\d\.]/g, "") ) * 1000 + 1000; let mem = parseInt( document.querySelector("#pageContent > div.problemindexholder > div.ttypography > div > div.header > div.memory-limit") .textContent .replace(/[^\d\.]/g, "") ); const data = { name: name, group: 'CF' + location.href.split('/')[4], tests: test.map((t, idx) => ({ ...t, id: idx })), url: location.href, memoryLimit: mem, timeLimit: time, testType: "single", input: { type: "stdin" }, output: { type: "stdout" }, languages: { java: { mainClass: "Main", taskClass: "" } }, batch: { id: crypto.randomUUID(), size: 1 } }; if (location.href.includes('/gym/')) { data.name = 'Gym' + location.href.split('/')[4] + location.href.split('/')[6]; data.group = 'Gym' + location.href.split('/')[4]; } sendToCPH(data); }); } function sendToCPH(data) { const port = 27121; GM_xmlhttpRequest({ method: 'POST', url: `http://localhost:${port}/`, headers: { 'Content-Type': 'application/json' }, data: JSON.stringify(data), onload: function (response) { if (response.status !== 200) { alert(`错误:CPH 返回状态码 ${response.status}`); } }, onerror: function () { alert(`连接失败\n请确认 CPH 插件已启动,且端口为 ${port}`); }, ontimeout: function () { alert('连接超时,请检查插件状态'); } }); } async function main() { addcss() addbtn() } async function waitHtmlAndWorkMain() { const wait = setInterval(async () => { const place = document.querySelector("html"); if (place) { clearInterval(wait); main(); } }, 500); } waitHtmlAndWorkMain();