// ==UserScript== // @name AtCoder Plus VScode CPH // @namespace http://tampermonkey.net/ // @version 6.0.0 // @author Andy_hpy // @icon https://aowuucdn.oss-accelerate.aliyuncs.com/atcoder.png // @description 将AtCoder题目测试用例发送到VS Code的CPH插件 // @match https://atcoder.jp/contests/*/tasks/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect 127.0.0.1 // @connect localhost // ==/UserScript== async function addcss() { GM_addStyle(` button.cgh-btn { float: right; height: 30px; background: #f72585; color: white; margin: 10px; border: 1px solid #f72585; cursor: pointer; transition: all 0.3s ease; border-radius: 3px; } button.cgh-btn:hover { background: #f50057; border-color: #f50057; } `); } async function getSample() { let sample = [], l = undefined; document.querySelectorAll("span.lang-en > div.part > section > div.div-btn-copy + pre[id^='pre-sample']").forEach(async (pre) => { if (l) { sample.push({ 'input': l, 'output': pre.textContent.trim() }); l = undefined; } else { l = pre.textContent.trim(); } }); return sample; } async function getData() { const pathParts = window.location.pathname.split('/'); const contestId = pathParts[2]; const problemId = pathParts[4]; const test = await getSample(); const mem = document.querySelector("#main-container > div.row > div:nth-child(3) > p").textContent.match(/(\d+)/g)[1]; const time = document.querySelector("#main-container > div.row > div:nth-child(3) > p").textContent.match(/(\d+)/g)[0]; const data = { name: contestId.replace(/\d+/g, '').toUpperCase() + " " + contestId.match(/\d+/g)[0] + " " + problemId.split('_').pop().toUpperCase(), group: contestId.replace(/\d+/g, '').toUpperCase() + " " + contestId.match(/\d+/g)[0], tests: test.map((t, idx) => ({ ...t, id: idx })), url: window.location.href, memoryLimit: parseInt(mem), timeLimit: parseInt(time) * 1000, testType: "single", input: { type: "stdin" }, output: { type: "stdout" }, languages: { java: { mainClass: "Main", taskClass: "" } }, batch: { id: crypto.randomUUID(), size: 1 } }; return data; } async function addbtn() { const btn = document.createElement('button'); btn.href = 'javascript:void(0)'; btn.innerHTML = '传送至CPH'; btn.className = 'cgh-btn'; btn.id = 'cgh-to-cph'; btn.addEventListener('click', async () => { const data = await getData(); console.log(data); console.log('Data to send:', JSON.stringify(data, null, 2)); sendToCPH(data); }); document.querySelector('.nav.navbar-nav.navbar-right').appendChild(btn); } async function main() { addcss(); addbtn(); } 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 waitHtmlAndWorkMain() { const wait = setInterval(async () => { const place = document.querySelector("html"); if (place) { clearInterval(wait); main(); } }, 500); } waitHtmlAndWorkMain();