ex124OJ

Extend 124OJ!

当前为 2022-11-25 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name ex124OJ
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.4.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 http://124.221.194.184/images/logo_small.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 username color.
  20. const NameColorList = {'Sukwants':'#8e44ad','Star32':'#e74c3c','2745518585':'#996600','syysongyuyang':'#e67e22','zsq147258369':'#52c41a','zhouchuan':'#b0e0e6'};
  21. // Add CCF level badge.
  22. const CCFBadgeList = {'zsq147258369':'#52c41a'};
  23. // Add name tag badge.
  24. const TagBadgeList = {'Sukwants':['#8e44ad','旅客'],'Star32':['#e74c3c','陌生人'],'2745518585':['#996600','作弊者'],'syysongyuyang':['#e67e22','原批'],'zsq147258369':['#52c41a','boring'],'zhouchuan':['#b0e0e6','Feyn']};
  25.  
  26.  
  27. function getBackground() {
  28. if (BackgroundSettings[0]) return BackgroundSettings[0];
  29. else return '';
  30. }
  31. function getOpacity() {
  32. if (BackgroundSettings[1]) return BackgroundSettings[1];
  33. else return '0.85';
  34. }
  35. function BackgroundImage() {
  36. if (BackgroundSettings[0]) {
  37. 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;">';
  38. document.getElementsByClassName('container')[0].children[0].children[1].innerHTML = document.getElementsByClassName('container')[0].children[0].children[1].innerHTML.match(/(.*> ){0,1}(.*)/)[2];
  39. GM_addStyle('\
  40. body {\
  41. background: url("' + getBackground() + '");\
  42. background-repeat: no-repeat;\
  43. background-attachment: fixed;\
  44. background-position: 50% 50%;\
  45. background-size: cover;\
  46. }\
  47. .uoj-content {\
  48. background-color: #fff;\
  49. margin: 16px -16px;\
  50. padding: 16px 16px;\
  51. opacity: ' + getOpacity() + ';\
  52. border-radius: 8px;\
  53. }\
  54. .navbar {\
  55. margin: 16px -16px;\
  56. padding: 8px 16px;\
  57. opacity: ' + getOpacity() + ';\
  58. border-radius: 8px;\
  59. }');
  60. }
  61. }
  62.  
  63. function changeIcon() {
  64. var Links = document.getElementsByTagName('link');
  65. for (var link in Links) {
  66. if (Links[link] && Links[link].nodeType && Links[link].getAttribute('rel') == 'shortcut icon') {
  67. Links[link].setAttribute('href', 'http://124.221.194.184/images/logo_small.png');
  68. }
  69. }
  70. }
  71.  
  72. function CodeBlock() {
  73. GM_addStyle('\
  74. @import url(https://cdn.jsdelivr.net/npm/firacode@6.2.0/distr/fira_code.css);\
  75. code {\
  76. font-family: "Fira Code";\
  77. }\
  78. code.sh_cpp>span {\
  79. font-style: normal !important;\
  80. font-weight: 400 !important;\
  81. }\
  82. code.sh_cpp>span.sh_preproc,\
  83. code.sh_cpp>span.sh_keyword,\
  84. code.sh_cpp>span.sh_type {\
  85. color: #8959a8;\
  86. }\
  87. code.sh_cpp>span.sh_string {\
  88. color: #718c00;\
  89. }\
  90. code.sh_cpp>span.sh_cbracket {\
  91. color: #4d4d4c;\
  92. }\
  93. code.sh_cpp>span.sh_symbol {\
  94. color: #3e999f;\
  95. }\
  96. code.sh_cpp>span.sh_number {\
  97. color: #f5871f;\
  98. }\
  99. code.sh_cpp>span.sh_function {\
  100. color: #4271ae;\
  101. }\
  102. code.sh_cpp>span.sh_comment {\
  103. color: #8e908c;\
  104. }');
  105. var CodeBlocks = document.getElementsByTagName('pre');
  106. for (var cb in CodeBlocks) {
  107. if (CodeBlocks[cb] && CodeBlocks[cb].nodeType) {
  108. console.log(CodeBlocks[cb].textContent);
  109. }
  110. }
  111. }
  112.  
  113. function NameColor() {
  114. var Names = document.getElementsByClassName('uoj-username');
  115. var NeedsRepeat = false;
  116. for (var i in Names) {
  117. if (Names[i].innerHTML && NameColorList[Names[i].innerHTML]) {
  118. Names[i].style = 'color:' + NameColorList[Names[i].innerHTML];
  119. if (Names[i].parentElement.getAttribute('class') == 'legendLabel') {
  120. NeedsRepeat = true;
  121. }
  122. }
  123. }
  124. if (NeedsRepeat) {
  125. setInterval(function(){
  126. var Names = document.getElementsByClassName('uoj-username');
  127. for (var i in Names) {
  128. if (Names[i].innerHTML && Names[i].parentElement.getAttribute('class') == 'legendLabel' && NameColorList[Names[i].innerHTML]) {
  129. Names[i].style = 'color:' + NameColorList[Names[i].innerHTML];
  130. }
  131. }
  132. }, 200);
  133. }
  134. var Honors = document.getElementsByClassName('uoj-honor');
  135. for (var j in Honors) {
  136. if (Honors[j].innerHTML && NameColorList[Honors[j].innerHTML]) {
  137. Honors[j].style = "color:" + NameColorList[Honors[j].innerHTML];
  138. }
  139. }
  140. }
  141.  
  142. const NameWithBadge = /^(.{1,}?)( <.*){0,1}$/;
  143. function CCFBadge() {
  144. var Names = document.getElementsByClassName('uoj-username');
  145. for (var i in Names) {
  146. if (!Names[i].innerHTML || !NameWithBadge.test(Names[i].innerHTML)) continue;
  147. var name = Names[i].innerHTML.match(NameWithBadge)[1];
  148. if (CCFBadgeList[name] && Names[i].parentElement.getAttribute('class') != 'legendLabel') {
  149. 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>';
  150. }
  151. }
  152. var Honors = document.getElementsByClassName('uoj-honor');
  153. for (var j in Honors) {
  154. if (!Honors[j].innerHTML || !NameWithBadge.test(Honors[j].innerHTML)) continue;
  155. var honor = Honors[j].innerHTML.match(NameWithBadge)[1];
  156. if (CCFBadgeList[honor]) {
  157. 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>';
  158. }
  159. }
  160. }
  161. function TagBadge() {
  162. var Names = document.getElementsByClassName('uoj-username');
  163. for (var i in Names) {
  164. if (!Names[i].innerHTML || !NameWithBadge.test(Names[i].innerHTML)) continue;
  165. var name = Names[i].innerHTML.match(NameWithBadge)[1];
  166. if (TagBadgeList[name] && Names[i].parentElement.getAttribute('class') != 'legendLabel') {
  167. 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>';
  168. }
  169. }
  170. var Honors = document.getElementsByClassName('uoj-honor');
  171. for (var j in Honors) {
  172. if (!Honors[j].innerHTML || !NameWithBadge.test(Honors[j].innerHTML)) continue;
  173. var honor = Honors[j].innerHTML.match(NameWithBadge)[1];
  174. if (TagBadgeList[honor]) {
  175. 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>';
  176. }
  177. }
  178. }
  179.  
  180. function TableStyle() {
  181. var Tables = document.getElementsByTagName('table');
  182. for (var table in Tables) {
  183. if (Tables[table].nodeType && Tables[table].parentNode.getAttribute('class') != 'legend' && !Tables[table].classList.length) {
  184. Tables[table].classList.add('table', 'table-bordered');
  185. }
  186. }
  187. var ths = document.getElementsByTagName('th');
  188. for (var th in ths) {
  189. if (ths[th].nodeType && ths[th].getAttribute('align')) {
  190. ths[th].setAttribute('style', 'text-align:' + ths[th].getAttribute('align'));
  191. }
  192. }
  193. }
  194.  
  195. const submissionRegExp = /^http:\/\/124.221.194.184\/submission\/\d{1,}/;
  196. function isSubmission() {
  197. return submissionRegExp.test(window.location.href);
  198. }
  199. function SubmissionCard() {
  200. setTimeout(function() {
  201. var Content = document.getElementsByClassName('uoj-content')[0];
  202. if (Content.childElementCount == 3) {
  203. var Table = Content.children[0];
  204. var TabList = document.createElement('ul');
  205. TabList.setAttribute('class', 'nav nav-tabs');
  206. TabList.setAttribute('role', 'tablist');
  207. 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>';
  208. var TabContent = document.createElement('div');
  209. TabContent.setAttribute('class', 'tab-content');
  210. 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>';
  211. Content.innerHTML = "";
  212. Content.appendChild(Table);
  213. Content.appendChild(TabList);
  214. Content.appendChild(TabContent);
  215. }
  216. }, 10);
  217. }
  218.  
  219. const ProblemRegExp = /^http:\/\/124.221.194.184.*\/problem\/(\d{1,})/;
  220. function isProblem() {
  221. return ProblemRegExp.test(window.location.href);
  222. }
  223. function downloadData() {
  224. var DownloadTag = document.createElement('a');
  225. DownloadTag.setAttribute('role', 'button');
  226. DownloadTag.setAttribute('class', 'btn btn-primary float-right');
  227. DownloadTag.setAttribute('href', '/download.php?type=problem&id=' + window.location.href.match(ProblemRegExp)[1]);
  228. DownloadTag.setAttribute('target', '_blank');
  229. DownloadTag.innerHTML = '<span class="glyphicon glyphicon-download-alt"></span> 下载数据';
  230. document.getElementsByClassName("btn btn-info float-right")[0].after(DownloadTag);
  231. }
  232.  
  233. const UserProfileRegExp = /^http:\/\/124.221.194.184\/user\/profile\/.{1,}/;
  234. function isUserProfile() {
  235. return UserProfileRegExp.test(window.location.href);
  236. }
  237. const BlogRegExp = /^http:\/\/124.221.194.184\/blog\/.{1,}/;
  238. function isBlog() {
  239. return BlogRegExp.test(window.location.href);
  240. }
  241. const GravatarURLRegExp = /\/\/cn.gravatar.com\/avatar\/(.*)$/;
  242. function changeGravatarURL() {
  243. var Gravatar = document.getElementsByClassName('img-thumbnail')[0];
  244. if (Gravatar && Gravatar.nodeType){
  245. console.log(Gravatar);
  246. Gravatar.setAttribute('src', '//gravatar.loli.net/avatar/' + Gravatar.getAttribute('src').match(GravatarURLRegExp)[1]);
  247. }
  248. var Gravatars = document.getElementsByClassName('img-rounded');
  249. for (var gravatar in Gravatars) {
  250. if (Gravatars[gravatar] && Gravatars[gravatar].nodeType && GravatarURLRegExp.test(Gravatars[gravatar].getAttribute('src'))) {
  251. Gravatars[gravatar].setAttribute('src', '//gravatar.loli.net/avatar/' + Gravatars[gravatar].getAttribute('src').match(GravatarURLRegExp)[1]);
  252. }
  253. }
  254. }
  255.  
  256. (function() {
  257. 'use strict';
  258. BackgroundImage();
  259. changeIcon();
  260. CodeBlock();
  261. NameColor();
  262. CCFBadge();
  263. TagBadge();
  264. TableStyle();
  265. if (isSubmission()) SubmissionCard();
  266. if (isProblem()) downloadData();
  267. if (isUserProfile() || isBlog()) changeGravatarURL();
  268. })();