洛谷记录侦测练习情况

通过查看记录统计练习情况

  1. // ==UserScript==
  2. // @name 洛谷记录侦测练习情况
  3. // @version 0.3
  4. // @description 通过查看记录统计练习情况
  5. // @match https://www.luogu.com.cn/record*
  6. // @match https://www.luogu.com.cn$
  7. // @author MlkMathew
  8. // @license MIT
  9. // @grant none
  10. // @namespace https://gf.qytechs.cn/users/1068192
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15. function query_diff(dif){
  16. let res=localStorage.getItem(dif);
  17. if(!res){
  18. return 0;
  19. }
  20. return Number(res);
  21. }
  22. function work(x){
  23. if((x.pid[0]=='U'||x.pid[0]=='T')&&'0'<=x.pid[1]&&x.pid[1]<='9'){
  24. return ;
  25. }
  26. if(!localStorage.getItem(x.pid)){
  27. let now=query_diff(x.difficulty);
  28. localStorage.setItem(x.pid,true);
  29. localStorage.setItem(x.difficulty,now+1);
  30. if(!now){
  31. let arr=[x.pid];
  32. localStorage.setItem(x.difficulty.toString()+"problems",JSON.stringify(arr));
  33. }
  34. else{
  35. let arr=JSON.parse(localStorage.getItem(x.difficulty.toString()+"problems"));
  36. arr[now]=x.pid;
  37. localStorage.setItem(x.difficulty.toString()+"problems",JSON.stringify(arr));
  38. }
  39. }
  40. }
  41. var col=["#bfbfbf","#fe4c61","#f39c11","#ffc116","#52c41a","#3498db","#9d3dcf","#0e1d69"];
  42. function display(){
  43. let box=document.createElement("div");
  44. box.className="lg-article";
  45. let fat=document.querySelector("#app-old > div.lg-index-content.am-center > div:nth-child(3) > div.am-u-lg-3.am-u-md-4.lg-right");
  46. fat.children[0].insertAdjacentElement("beforebegin",box);
  47. {
  48. const res=[];
  49. for(let i=0;i<=7;i++)
  50. {
  51. res[i]=query_diff(i);
  52. }
  53. let table=document.createElement("table");
  54. table.style=
  55. "border-collapse:separate;"+
  56. "font-family:inherit;"+
  57. "font-size:1.4rem;"+
  58. "letter-spacing:0px;"+
  59. "white-space:pre-wrap;";
  60. box.appendChild(table);
  61. let thead=document.createElement("thead");
  62. {
  63. let tr=document.createElement("tr");
  64. let th=document.createElement("th");
  65. th.textContent="练习情况(已爬取的数据)";
  66. th.style="background:rgb(228,240,245);"
  67. th.colSpan="2";
  68. tr.appendChild(th);
  69. thead.appendChild(tr);
  70. }
  71. table.appendChild(thead);
  72. let tbody=document.createElement("tbody");
  73. table.appendChild(tbody);
  74. {
  75. let tr=document.createElement("tr");
  76. {
  77. let td=document.createElement("td");
  78. let problemcolor=document.createElement("span");
  79. problemcolor.textContent=" 暂无评定 ";
  80. problemcolor.style="color:rgb(255,255,255);background:rgb(191,191,191);border-radius:5px;";
  81. td.appendChild(problemcolor);
  82. tr.appendChild(td);
  83. }
  84. let problemcount=document.createElement("td");
  85. problemcount.textContent=res[0].toString()+"题";
  86. tr.appendChild(problemcount);
  87. tr.style="border-spacing:10px;";
  88. tbody.appendChild(tr);
  89. }
  90. {
  91. let tr=document.createElement("tr");
  92. {
  93. let td=document.createElement("td");
  94. let problemcolor=document.createElement("span");
  95. problemcolor.textContent=" 入门 ";
  96. problemcolor.style="color:rgb(255,255,255);background:rgb(254,76,97);border-radius:5px;";
  97. td.appendChild(problemcolor);
  98. tr.appendChild(td);
  99. }
  100. let problemcount=document.createElement("td");
  101. problemcount.textContent=res[1].toString()+"题";
  102. tr.appendChild(problemcount);
  103. tr.style="border-spacing:10px;";
  104. tbody.appendChild(tr);
  105. }
  106. {
  107. let tr=document.createElement("tr");
  108. {
  109. let td=document.createElement("td");
  110. let problemcolor=document.createElement("span");
  111. problemcolor.textContent=" 普及− ";
  112. problemcolor.style="color:rgb(255,255,255);background:rgb(243,156,17);border-radius:5px;";
  113. td.appendChild(problemcolor);
  114. tr.appendChild(td);
  115. }
  116. let problemcount=document.createElement("td");
  117. problemcount.textContent=res[2].toString()+"题";
  118. tr.appendChild(problemcount);
  119. tr.style="border-spacing:10px;";
  120. tbody.appendChild(tr);
  121. }
  122. {
  123. let tr=document.createElement("tr");
  124. {
  125. let td=document.createElement("td");
  126. let problemcolor=document.createElement("span");
  127. problemcolor.textContent=" 普及/提高− ";
  128. problemcolor.style="color:rgb(255,255,255);background:rgb(255,193,22);border-radius:5px;";
  129. td.appendChild(problemcolor);
  130. tr.appendChild(td);
  131. }
  132. let problemcount=document.createElement("td");
  133. problemcount.textContent=res[3].toString()+"题";
  134. tr.appendChild(problemcount);
  135. tr.style="border-spacing:10px;";
  136. tbody.appendChild(tr);
  137. }
  138. {
  139. let tr=document.createElement("tr");
  140. {
  141. let td=document.createElement("td");
  142. let problemcolor=document.createElement("span");
  143. problemcolor.textContent=" 普及+/提高 ";
  144. problemcolor.style="color:rgb(255,255,255);background:rgb(82,196,26);border-radius:5px;";
  145. td.appendChild(problemcolor);
  146. tr.appendChild(td);
  147. }
  148. let problemcount=document.createElement("td");
  149. problemcount.textContent=res[4].toString()+"题";
  150. tr.appendChild(problemcount);
  151. tr.style="border-spacing:10px;";
  152. tbody.appendChild(tr);
  153. }
  154. {
  155. let tr=document.createElement("tr");
  156. {
  157. let td=document.createElement("td");
  158. let problemcolor=document.createElement("span");
  159. problemcolor.textContent=" 提高+/省选− ";
  160. problemcolor.style="color:rgb(255,255,255);background:rgb(52,152,219);border-radius:5px;";
  161. td.appendChild(problemcolor);
  162. tr.appendChild(td);
  163. }
  164. let problemcount=document.createElement("td");
  165. problemcount.textContent=res[5].toString()+"题";
  166. tr.appendChild(problemcount);
  167. tr.style="border-spacing:10px;";
  168. tbody.appendChild(tr);
  169. }
  170. {
  171. let tr=document.createElement("tr");
  172. {
  173. let td=document.createElement("td");
  174. let problemcolor=document.createElement("span");
  175. problemcolor.textContent=" 省选/NOI− ";
  176. problemcolor.style="color:rgb(255,255,255);background:rgb(157,61,207);border-radius:5px;";
  177. td.appendChild(problemcolor);
  178. tr.appendChild(td);
  179. }
  180. let problemcount=document.createElement("td");
  181. problemcount.textContent=res[6].toString()+"题";
  182. tr.appendChild(problemcount);
  183. tr.style="border-spacing:10px;";
  184. tbody.appendChild(tr);
  185. }
  186. {
  187. let tr=document.createElement("tr");
  188. {
  189. let td=document.createElement("td");
  190. let problemcolor=document.createElement("span");
  191. problemcolor.textContent=" NOI/NOI+/CTSC ";
  192. problemcolor.style="color:rgb(255,255,255);background:rgb(14,29,105);border-radius:5px;";
  193. td.appendChild(problemcolor);
  194. tr.appendChild(td);
  195. }
  196. let problemcount=document.createElement("td");
  197. problemcount.textContent=res[7].toString()+"题";
  198. tr.appendChild(problemcount);
  199. tr.style="border-spacing:10px;";
  200. tbody.appendChild(tr);
  201. }
  202. let tall=document.createElement("table");
  203. box.appendChild(tall);
  204. {
  205. let tr=document.createElement("tr");
  206. {
  207. let td=document.createElement("td");
  208. let problemcolor=document.createElement("span");
  209. problemcolor.textContent=" 通过总数 ";
  210. problemcolor.style="background:rgb(228,240,245);border-radius:5px;";
  211. td.appendChild(problemcolor);
  212. tr.appendChild(td);
  213. }
  214. let problemcount=document.createElement("td");
  215. let sum=0;
  216. for(let i=0;i<=7;i++)
  217. {
  218. sum+=res[i];
  219. }
  220. problemcount.textContent=sum.toString()+"题";
  221. tr.appendChild(problemcount);
  222. tr.style="border-spacing:10px;";
  223. tr.colSpan="2";
  224. tbody.appendChild(tr);
  225. }
  226. {
  227. let button=document.createElement("button");
  228. button.textContent="清空数据";
  229. button.style=
  230. "color:rgb(255,255,255);border-width:2px;background:rgb(14,144,210);"
  231. +"border-color:rgb(14,140,200);border-radius:5px;box-shadow:none;";
  232. box.appendChild(button);
  233. function click(){
  234. if(confirm("确定要清空所有数据?")){
  235. localStorage.clear();
  236. }
  237. }
  238. button.onclick=click;
  239. }
  240. box.appendChild(document.createElement("p"));
  241. {
  242. let button=document.createElement("button");
  243. button.textContent="爬取数据";
  244. button.style=
  245. "color:rgb(255,255,255);border-width:2px;background:rgb(14,144,210);"
  246. +"border-color:rgb(14,140,200);border-radius:5px;box-shadow:none;";
  247. box.appendChild(button);
  248. function click(){
  249. if(!confirm("确定要一页页记录爬取数据?(可以关闭浏览器停下,但是下次进入记录界面会继续,不要手贱输太多)")){
  250. return ;
  251. }
  252. let num=Number(prompt("输入执行页码数","10"));
  253. var uid=window._feInjection.currentUser.uid;
  254. localStorage.setItem("fetch_pages",num.toString());
  255. location.href="https://www.luogu.com.cn/record/list?user="+uid.toString()+"&status=12&page=1";
  256. }
  257. button.onclick=click;
  258. }
  259. box.appendChild(document.createElement("p"));
  260. {
  261. let button=document.createElement("button");
  262. button.textContent="生成柱状图(复制到剪贴板)";
  263. button.style=
  264. "color:rgb(255,255,255);border-width:2px;background:rgb(14,144,210);"
  265. +"border-color:rgb(14,140,200);border-radius:5px;box-shadow:none;";
  266. box.appendChild(button);
  267. let tip=document.createElement("dialog");
  268. let tip_txt=document.createElement("p");
  269. tip_txt.textContent="已复制到剪贴板";
  270. tip.style="width:150px;height:50px;text-align:center;border-width:0px;";
  271. tip.appendChild(tip_txt);
  272. button.appendChild(tip);
  273. function click(){
  274. let maxv=res[0];
  275. for(let i=1;i<=7;i++)
  276. {
  277. if(maxv<res[i]){
  278. maxv=res[i];
  279. }
  280. }
  281. let latex=
  282. "$$"+
  283. "\\def{\\cR}{FE4C61} \\def{\\cO}{F39C11} \\def{\\cY}{FFC116} \\def{\\cG}{52C41A} \\def{\\cB}{3498DB} \\def{\\cP}{9D3DCF} \\def{\\cD}{0E1D69} \\def{\\cE}{BFBFBF} \\def{\\s}{35pt} \\def{\\w}{\\kern{5pt}}"+
  284. "\\newcommand{\\a}[1]{&\\textcolor{A9A9A9}{\\kern{-5pt}\\underline{#1\\kern{242pt}}\\kern{8pt}}\\\\[\\s]}"+
  285. "\\newcommand{\\b}[2]{\\fcolorbox{black}{#2}{\\raisebox{#1pt}{\\kern{10pt}}}\\raisebox{#1pt}{\\scriptsize\\kern{-17pt}\\raisebox{4.5pt}{#1题}}}"+
  286. "\\newcommand{\\c}[0]{\\kern{-10pt}\\large\\textbf{练习情况统计表}}"+
  287. "\\newcommand{\\t}[2]{\\fcolorbox{black}{#2}{\\color{white}\\textbf{#1}}}"+
  288. "\\newcommand{\\main}[9]{"+
  289. "\\boxed{\\kern{8pt}\\begin{gathered}\\\\[-6pt]\\c\\\\[10pt]"+
  290. "\\begin{aligned}\\a{500}\\a{450}\\a{350}\\a{300}\\a{250}\\a{200}\\a{150}\\a{100}\\a{\\w50}\\a{\\w\\w 0}\\end{aligned} \\\\[-64pt] \\\\[-#1pt]"+
  291. "\\begin{matrix}"+
  292. " & \\b{#2}{\\cE}& \\b{#3}{\\cR} & \\b{#4}{\\cO} & \\b{#5}{\\cY} & \\b{#6}{\\cG} & \\b{#7}{\\cB} & \\b{#8}{\\cP} & \\b{#9}{\\cD} & \\\\[5pt]"+
  293. "\\kern{-6pt}\\text{项目} & \\t{灰}{\\cE} & \\t{红}{\\cR} & \\t{橙}{\\cO} & \\t{黄}{\\cY}&\\t{绿}{\\cG}&\\t{蓝}{\\cB}&\\t{紫}{\\cP} & \\t{黑}{\\cD} & \\kern{8pt} \\\\"+
  294. "\\end{matrix}"+
  295. "\\end{gathered}}}"+
  296. "\\main{"+
  297. maxv.toString()+
  298. "}{"+
  299. res[0].toString()+
  300. "}{"+
  301. res[1].toString()+
  302. "}{"+
  303. res[2].toString()+
  304. "}{"+
  305. res[3].toString()+
  306. "}{"+
  307. res[4].toString()+
  308. "}{"+
  309. res[5].toString()+
  310. "}{"+
  311. res[6].toString()+
  312. "}{"+
  313. res[7].toString()+
  314. "}$$";
  315. navigator.clipboard.writeText(latex);
  316. tip.setAttribute("open","");
  317. setTimeout(()=>{
  318. tip.removeAttribute("open");
  319. },"1000");
  320. }
  321. button.onclick=click;
  322. }
  323. box.appendChild(document.createElement("p"));
  324. {
  325. let button=document.createElement("button");
  326. button.textContent="生成具体练习情况(简陋版)(复制到剪贴板)";
  327. button.style=
  328. "color:rgb(255,255,255);border-width:2px;background:rgb(14,144,210);"
  329. +"border-color:rgb(14,140,200);border-radius:5px;box-shadow:none;";
  330. box.appendChild(button);
  331. let tip=document.createElement("dialog");
  332. let tip_txt=document.createElement("p");
  333. tip_txt.textContent="已复制到剪贴板";
  334. tip.style="width:150px;height:50px;text-align:center;border-width:0px;";
  335. tip.appendChild(tip_txt);
  336. button.appendChild(tip);
  337. function click(){
  338. let txt="";
  339. let fir=true;
  340. for(let i=0;i<=7;i++)
  341. {
  342. if(query_diff(i)){
  343. if(!fir){
  344. txt+="\n---\n";
  345. }
  346. fir=false;
  347. let arr=JSON.parse(localStorage.getItem(i.toString()+"problems"));
  348. arr.sort();
  349. for(let j=0;j<arr.length;j++)
  350. {
  351. txt+=arr[j]+"\n";
  352. }
  353. }
  354. }
  355. navigator.clipboard.writeText(txt);
  356. tip.setAttribute("open","");
  357. setTimeout(()=>{
  358. tip.removeAttribute("open");
  359. },"1000");
  360. }
  361. button.onclick=click;
  362. }
  363. box.appendChild(document.createElement("p"));
  364. {
  365. let button=document.createElement("button");
  366. button.textContent="生成具体练习情况(复制到剪贴板)";
  367. button.style=
  368. "color:rgb(255,255,255);border-width:2px;background:rgb(14,144,210);"
  369. +"border-color:rgb(14,140,200);border-radius:5px;box-shadow:none;";
  370. box.appendChild(button);
  371. let tip=document.createElement("dialog");
  372. let tip_txt=document.createElement("p");
  373. tip_txt.textContent="已复制到剪贴板";
  374. tip.style="width:150px;height:50px;text-align:center;border-width:0px;";
  375. tip.appendChild(tip_txt);
  376. button.appendChild(tip);
  377. function click(){
  378. let txt="";
  379. let fir=true;
  380. for(let i=0;i<=7;i++)
  381. {
  382. if(query_diff(i)){
  383. if(!fir){
  384. txt+="\n---\n";
  385. }
  386. fir=false;
  387. let arr=JSON.parse(localStorage.getItem(i.toString()+"problems"));
  388. arr.sort();
  389. for(let j=0;j<arr.length;j++)
  390. {
  391. let nam="";
  392. for(let k=0;k<arr[j].length;k++)
  393. {
  394. if(arr[j][k]=='_'){
  395. nam+='\\';
  396. }
  397. if(k&&arr[j][k-1]=='A'&&arr[j][k]=='T'){
  398. nam+='\\!';
  399. }
  400. if(k&&arr[j][k-1]=='U'&&arr[j][k]=='V'){
  401. nam+='\\!';
  402. }
  403. if(k&&arr[j][k-1]=='V'&&arr[j][k]=='A'){
  404. nam+='\\!';
  405. }
  406. nam+=arr[j][k];
  407. if(k&&arr[j][k-1]=='V'&&arr[j][k]=='A'){
  408. nam+='\\!';
  409. }
  410. }
  411. if(j){
  412. txt+="$\\text{ }$"
  413. }
  414. txt+="[$\\color{"+col[i]+"}\\small\\text{"+nam+"}$](https://www.luogu.com.cn/problem/"+arr[j]+")\n";
  415. }
  416. }
  417. }
  418. navigator.clipboard.writeText(txt);
  419. tip.setAttribute("open","");
  420. setTimeout(()=>{
  421. tip.removeAttribute("open");
  422. },"1000");
  423. }
  424. button.onclick=click;
  425. }
  426. }
  427. }
  428. if(window.location.href.match("https://www.luogu.com.cn/record")){
  429. var rec=window._feInjection.currentData.records.result;
  430. var uid=window._feInjection.currentUser.uid;
  431. for(let i=0;i<rec.length;i++)
  432. {
  433. if(rec[i].status==12&&rec[i].user.uid==uid){
  434. work(rec[i].problem);
  435. }
  436. }
  437. let fet=localStorage.getItem("fetch_pages");
  438. if(fet){
  439. let num=Number(fet);
  440. let now=0;
  441. let web=location.href;
  442. let nxt="";
  443. for(let i=0;i+5<=web.length;i++)
  444. {
  445. if(web.substr(i,5)=="page="){
  446. nxt+="page=";
  447. let ext="";
  448. for(let j=i+5;j<web.length;j++)
  449. {
  450. if('0'<=web[j]&&web[j]<='9'){
  451. now=now*10+(web[j]-'0');
  452. }
  453. else{
  454. ext=web.substr(j,web.length-j);
  455. break;
  456. }
  457. }
  458. nxt+=(now+1).toString();
  459. nxt+=ext;
  460. break;
  461. }
  462. nxt+=web[i];
  463. }
  464. if(now){
  465. if(now==num){
  466. localStorage.removeItem("fetch_pages");
  467. }
  468. else{
  469. location.href=nxt;
  470. }
  471. }
  472. }
  473. }
  474. else{
  475. display();
  476. }
  477. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址