ex124OJ

Extend 124OJ!

当前为 2022-12-01 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name ex124OJ
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.5.9
  5. // @description Extend 124OJ!
  6. // @author Sukwants
  7. // @license MIT
  8. // @match http://124.221.194.184
  9. // @match http://124.221.194.184/*
  10. // @icon https://www.imageoss.com/images/2022/11/29/ex124OJba563861978a769d.png
  11. // @grant GM_addStyle
  12. // ==/UserScript==
  13.  
  14.  
  15. /* ==User Settings== */
  16.  
  17. // Change Page Background. (Image URL, Opacity)
  18. const BackgroundSettings = [];
  19. // Change Site Icon. (Image URL)
  20. const SiteIconImage = 'https://www.imageoss.com/images/2022/11/29/ex124OJba563861978a769d.png';
  21. // Change username color.
  22. const NameColorList = {'Sukwants':'#8e44ad','Star32':'#e74c3c','2745518585':'#996600','syysongyuyang':'#e67e22','zsq147258369':'#52c41a','zhouchuan':'#b0e0e6'};
  23. // Add CCF level badge.
  24. const CCFBadgeList = {'zsq147258369':'#52c41a'};
  25. // Add name tag badge.
  26. const TagBadgeList = {'Sukwants':['#8e44ad','旅客'],'Star32':['#e74c3c','陌生人'],'2745518585':['#996600','作弊者'],'syysongyuyang':['#e67e22','原批'],'zsq147258369':['#52c41a','boring'],'zhouchuan':['#b0e0e6','Feyn']};
  27.  
  28.  
  29. const submissionRegExp = /^http:\/\/124.221.194.184\/submission\/\d{1,}/;
  30. function isSubmission() {
  31. return submissionRegExp.test(window.location.href);
  32. }
  33. const ProblemRegExp = /^http:\/\/124.221.194.184.*\/problem\/(\d{1,})(\?.*){0,1}$/;
  34. function isProblem() {
  35. return ProblemRegExp.test(window.location.href);
  36. }
  37. const UserProfileRegExp = /^http:\/\/124.221.194.184\/user\/profile\/.{1,}/;
  38. function isUserProfile() {
  39. return UserProfileRegExp.test(window.location.href);
  40. }
  41. const BlogRegExp = /^http:\/\/124.221.194.184\/blog\/.{1,}/;
  42. function isBlog() {
  43. return BlogRegExp.test(window.location.href);
  44. }
  45.  
  46. function whenMourn() {
  47. GM_addStyle('\
  48. html {\
  49. -webkit-filter: grayscale(100%);\
  50. -moz-filter: grayscale(100%);\
  51. -ms-filter: grayscale(100%);\
  52. -o-filter: grayscale(100%);\
  53. filter: grayscale(100%);\
  54. filter: gray;\
  55. }');
  56. if (isSubmission()) {
  57. GM_addStyle('\
  58. .card>.card-header {\
  59. color: #fff;\
  60. }');
  61. }
  62. var Banner = document.createElement('img');
  63. Banner.setAttribute('src', 'https://www.imageoss.com/images/2022/11/30/cb6a1d050e324a8b6ec7996b0a398f7376e9e2bd.png3840w_360h_1c_90q74cf9fde037f143b.jpg');
  64. Banner.setAttribute('style', 'width:100%; margin: -50px 0');
  65. document.getElementsByTagName('body')[0].children[0].children[0].before(Banner);
  66. document.getElementsByTagName('body')[0].children[0].children[1].children[1].setAttribute('style', 'color:white');
  67. }
  68.  
  69. function getBackground() {
  70. if (BackgroundSettings[0]) return BackgroundSettings[0];
  71. else return '';
  72. }
  73. function getOpacity() {
  74. if (BackgroundSettings[1]) return BackgroundSettings[1];
  75. else return '0.85';
  76. }
  77. function BackgroundImage() {
  78. if (BackgroundSettings[0]) {
  79. document.getElementsByClassName('navbar-brand')[0].innerHTML = '<img src="http://124.221.194.184/images/logo_small.png" alt="Logo" class="img-rounded" style="width:39px; height:39px;">';
  80. document.getElementsByClassName('container')[0].children[0].children[1].innerHTML = document.getElementsByClassName('container')[0].children[0].children[1].innerHTML.match(/(.*> ){0,1}(.*)/)[2];
  81. GM_addStyle('\
  82. body {\
  83. background: url("' + getBackground() + '");\
  84. background-repeat: no-repeat;\
  85. background-attachment: fixed;\
  86. background-position: 50% 50%;\
  87. background-size: cover;\
  88. }\
  89. .uoj-content {\
  90. background-color: #fff;\
  91. margin: 16px -16px;\
  92. padding: 16px 16px;\
  93. opacity: ' + getOpacity() + ';\
  94. border-radius: 8px;\
  95. }\
  96. .navbar {\
  97. margin: 16px -16px;\
  98. padding: 8px 16px;\
  99. opacity: ' + getOpacity() + ';\
  100. border-radius: 8px;\
  101. }');
  102. }
  103. }
  104.  
  105. function getIcon() {
  106. if (SiteIconImage) return SiteIconImage;
  107. else return '/images/logo.png';
  108. }
  109. const LogoURLExp = /^.*\/images\/logo(_small){0,1}.png$/;
  110. function changeIcon() {
  111. var Links = document.getElementsByTagName('link');
  112. for (var link in Links) {
  113. if (Links[link] && Links[link].nodeType && Links[link].getAttribute('rel') == 'shortcut icon') {
  114. Links[link].setAttribute('href', getIcon());
  115. }
  116. }
  117. var Icons = document.getElementsByTagName('img');
  118. for (var icon in Icons) {
  119. if (Icons[icon] && Icons[icon].nodeType && LogoURLExp.test(Icons[icon].getAttribute('src'))) {
  120. Icons[icon].setAttribute('src', getIcon());
  121. }
  122. }
  123. }
  124.  
  125. const ManageStatementExp = /^.*\/manage\/statement(\?.*){0,1}$/
  126. function CodeBlock() {
  127. GM_addStyle('\
  128. @import url(https://cdn.jsdelivr.net/npm/firacode@6.2.0/distr/fira_code.css);\
  129. code {\
  130. font-family: "Fira Code";\
  131. }\
  132. code.sh_cpp>span {\
  133. font-style: normal !important;\
  134. font-weight: 400 !important;\
  135. }\
  136. code.sh_cpp>span.sh_preproc,\
  137. code.sh_cpp>span.sh_keyword,\
  138. code.sh_cpp>span.sh_type {\
  139. color: #8959a8;\
  140. }\
  141. code.sh_cpp>span.sh_string {\
  142. color: #718c00;\
  143. }\
  144. code.sh_cpp>span.sh_cbracket {\
  145. color: #4d4d4c;\
  146. }\
  147. code.sh_cpp>span.sh_symbol {\
  148. color: #3e999f;\
  149. }\
  150. code.sh_cpp>span.sh_number {\
  151. color: #f5871f;\
  152. }\
  153. code.sh_cpp>span.sh_function {\
  154. color: #4271ae;\
  155. }\
  156. code.sh_cpp>span.sh_comment {\
  157. color: #8e908c;\
  158. }\
  159. .copybutton {\
  160. float: right;\
  161. background-color: rgb(0,0,0,.1);\
  162. padding: .25em .625em;\
  163. border: 0 solid transparent;\
  164. border-radius: .28571429rem;\
  165. }\
  166. .copybutton:hover {\
  167. background-color: rgb(0,0,0,.2);\
  168. }\
  169. .copybutton:focus {\
  170. background-color: rgb(0,0,0,.2);\
  171. outline: none;\
  172. }');
  173. if (!ManageStatementExp.test(window.location.href)) {
  174. setTimeout(function(){
  175. var CodeBlocks = document.getElementsByTagName('pre');
  176. for (var cb in CodeBlocks) {
  177. if (CodeBlocks[cb] && CodeBlocks[cb].nodeType) {
  178. var Content = CodeBlocks[cb].textContent;
  179. var InputId = Math.round(Math.random() * 998244353);
  180. var ButtonId = Math.round(Math.random() * 998244353);
  181. CodeBlocks[cb].innerHTML = '<button class="copybutton" id = "' + ButtonId + '" onclick="\
  182. var ib = document.getElementById(\'' + InputId + '\');\
  183. ib.setAttribute(\'style\', \'display:initial\');\
  184. ib.value = \'' + Content.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/'/g, '\\&#39;').replace(/"/g, '&#34;') + '\';\
  185. ib.select();\
  186. document.execCommand(\'copy\');\
  187. ib.setAttribute(\'style\', \'display:none\');\
  188. var ic = document.getElementById(\'' + ButtonId + '\');\
  189. ic.innerHTML = \'已复制\';\
  190. setTimeout(function() { ic.innerHTML = \'复制\'; }, 500);">复制</button>' + CodeBlocks[cb].innerHTML;
  191. var InputBox = document.createElement('textarea');
  192. InputBox.setAttribute('id', InputId);
  193. InputBox.setAttribute('style', 'display:none');
  194. CodeBlocks[cb].appendChild(InputBox);
  195. }
  196. }
  197. }, 30);
  198. }
  199. }
  200.  
  201. function NameColor() {
  202. var Names = document.getElementsByClassName('uoj-username');
  203. var NeedsRepeat = false;
  204. for (var i in Names) {
  205. if (Names[i].innerHTML && NameColorList[Names[i].innerHTML]) {
  206. Names[i].style = 'color:' + NameColorList[Names[i].innerHTML];
  207. if (Names[i].parentElement.getAttribute('class') == 'legendLabel') {
  208. NeedsRepeat = true;
  209. }
  210. }
  211. }
  212. if (NeedsRepeat) {
  213. setInterval(function(){
  214. var Names = document.getElementsByClassName('uoj-username');
  215. for (var i in Names) {
  216. if (Names[i].innerHTML && Names[i].parentElement.getAttribute('class') == 'legendLabel' && NameColorList[Names[i].innerHTML]) {
  217. Names[i].style = 'color:' + NameColorList[Names[i].innerHTML];
  218. }
  219. }
  220. }, 200);
  221. }
  222. var Honors = document.getElementsByClassName('uoj-honor');
  223. for (var j in Honors) {
  224. if (Honors[j].innerHTML && NameColorList[Honors[j].innerHTML]) {
  225. Honors[j].style = "color:" + NameColorList[Honors[j].innerHTML];
  226. }
  227. }
  228. }
  229.  
  230. const NameWithBadge = /^(.{1,}?)( <.*){0,1}$/;
  231. function CCFBadge() {
  232. var Names = document.getElementsByClassName('uoj-username');
  233. for (var i in Names) {
  234. if (!Names[i].innerHTML || !NameWithBadge.test(Names[i].innerHTML)) continue;
  235. var name = Names[i].innerHTML.match(NameWithBadge)[1];
  236. if (CCFBadgeList[name] && Names[i].parentElement.getAttribute('class') != 'legendLabel') {
  237. Names[i].innerHTML = Names[i].innerHTML + ' <svg width="1em" height="1em" data-v-303bbf52="" aria-hidden="true" focusable="false" data-prefix="fad" data-icon="badge-check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="margin-bottom:.25em!important;bottom:10px;--fa-primary-color:#fff;--fa-secondary-color:' + CCFBadgeList[name] + ';--fa-secondary-opacity:1;"><g data-v-303bbf52="" class="fa-group"><path data-v-303bbf52="" fill="var(--fa-secondary-color)" d="M512 256a88 88 0 0 0-57.1-82.4A88 88 0 0 0 338.4 57.1a88 88 0 0 0-164.8 0A88 88 0 0 0 57.1 173.6a88 88 0 0 0 0 164.8 88 88 0 0 0 116.5 116.5 88 88 0 0 0 164.8 0 88 88 0 0 0 116.5-116.5A88 88 0 0 0 512 256zm-144.8-44.25l-131 130a11 11 0 0 1-15.55-.06l-75.72-76.33a11 11 0 0 1 .06-15.56L171 224a11 11 0 0 1 15.56.06l42.15 42.49 97.2-96.42a11 11 0 0 1 15.55.06l25.82 26a11 11 0 0 1-.08 15.56z" class="fa-secondary"></path></g></svg>';
  238. }
  239. }
  240. var Honors = document.getElementsByClassName('uoj-honor');
  241. for (var j in Honors) {
  242. if (!Honors[j].innerHTML || !NameWithBadge.test(Honors[j].innerHTML)) continue;
  243. var honor = Honors[j].innerHTML.match(NameWithBadge)[1];
  244. if (CCFBadgeList[honor]) {
  245. Honors[j].innerHTML = Honors[j].innerHTML + ' <svg width="1em" height="1em" data-v-303bbf52="" aria-hidden="true" focusable="false" data-prefix="fad" data-icon="badge-check" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="margin-bottom:.25em!important;bottom:10px;--fa-primary-color:#fff;--fa-secondary-color:' + CCFBadgeList[honor] + ';--fa-secondary-opacity:1;"><g data-v-303bbf52="" class="fa-group"><path data-v-303bbf52="" fill="var(--fa-secondary-color)" d="M512 256a88 88 0 0 0-57.1-82.4A88 88 0 0 0 338.4 57.1a88 88 0 0 0-164.8 0A88 88 0 0 0 57.1 173.6a88 88 0 0 0 0 164.8 88 88 0 0 0 116.5 116.5 88 88 0 0 0 164.8 0 88 88 0 0 0 116.5-116.5A88 88 0 0 0 512 256zm-144.8-44.25l-131 130a11 11 0 0 1-15.55-.06l-75.72-76.33a11 11 0 0 1 .06-15.56L171 224a11 11 0 0 1 15.56.06l42.15 42.49 97.2-96.42a11 11 0 0 1 15.55.06l25.82 26a11 11 0 0 1-.08 15.56z" class="fa-secondary"></path></g></svg>';
  246. }
  247. }
  248. }
  249. function TagBadge() {
  250. var Names = document.getElementsByClassName('uoj-username');
  251. for (var i in Names) {
  252. if (!Names[i].innerHTML || !NameWithBadge.test(Names[i].innerHTML)) continue;
  253. var name = Names[i].innerHTML.match(NameWithBadge)[1];
  254. if (TagBadgeList[name] && Names[i].parentElement.getAttribute('class') != 'legendLabel') {
  255. Names[i].innerHTML = Names[i].innerHTML + ' <span style="background-color:' + TagBadgeList[name][0] + ';padding:0.2em 0.6em;border-radius:.2em;color:#fff;font-size:0.7em;font-weight:bold;display:inline-block">' + TagBadgeList[name][1] + '</span>';
  256. }
  257. }
  258. var Honors = document.getElementsByClassName('uoj-honor');
  259. for (var j in Honors) {
  260. if (!Honors[j].innerHTML || !NameWithBadge.test(Honors[j].innerHTML)) continue;
  261. var honor = Honors[j].innerHTML.match(NameWithBadge)[1];
  262. if (TagBadgeList[honor]) {
  263. Honors[j].innerHTML = Honors[j].innerHTML + ' <span style="background-color:' + TagBadgeList[honor][0] + ';padding:0.2em 0.6em;border-radius:.2em;color:#fff;font-size:0.7em;font-weight:bold;display:inline-block">' + TagBadgeList[honor][1] + '</span>';
  264. }
  265. }
  266. }
  267.  
  268. function TableStyle() {
  269. var Tables = document.getElementsByTagName('table');
  270. for (var table in Tables) {
  271. if (Tables[table].nodeType && Tables[table].parentNode.getAttribute('class') != 'legend' && !Tables[table].classList.length) {
  272. Tables[table].classList.add('table', 'table-bordered');
  273. }
  274. }
  275. var ths = document.getElementsByTagName('th');
  276. for (var th in ths) {
  277. if (ths[th].nodeType && ths[th].getAttribute('align')) {
  278. ths[th].setAttribute('style', 'text-align:' + ths[th].getAttribute('align'));
  279. }
  280. }
  281. }
  282.  
  283. function SubmissionCard() {
  284. setTimeout(function() {
  285. var Content = document.getElementsByClassName('uoj-content')[0];
  286. if (Content.childElementCount == 3) {
  287. var Table = Content.children[0];
  288. var TabList = document.createElement('ul');
  289. TabList.setAttribute('class', 'nav nav-tabs');
  290. TabList.setAttribute('role', 'tablist');
  291. TabList.innerHTML = '<li class="nav-item"><a class="nav-link active" href="#test-cases" role="tab" data-toggle="tab" aria-selected="true"><span class="glyphicon glyphicon-check"></span> 测试点信息</a></li><li class="nav-item"><a class="nav-link" href="#source" role="tab" data-toggle="tab" aria-selected="false"><span class="glyphicon glyphicon-file"></span> 源代码</a></li>';
  292. var TabContent = document.createElement('div');
  293. TabContent.setAttribute('class', 'tab-content');
  294. TabContent.innerHTML = '<div class="tab-pane card active" id="test-cases"><div class="card-body">' + Content.children[2].children[1].innerHTML + '</div></div><div class="tab-pane card" id="source"><div class="card-body">' + Content.children[1].children[1].innerHTML + '</div></div>';
  295. Content.innerHTML = "";
  296. Content.appendChild(Table);
  297. Content.appendChild(TabList);
  298. Content.appendChild(TabContent);
  299. }
  300. }, 50);
  301. }
  302.  
  303. function downloadData() {
  304. var DownloadTag = document.createElement('a');
  305. DownloadTag.setAttribute('role', 'button');
  306. DownloadTag.setAttribute('class', 'btn btn-primary float-right');
  307. DownloadTag.setAttribute('href', '/download.php?type=problem&id=' + window.location.href.match(ProblemRegExp)[1]);
  308. DownloadTag.setAttribute('target', '_blank');
  309. DownloadTag.innerHTML = '<span class="glyphicon glyphicon-download-alt"></span> 下载数据';
  310. document.getElementsByClassName("btn btn-info float-right")[0].after(DownloadTag);
  311. }
  312.  
  313. const GravatarURLRegExp = /\/\/cn.gravatar.com\/avatar\/(.*)$/;
  314. function changeGravatarURL() {
  315. var Gravatar = document.getElementsByClassName('img-thumbnail')[0];
  316. if (Gravatar && Gravatar.nodeType){
  317. console.log(Gravatar);
  318. Gravatar.setAttribute('src', '//gravatar.loli.net/avatar/' + Gravatar.getAttribute('src').match(GravatarURLRegExp)[1]);
  319. }
  320. var Gravatars = document.getElementsByClassName('img-rounded');
  321. for (var gravatar in Gravatars) {
  322. if (Gravatars[gravatar] && Gravatars[gravatar].nodeType && GravatarURLRegExp.test(Gravatars[gravatar].getAttribute('src'))) {
  323. Gravatars[gravatar].setAttribute('src', '//gravatar.loli.net/avatar/' + Gravatars[gravatar].getAttribute('src').match(GravatarURLRegExp)[1]);
  324. }
  325. }
  326. }
  327.  
  328. (function() {
  329. 'use strict';
  330. whenMourn();
  331. BackgroundImage();
  332. changeIcon();
  333. CodeBlock();
  334. NameColor();
  335. CCFBadge();
  336. TagBadge();
  337. TableStyle();
  338. if (isSubmission()) SubmissionCard();
  339. if (isProblem()) downloadData();
  340. if (isUserProfile() || isBlog()) changeGravatarURL();
  341. })();