您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
gym做题信息统计
// ==UserScript== // @name Codeforces Gym Statistic // @namespace http://tampermonkey.net/ // @version 1.0 // @description gym做题信息统计 // @author Tanphoon // @match https://codeforces.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=codeforces.com // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; const pathname = window.location.pathname; console.log(pathname); if (pathname.startsWith("/contests/with/")) { gymAnalyze(); } function gymAnalyze() { const handle = pathname.substring(pathname.lastIndexOf('/') + 1, pathname.length); // 定义请求的URL const userDataUrl = `https://codeforces.com/api/user.status?handle=${handle}`; const contestListUrl = 'https://codeforces.com/api/contest.list?gym=true'; // 使用fetch函数获取JSON数据,并将其转换为JSON对象 async function fetchData(url) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); } catch (error) { console.error(`Fetch error for ${url}: `, error); throw error; } }; async function getContestData() { const today = new Date().toLocaleDateString(); // 比赛信息 let contestData = {}; if (!localStorage.getItem("ContestDataVersion") || localStorage.getItem("ContestDataVersion") != today) { try { const contestList = await fetchData(contestListUrl); contestList.result.forEach(item => { contestData[item.id] = item.name; }); localStorage.setItem("ContestDataVersion", today); localStorage.setItem("ContestData", JSON.stringify(contestData)); } catch (error) { console.error("An error occurred while fetching data:", error); } } else { contestData = JSON.parse(localStorage.getItem("ContestData")); } return contestData; } async function main() { const contestData = await getContestData(); const userData = await fetchData(userDataUrl); let data = {}; userData.result.forEach(item => { // 提取所需字段 const commitId = item.id; const contestId = item.contestId; const time = new Date(item.creationTimeSeconds * 1000).toLocaleString(); const verdict = item.verdict; const problemId = item.problem.index; if (contestId > 100000) { if (!data[contestId]) { data[contestId] = { 'name': contestData[contestId], 'correct': [], 'problem': {}, }; } // 通过的题目 if (verdict == "OK" && !data[contestId]['correct'].includes(problemId)) data[contestId]['correct'].push(problemId); // 题目提交信息 if (!data[contestId]['problem'][problemId]) { data[contestId]['problem'][problemId] = []; } data[contestId]['problem'][problemId].push({ commitId, time, verdict }); } }); // 用户信息 drawTable(data); console.log(data); } function drawTable(data) { const facebox = document.createElement('style'); facebox.textContent = ` .popup { display: none; position: fixed; z-index: 99; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0, 0, 0, 0.4); } .popup-content { background-color: #fefefe; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 10px; width: 50%; border-radius: 5px; } .close { color: #aaa; float: right; font-size: 28px; font-weight: bold; } .close:hover, .close:focus { color: black; text-decoration: none; cursor: pointer; } .content { border: 1px solid #888; padding: 20px; border-radius: 5px; } #gym th, td { cursor: pointer; } `; document.head.appendChild(facebox); let datatable = ` <div id="gyms" class="datatable" style="background-color: #E1E1E1; padding-bottom: 3px;"> <div class="lt"> </div> <div class="rt"> </div> <div class="lb"> </div> <div class="lb"> </div> <div style="padding: 4px 0 0 6px;font-size:1.4rem;position:relative;">Gyms</div> <div style="background-color: white;margin:0.3em 3px 0 3px;position:relative;"> <div class="ilt"> </div> <div class="irt"> </div> <table class="tablesorter user-contests-table"> <thead> <tr> <th class="top left">#</th> <th class="top">Contest</th> ${Array.from("ABCDEFGHIJKLM").map(problemId => `<th class="top">${problemId}</th>`).join('')} <th class="top right">Solved</th> </tr> </thead> <tbody> ${Object.keys(data).map((contestId, index) => ` <tr> <td>${index + 1}</td> <td><a href="/gym/${contestId}">${data[contestId]['name']}</a></td> ${Array.from("ABCDEFGHIJKLM").map(problemId => { const correct = data[contestId]['correct'].includes(problemId); const style = correct ? "font-weight: bold;color:#0a0" : "color:#00a"; if (data[contestId]['problem'][problemId]) { return ` <td style="${style}" problemid=${problemId}> ${correct ? '+' : '-'}${data[contestId]['problem'][problemId].length} </td>`; } else { return `<td problemid=${problemId}></td>`; } }).join('')} <td>${Object.keys(data[contestId]['problem']).length}</td> </tr> `).join('')} </tbody> </table> </div> </div> `; let contests = document.querySelector("#pageContent > .datatable"); contests.insertAdjacentHTML("afterend", datatable); let gyms = document.querySelector("#pageContent > #gyms"); contests.style.display = 'block'; gyms.style.display = 'none'; document.querySelector("#pageContent > div.second-level-menu > ul > li.current.selectedLava").insertAdjacentHTML("afterend", "<li><a id='toggleButton' style='cursor: pointer;'>SWITCH TO GYMS</a></li>") const toggleButton = document.getElementById('toggleButton'); toggleButton.addEventListener('click', () => { if (contests.style.display === 'none') { contests.style.display = 'block'; gyms.style.display = 'none'; toggleButton.textContent = 'SWITCH TO GYMS'; } else { contests.style.display = 'none'; gyms.style.display = 'block'; toggleButton.textContent = 'SWITCH TO COMTESTS'; } }); let popdiv = ` <div id="mypopup" class="popup"> <div class="popup-content"> <span class="close">×</span> <div class="content" id="popupMessage"> <h2>This is the popup content</h2> <p>You can add any content inside the popup.</p> </div> </div> </div> `; gyms.insertAdjacentHTML('afterend', popdiv); const table = document.getElementById("gyms"); const popup = document.getElementById("mypopup"); const closeBtn = document.querySelector(".close"); const popupMessage = document.getElementById("popupMessage"); const columnNames = Array.from(table.getElementsByTagName("th")).map(th => th.textContent); table.addEventListener("click", (event) => { const cell = event.target.closest("td"); if (cell) { const contestId = Object.keys(data)[cell.parentNode.rowIndex - 1]; const problemId = cell.getAttribute('problemid'); const commitInfos = data[contestId]['problem'][problemId]; if (commitInfos) { popupMessage.innerHTML = commitInfos.map(item => ` ${item.time} <span style="${item.verdict == "OK" ? "font-weight: bold;color:#0a0" : "color:#00a"}">${item.verdict == "OK" ? "Accepted" : item.verdict.replace("/^\w/", (match) => match.toUpperCase())}</span> → <a href=https://cf.dianhsu.com/gym/${contestId}/submission/${item.commitId} target="_blank">${item.commitId}</a><br> `).join(''); popup.style.display = "block"; } } }); closeBtn.addEventListener("click", () => { popup.style.display = "none"; }); popup.addEventListener("click", (event) => { if (event.target === popup) { popup.style.display = "none"; } }); } main(); } })();