// ==UserScript== // @name GenGen-RMJ-DET // @namespace http://tampermonkey.net/ // @version 5.1.1 // @author GenGen 队 // @match https://www.luogu.com.cn/record/cf/* // @match https://www.luogu.com.cn/record/at/* // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @connect codeforces.com // @connect www.luogu.com.cn // @connect atcoder.jp // @run-at document-start // @description GenGen RMJ 提交记录详情 // @license MIT // ==/UserScript== (function() { const _gmGet = GM_getValue; const _gmReq = GM_xmlhttpRequest; const VALID = [ /^https:\/\/www\.luogu\.com\.cn\/record\/cf\/[^/]+\/[^/?#]+/, /^https:\/\/www\.luogu\.com\.cn\/record\/at\/[^/]+\/[^/?#]+/, ]; if (!VALID.some(r => r.test(location.href))) return; const m = location.pathname.match(/\/record\/(cf|at)\/([^/]+)\/([^/?#]+)/); if (!m) return; const [, plat, cid, sid] = m; const isCF = plat === 'cf'; const isAT = plat === 'at'; const handle = _gmGet('cf-handle', '') || _gmGet('rmj-cf-handle', '') || ''; const code = _gmGet(`{${cid},${sid}}`, ''); const titleTimer = setInterval(() => { document.title = 'GenGen RMJ 加载中'; }, 100); const mask = document.createElement('div'); mask.id = 'rmj-mask'; mask.style.cssText = 'position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgb(239,239,239);z-index:2147483647;'; (document.documentElement || document.body || document).appendChild(mask); const CF2LG = { OK:12, WRONG_ANSWER:6, TIME_LIMIT_EXCEEDED:5, MEMORY_LIMIT_EXCEEDED:4, OUTPUT_LIMIT_EXCEEDED:3, RUNTIME_ERROR:7, COMPILATION_ERROR:2, TESTING:1, WAITING:0 }; const FINAL_CF = new Set(['OK','WRONG_ANSWER','COMPILATION_ERROR','RUNTIME_ERROR', 'TIME_LIMIT_EXCEEDED','MEMORY_LIMIT_EXCEEDED','OUTPUT_LIMIT_EXCEEDED']); const gmJson = (url) => new Promise((ok, no) => { _gmReq({ method:'GET', url, timeout:15000, anonymous:true, onload: r => { try { ok(JSON.parse(r.responseText)); } catch (e) { no(e); } }, onerror: () => no(new Error('net')), ontimeout: () => no(new Error('timeout')) }); }); const gmText = (url) => new Promise((ok, no) => { _gmReq({ method:'GET', url, timeout:15000, anonymous:true, onload: r => r.status === 200 ? ok(r.responseText) : no(new Error('status ' + r.status)), onerror: () => no(new Error('net')), ontimeout: () => no(new Error('timeout')) }); }); let cachedTpl = null; const fetchTemplate = async () => { if (cached