Enhanced ioihw20

Showing problem owners and real names on ioihw20.duck-ac.cn

  1. // ==UserScript==
  2. // @name Enhanced ioihw20
  3. // @description Showing problem owners and real names on ioihw20.duck-ac.cn
  4. // @license MIT
  5. // @version 0.2.1
  6. // @author Cekavis
  7. // @match https://ioihw20.duck-ac.cn/*
  8. // @grant GM_addStyle
  9. // @namespace https://gf.qytechs.cn/users/696898
  10. // ==/UserScript==
  11.  
  12. GM_addStyle (`
  13. body > div > div.uoj-content > div.table-responsive > table > thead > tr > th:nth-child(1){
  14. width: 8em !important;
  15. }
  16. `);
  17.  
  18. (function() {
  19. 'use strict';
  20.  
  21. let dict = {
  22. 'ioi2021_00': '虞皓翔',
  23. 'ioi2021_01': '马耀华',
  24. 'ioi2021_02': '彭博',
  25. 'ioi2021_03': '屠学畅',
  26. 'ioi2021_04': '黄子宽',
  27. 'ioi2021_05': '彭思进',
  28. 'ioi2021_06': '胡昊',
  29. 'ioi2021_07': '邓明扬',
  30. 'ioi2021_08': '周欣',
  31. 'ioi2021_09': '陈雨昕',
  32. 'ioi2021_10': '叶卓睿',
  33. 'ioi2021_11': '魏衍芃',
  34. 'ioi2021_12': '林昊翰',
  35. 'ioi2021_13': '李白天',
  36. 'ioi2021_14': '代晨昕',
  37. 'ioi2021_15': '张隽恺',
  38. 'ioi2021_16': '徐哲安',
  39. 'ioi2021_17': '郭城志',
  40. 'ioi2021_18': '徐舟子',
  41. 'ioi2021_19': '周镇东',
  42. 'ioi2021_20': '张好风',
  43. 'ioi2021_21': '袁浩天',
  44. 'ioi2021_22': '魏辰轩',
  45. 'ioi2021_23': '邱天异',
  46. 'ioi2021_24': '张博为',
  47. 'ioi2021_25': '陈峻宇',
  48. 'ioi2021_26': '孙诺舟',
  49. 'ioi2021_27': '蒋凌宇',
  50. 'ioi2021_28': '潘佳奇',
  51. 'ioi2021_29': '钱易',
  52. 'ioi2021_30': '张庭川',
  53. 'ioi2021_31': '丁晓漫',
  54. 'ioi2021_32': '左骏驰',
  55. 'ioi2021_33': '万天航',
  56. 'ioi2021_34': '施良致',
  57. 'ioi2021_35': '刘宇豪',
  58. 'ioi2021_36': '李泽清',
  59. 'ioi2021_37': '林立',
  60. 'ioi2021_38': '戴傅聪',
  61. 'ioi2021_39': '王泽远',
  62. 'ioi2021_40': '陈胤戬',
  63. 'ioi2021_41': '陆宏',
  64. 'ioi2021_42': '吕秋实',
  65. 'ioi2021_43': '欧阳宇鹏',
  66. 'ioi2021_44': '张记僖',
  67. 'ioi2021_45': '吴孟周',
  68. 'ioi2021_46': '曹原',
  69. 'ioi2021_47': '陈亮舟',
  70. 'ioi2021_48': '卢宸昊',
  71. 'ioi2021_49': '曾庆之',
  72. 'ioi2021_50': '万成章',
  73. 'ioi2021_51': '张景行',
  74. 'ioi2021_52': '戴江齐',
  75. 'ioi2021_53': '郑路明',
  76. 'ioi2021_54': '周航锐',
  77. 'ioi2021_55': '曹越',
  78. 'ioi2021_56': '冯施源',
  79. 'ioi2021_57': '罗恺',
  80. 'ioi2021_58': '冷滟泽',
  81. 'ioi2021_59': '杨珖',
  82. 'ioi2021_60': '陶立宇',
  83. 'ioi2021_61': '陈于思',
  84. 'ioi2021_62': '王相文',
  85. 'ioi2021_63': '孙嘉伟',
  86. 'ioi2021_64': '孙若凡',
  87. 'ioi2021_65': '宣毅鸣',
  88. 'ioi2021_66': '谢濡键',
  89. 'ioi2021_67': '孙从博',
  90. 'ioi2021_68': '许庭强',
  91. 'ioi2021_69': '周子衡',
  92. 'ioi2021_70': '苏焜',
  93. 'ioi2021_71': '管晏如',
  94. 'ioi2021_72': '陈永志',
  95. 'ioi2021_73': '蔡欣然',
  96. 'ioi2021_74': '韩豫葳',
  97. 'ioi2021_75': '张湫阳',
  98. 'ioi2021_76': '丁其安',
  99. 'ioi2021_77': '翁伟捷',
  100. 'ioi2021_78': '吴家庆',
  101. 'ioi2021_79': '潘逸飞',
  102. 'ioi2021_80': '谢琳涵'
  103. }
  104.  
  105. $('td').each(function () {
  106. console.log(this.innerHTML);
  107. if(this.innerHTML.match(/#\d+\./)) {
  108. let pid = this.innerHTML.match(/\#\d+/)[0]
  109. let uid = Math.floor((pid.substr(1)-101)/4)
  110. console.log(pid, uid)
  111. if(0<=uid && uid<=50){
  112. if(uid<10) uid = "0" + uid;
  113. let name = dict["ioi2021_"+uid]
  114. this.innerHTML = this.innerHTML.replace(pid, '<span style="color:#A0A0A0;font-size:80%">(' + name + ')</span>' + pid)
  115. }
  116. }
  117. })
  118. $('h1').each(function () {
  119. console.log(this.innerHTML);
  120. if(this.innerHTML.match(/#\d+\./)) {
  121. let pid = this.innerHTML.match(/\#\d+/)[0]
  122. let uid = Math.floor((pid.substr(1)-101)/4)
  123. console.log(pid, uid)
  124. if(0<=uid && uid<=50){
  125. if(uid<10) uid = "0" + uid;
  126. let name = dict["ioi2021_"+uid]
  127. this.innerHTML = this.innerHTML.replace(pid, '<span style="color:#A0A0A0;font-size:80%">(' + name + ')</span>' + pid)
  128. }
  129. }
  130. })
  131. $('td').each(function () {
  132. console.log(this.innerHTML);
  133. if(this.innerHTML.match(/#\d+/)==this.innerHTML) {
  134. let pid = this.innerHTML.match(/\#\d+/)[0]
  135. let uid = Math.floor((pid.substr(1)-101)/4)
  136. console.log(pid, uid)
  137. if(0<=uid && uid<=50){
  138. if(uid<10) uid = "0" + uid;
  139. let name = dict["ioi2021_"+uid]
  140. this.innerHTML = this.innerHTML.replace(pid, '<span style="color:#A0A0A0;font-size:80%">(' + name + ')</span>' + pid)
  141. }
  142. }
  143. })
  144.  
  145. $('*').each(function() {
  146. if(this.innerHTML.match(/^ioi2021_[0-9]+$/g)) {
  147. let uid = this.innerHTML.match(/ioi2021_[0-9]+/g)[0]
  148. let name = dict[uid]
  149. console.log(uid, name)
  150. this.innerHTML = '<span style="font-weight:normal">' + name + '</span>';
  151. }
  152. })
  153.  
  154. })();
  155.  
  156. const config = {
  157. url: {
  158. codeforces: 'https://www.codeforces.com',
  159. },
  160. };
  161.  
  162. const userlist = [
  163. "虞皓翔",
  164. "马耀华",
  165. "彭博",
  166. "屠学畅",
  167. "黄子宽",
  168. "彭思进",
  169. "胡昊",
  170. "邓明扬",
  171. "周欣",
  172. "陈雨昕",
  173. "叶卓睿",
  174. "魏衍芃",
  175. "林昊翰",
  176. "李白天",
  177. "代晨昕",
  178. "张隽恺",
  179. "徐哲安",
  180. "郭城志",
  181. "徐舟子",
  182. "周镇东",
  183. "张好风",
  184. "袁浩天",
  185. "魏辰轩",
  186. "邱天异",
  187. "张博为",
  188. "陈峻宇",
  189. "孙诺舟",
  190. "蒋凌宇",
  191. "潘佳奇",
  192. "钱易",
  193. "张庭川",
  194. "丁晓漫",
  195. "左骏驰",
  196. "万天航",
  197. "施良致",
  198. "刘宇豪",
  199. "李泽清",
  200. "林立",
  201. "戴傅聪",
  202. "王泽远",
  203. "陈胤戬",
  204. "陆宏",
  205. "吕秋实",
  206. "欧阳宇鹏",
  207. "张记僖",
  208. "吴孟周",
  209. "曹原",
  210. "陈亮舟",
  211. "卢宸昊",
  212. "曾庆之",
  213. "万成章",
  214. "张景行",
  215. "戴江齐",
  216. "郑路明",
  217. "周航锐",
  218. "曹越",
  219. "冯施源",
  220. "罗恺",
  221. "冷滟泽",
  222. "杨珖",
  223. "陶立宇",
  224. "陈于思",
  225. "王相文",
  226. "孙嘉伟",
  227. "孙若凡",
  228. "宣毅鸣",
  229. "谢濡键",
  230. "孙从博",
  231. "许庭强",
  232. "周子衡",
  233. "苏焜",
  234. "管晏如",
  235. "陈永志",
  236. "蔡欣然",
  237. "韩豫葳",
  238. "张湫阳",
  239. "丁其安",
  240. "翁伟捷",
  241. "吴家庆",
  242. "潘逸飞",
  243. "谢琳涵",
  244. ];
  245.  
  246. const problemShortcutList = [
  247. 'UC', 'DG', 'RB',
  248. 'HC', 'IB', 'FJ',
  249. 'GK', 'UH', 'QH',
  250. 'EE', 'DJ', 'IH',
  251. 'HL', 'MI', 'EJ',
  252. 'MB', 'UI', 'ED',
  253. 'AA', 'BG', 'ML',
  254. 'CF', 'TE', 'QG',
  255. 'PH', 'UJ', 'BB',
  256. 'CI', 'SD', 'NG',
  257. 'DK', 'LD', 'IJ',
  258. 'NC', 'BJ', 'FK',
  259. 'CH', 'NJ', 'RH',
  260. 'QF', 'BE', 'KI',
  261. 'AC', 'PG', 'HM',
  262. 'PJ', 'ID', 'EG',
  263. 'SI', 'KC', 'GI',
  264. 'OG', 'CK', 'DB',
  265. 'QE', 'GH', 'NI',
  266. 'OL', 'KA', 'MG',
  267. 'SG', 'NL', 'KH',
  268. 'QJ', 'KG', 'AB',
  269. 'KD', 'IL', 'NF',
  270. 'CM', 'NE', 'HD',
  271. 'DH', 'EC', 'BM',
  272. 'LC', 'CD', 'JI',
  273. 'DL', 'ME', 'PE',
  274. 'LI', 'AI', 'RJ',
  275. 'SF', 'II', 'HG',
  276. 'RE', 'LL', 'OA',
  277. 'FB', 'QD', 'DA',
  278. 'TC', 'AE', 'CB',
  279. 'GF', 'AG', 'JC',
  280. 'PA', 'TH', 'EH',
  281. 'AJ', 'TK', 'EI',
  282. 'UL', 'AF', 'SK',
  283. 'BH', 'RD', 'OK',
  284. 'FC', 'JD', 'OE',
  285. 'TF', 'FF', 'DD',
  286. 'CJ', 'HK', 'MJ',
  287. 'FG', 'GL', 'AL',
  288. 'FI', 'IC', 'QC',
  289. 'MD', 'OJ', 'HI',
  290. 'KK', 'JH', 'OB',
  291. 'BK', 'GJ', 'KE',
  292. 'CA', 'IK', 'LE',
  293. 'RI', 'LK', 'PD',
  294. 'JE', 'LB', 'HB',
  295. 'BL', 'RG', 'AH',
  296. 'AK', 'GG', 'JG',
  297. ];
  298.  
  299. const problemSourceIdList = [
  300. 101221, 101239, 101242, 101471, 102482, 102511, 101630,
  301. 101190, 100851, 100553, 100307, 101620, 101173, 101480,
  302. 100543, 100299, 101612, 101142, 100801, 100531, 100269
  303. ];
  304.  
  305. const colors = [
  306. 'black',
  307. 'green',
  308. 'yellow',
  309. 'red',
  310. ];
  311.  
  312. const db = {
  313. load() {
  314. return JSON.parse(localStorage.getItem('hw') || '[]');
  315. },
  316. dump(data) {
  317. localStorage.setItem('hw', JSON.stringify(data || []));
  318. },
  319. update(pid, status) {
  320. let data = db.load();
  321. data[pid] = status;
  322. db.dump(data);
  323. },
  324. query(pid) {
  325. return db.load()[pid] || 0;
  326. },
  327. };
  328.  
  329. const dbWinner = {
  330. update(winner) {
  331. localStorage.setItem('hw-winner', String(winner));
  332. },
  333. query() {
  334. let plain = localStorage.getItem('hw-winner');
  335. if (isNaN(parseInt(plain))) {
  336. return -1;
  337. } else {
  338. return parseInt(plain);
  339. }
  340. }
  341. };
  342.  
  343. function getProblemInfo(problemId) {
  344. let problemType = problemId == 1 ? '测试题' : (problemId < 300 && problemId % 4 ? '作业题' : '自选题');
  345.  
  346. let shortcut, shortcutId, contestId
  347. if (problemId >= 101) {
  348. shortcutId = problemId - 101 - ((problemId - 101) >> 2);
  349. shortcut = problemShortcutList[shortcutId];
  350. contestId = problemType == '作业题' ? problemSourceIdList[shortcut.charCodeAt(0) - 65] : -1;
  351. }
  352.  
  353. let authorId, authorName;
  354. if (problemId == 1) authorName = 'root';
  355. else {
  356. authorId = (problemId - 101) >> 2;
  357. authorName = 'ioi2021_' + (problemId < 300 ? (authorId < 10 ? '0' : '') + String(authorId) : problemId - 300 + 49 );
  358. }
  359.  
  360. return {
  361. problemType,
  362. authorId,
  363. authorName,
  364. shortcut,
  365. shortcutId,
  366. contestId
  367. };
  368. }
  369.  
  370. function getUserInfo(id) {
  371. function strMatch(source, reg_exp, default_value) {
  372. let match_result = source.match(reg_exp);
  373. if (match_result) {
  374. return match_result[1];
  375. } else {
  376. console.log("[Warning] string doesn't match!");
  377. return default_value;
  378. }
  379. }
  380. id = id < 10 ? '0' + String(id) : String(id);
  381. return $.get({
  382. url: `https://ioihw20.duck-ac.cn/user/profile/ioi2021_${id}`,
  383. }).then((res) => {
  384. let motto = strMatch(res, /<h4 class="list-group-item-heading">格言<\/h4>\s+<p class="list-group-item-text">(.*?)<\/p>/s, "<error>");
  385.  
  386. let regex = /"\/problem\/(\d+)"/g, match, count = 0;
  387. while (match = regex.exec(res)) {
  388. let problemId = parseInt(match[1]);
  389. let { problemType } = getProblemInfo(problemId);
  390. count += problemType == '作业题';
  391. }
  392.  
  393. return {
  394. id,
  395. motto,
  396. count,
  397. };
  398. });
  399. }
  400.  
  401. async function render() {
  402. $('*').each(function () {
  403. if (this.innerHTML.match(/^ioi2021_[0-9]+$/g)) {
  404. let uid = parseInt(this.innerHTML.match(/ioi2021_[0-9]+/g)[0].slice(8));
  405. let name = userlist[uid];
  406. if (uid == dbWinner.query()) {
  407. name += '<sup><span style="color: red">卷王</span></sup>';
  408. }
  409. if (name) {
  410. console.log(uid, name);
  411. this.innerHTML = '<span style="font-weight: normal">' + name + '</span>';
  412. }
  413. }
  414. });
  415.  
  416. if (location.pathname.startsWith('/problems')) {
  417. $(".table tr td:first-child").each(function () {
  418. let pid = this.innerHTML.slice(1);
  419. let status = db.query(pid);
  420. this.style.color = colors[status];
  421. if (status) {
  422. this.style['font-weight'] = 'bold';
  423. } else {
  424. this.style['font-weight'] = 'normal';
  425. }
  426. console.log(pid, status);
  427. });
  428. }
  429. }
  430.  
  431. async function mainRender() {
  432. $('.navbar .navbar-nav').append('<li><a href="/ranklist">排行榜</a></li>')
  433.  
  434. if (location.pathname == '/ranklist') {
  435. document.title = document.title.replace('比赛排行榜', '排行榜');
  436.  
  437. let userListPromised = [];
  438. $('.pagination').remove();
  439. $('.table tbody tr').remove();
  440. for (let userId = 0; userId < 81; userId++) {
  441. userListPromised.push(getUserInfo(userId));
  442. }
  443. let userList = await Promise.all(userListPromised);
  444. userList.sort((firstUser, secondUser) => {
  445. console.log(firstUser, secondUser);
  446. if (firstUser.count == secondUser.count) {
  447. return parseInt(firstUser.id) - parseInt(secondUser.id);
  448. }
  449. return secondUser.count - firstUser.count;
  450. });
  451. if (userList.length) {
  452. dbWinner.update(userList[0].id);
  453. }
  454. console.log(userList);
  455. $('.table thead tr th:last-child').text('通过数');
  456. for (let user of userList) {
  457. console.log(user);
  458. let $tr = $('<tr></tr>');
  459. $tr.append(`<td>${user.id}</td>`);
  460. $tr.append(`<td><a class="uoj-username" href="https://ioihw20.duck-ac.cn/user/profile/ioi2021_${user.id}" style="color:rgb(75,175,178)">ioi2021_${user.id}</a></td>`);
  461. $tr.append(`<td>${user.motto}</td>`);
  462. $tr.append(`<td>${user.count}</td>`);
  463. $('.table tbody').append($tr);
  464. }
  465. }
  466.  
  467. if (location.pathname.startsWith('/problem/')) {
  468. let problemId = parseInt(location.href.substr(location.href.lastIndexOf("problem/") + 8, 3), 10);
  469. let { problemType, authorName, shortcut, shortcutId, contestId } = getProblemInfo(problemId);
  470.  
  471. if (problemType == '作业题') {
  472. $(".nav-tabs").eq(0).append(`<li>
  473. <span style="display:block;padding:10px 15px;">
  474. Source:&nbsp;&nbsp;
  475. <a target="_blank" rel="noopener noreferrer" href="${config.url.codeforces}/gym/${contestId}/problem/${shortcut[1]}">
  476. ${shortcut}
  477. </a>
  478. <a target="_blank" rel="noopener noreferrer" href="${config.url.codeforces}/gym/${contestId}">
  479. (${contestId})
  480. </a>
  481. </span>
  482. </li>`);
  483. }
  484. }
  485.  
  486. render();
  487. }
  488.  
  489. if (location.pathname.startsWith('/problems')) {
  490. $(".table tr td:first-child").click(function () {
  491. let pid = this.innerHTML.slice(1);
  492. let status = db.query(pid);
  493. status = (status + 1) % colors.length;
  494. db.update(pid, status);
  495. render();
  496. });
  497. }
  498.  
  499. mainRender();

QingJ © 2025

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