0x3f-problem-solution

自定义分数区间显示题目 标记题目状态 配合灵茶山艾府题单解题

当前为 2024-07-28 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name 0x3f-problem-solution
  3. // @namespace https://gf.qytechs.cn/zh-CN/scripts/501134-0x3f-problem-solution
  4. // @version 0.0.4.2
  5. // @author wuxin0011
  6. // @description 自定义分数区间显示题目 标记题目状态 配合灵茶山艾府题单解题
  7. // @license MIT
  8. // @icon https://assets.leetcode.cn/aliyun-lc-upload/users/endlesscheng/avatar_1690721039.png
  9. // @source https://gf.qytechs.cn/zh-CN/scripts/501134-0x3f-problem-solution
  10. // @match https://leetcode.cn/circle/discuss/*
  11. // @match https://leetcode.cn/problems/*
  12. // @match https://leetcode.cn/contest/weekly-contest-*/problems/*
  13. // @match https://leetcode.cn/contest/biweekly-contest-*/problems/*
  14. // @require https://cdn.jsdelivr.net/npm/vue@3.4.31/dist/vue.global.prod.js
  15. // @require data:application/javascript,%3Bwindow.Vue%3DVue%3B
  16. // @require https://unpkg.com/element-plus@2.7.6/dist/index.full.js
  17. // @resource elementPlusCss https://unpkg.com/element-plus@2.7.6/dist/index.css
  18. // @grant GM_addStyle
  19. // @grant GM_deleteValue
  20. // @grant GM_getResourceText
  21. // @grant GM_getValue
  22. // @grant GM_registerMenuCommand
  23. // @grant GM_setValue
  24. // ==/UserScript==
  25.  
  26. (t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const e=document.createElement("style");e.textContent=t,document.head.append(e)})(" .m-setting-button[data-v-37449578]{position:fixed;top:200px;right:0;z-index:100000}.m-button[data-v-37449578]{margin-left:16px!important;padding:5px!important;font-size:14px!important}.processs-flex[data-v-37449578]{display:flex;justify-content:center;align-items:center} ");
  27.  
  28. (function (vue, ElementPlus) {
  29. 'use strict';
  30.  
  31. var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
  32. var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  33. var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  34. var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  35. class Cache {
  36. set(k, v) {
  37. _GM_setValue(k, v);
  38. }
  39. get(k, parse = true, name = String.name) {
  40. try {
  41. let v = _GM_getValue(k);
  42. switch (name) {
  43. case String.name:
  44. if (v == null) {
  45. return "null";
  46. }
  47. return v;
  48. case Object.name:
  49. if (v == null || v == void 0 || typeof v != "object") {
  50. return {};
  51. }
  52. return v;
  53. case Boolean.name:
  54. if (v === null || v == void 0) {
  55. return false;
  56. }
  57. if (v == false || v == "false" || v == "" || v == "null") {
  58. return false;
  59. }
  60. return v;
  61. case Array.name:
  62. if (v === null || v == void 0 || !Array.isArray(v)) {
  63. return [];
  64. }
  65. return v;
  66. default:
  67. return v;
  68. }
  69. } catch (E) {
  70. return null;
  71. }
  72. }
  73. remove(k) {
  74. _GM_deleteValue(k);
  75. }
  76. }
  77. const Cache$1 = new Cache();
  78. const _export_sfc = (sfc, props) => {
  79. const target = sfc.__vccOpts || sfc;
  80. for (const [key, val] of props) {
  81. target[key] = val;
  82. }
  83. return target;
  84. };
  85. const _sfc_main$1 = {};
  86. const _hoisted_1$1 = /* @__PURE__ */ vue.createElementVNode("p", null, " 1. 本人目前测试过,没有封号,但是对于查询过题目会缓存在本地,因此尽量不要清空浏览器缓存 ", -1);
  87. const _hoisted_2$1 = /* @__PURE__ */ vue.createElementVNode("p", null, " 2. 脚本会监控题做题提交状态 ,当题目提交时候会缓存题目状态,如果题单中有这个题目,会直接从缓存中获取 ", -1);
  88. const _hoisted_3$1 = [
  89. _hoisted_1$1,
  90. _hoisted_2$1
  91. ];
  92. function _sfc_render(_ctx, _cache) {
  93. return vue.openBlock(), vue.createElementBlock("div", null, _hoisted_3$1);
  94. }
  95. const Q1 = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render]]);
  96. const isLeetCodeCircleUrl = (url = window.location.href) => url && url.indexOf("https://leetcode.cn/circle") != -1;
  97. const isProblem = (url = window.location.href) => /^https?:\/\/leetcode.cn\/problems\/.*/i.test(url);
  98. const isContest = (url = window.location.href) => url.indexOf("https://leetcode.cn/contest/weekly-contest") != -1 || url.indexOf("https://leetcode.cn/contest/biweekly-contest") != -1;
  99. const width = 14;
  100. const height = 14;
  101. const problemFinsh = () => `
  102.  
  103. <svg width="${width}px" height="${height}px" status="ac" viewBox="0 0 1024 1024" version="1.1"
  104. xmlns="http://www.w3.org/2000/svg">
  105. <path d="M512 512m-448 0a448 448 0 1 0 896 0 448 448 0 1 0-896 0Z" fill="#4CAF50" />
  106. <path
  107. d="M738.133333 311.466667L448 601.6l-119.466667-119.466667-59.733333 59.733334 179.2 179.2 349.866667-349.866667z"
  108. fill="#CCFF90" />
  109. </svg>
  110.  
  111. `;
  112. const problemsTry = () => `
  113. <svg width="${width}px" height="${height}px" status="notac" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
  114. xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512"
  115. style="enable-background:new 0 0 512 512;" xml:space="preserve">
  116. <path style="fill:#FEDEA1;" d="M256,12.8C121.899,12.8,12.8,121.899,12.8,256S121.899,499.2,256,499.2S499.2,390.101,499.2,256
  117. S390.101,12.8,256,12.8z" />
  118. <g>
  119. <path style="fill:#573A32;" d="M256,115.2c-49.271,0-92.561,25.353-117.726,63.676l18.859,18.859
  120. C177.178,163.806,213.734,140.8,256,140.8c63.625,0,115.2,51.567,115.2,115.2h-38.4l51.2,51.2l51.2-51.2h-38.4
  121. C396.8,178.244,333.764,115.2,256,115.2z" />
  122. <path style="fill:#573A32;" d="M256,0C114.62,0,0,114.62,0,256s114.62,256,256,256s256-114.62,256-256S397.38,0,256,0z M256,486.4
  123. C128.956,486.4,25.6,383.044,25.6,256S128.956,25.6,256,25.6S486.4,128.956,486.4,256S383.044,486.4,256,486.4z" />
  124. <path style="fill:#573A32;" d="M256,371.2c-63.625,0-115.2-51.567-115.2-115.2h38.4L128,204.8L76.8,256h38.4
  125. c0,77.756,63.036,140.8,140.8,140.8c49.272,0,92.561-25.353,117.726-63.676l-18.859-18.859
  126. C334.822,348.194,298.266,371.2,256,371.2z" />
  127. </g>
  128. </svg>
  129.  
  130. `;
  131. const problemsNo = () => install_pos() ? `
  132. <svg width="${width}px" height="${height}px" status="null" viewBox="0 0 24 24" id="meteor-icon-kit__regular-circle" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12Z" fill="#758CA3"/></svg>
  133. ` : ``;
  134. const inf = 4e3;
  135. const mi = 1e3;
  136. const __0x3f_problmes_solution__ = "__0x3f_problmes_solution__";
  137. const __0x3f_problmes_urls__ = "__0x3f_problmes_urls__";
  138. const __0x3f_problmes_update__ = "__0x3f_problmes_update__";
  139. const __is_none_0x3f_problmes_button__ = "__is_none_0x3f_problmes_button__";
  140. const __0x3f_problmes_ok_insert_pos__ = "__0x3f_problmes_insert_pos__";
  141. const __add_cur__ = "__add_cur__";
  142. const defaultObj = {
  143. min: mi,
  144. max: inf,
  145. visiableMember: true,
  146. onlyUrls: false,
  147. useDefaultSetting: true,
  148. hiddenAc: false
  149. };
  150. function install_pos() {
  151. return !Cache$1.get(__0x3f_problmes_ok_insert_pos__, false, Boolean.name);
  152. }
  153. function isShow(text, min, max) {
  154. if (!text) {
  155. return true;
  156. }
  157. let res = text.match(/\d+/ig);
  158. if (!res) {
  159. return true;
  160. }
  161. if (Array.isArray(res) && res.length < 2) {
  162. return true;
  163. }
  164. let s = 0;
  165. for (let i = res.length - 1; i >= 0; i--) {
  166. s = res[i];
  167. if (s >= mi && s <= inf) {
  168. return s >= min && s <= max;
  169. }
  170. }
  171. return true;
  172. }
  173. let A = void 0;
  174. const queryProblem = () => Array.from(document.querySelectorAll(".css-1ayia3m-MarkdownContent li>a")).filter((item) => item && item instanceof HTMLAnchorElement && isProblem(item.href));
  175. function loadProblems() {
  176. A = queryProblem();
  177. }
  178. function handlerProblem(data) {
  179. var _a;
  180. try {
  181. loadProblems();
  182. let { min, max, visiableMember, useDefaultSetting, onlyUrls, hiddenAc } = data;
  183. if (isNaN(min) || isNaN(max)) {
  184. min = mi;
  185. max = inf;
  186. }
  187. if (min < mi) {
  188. min = mi;
  189. }
  190. if (max < min) {
  191. max = inf;
  192. }
  193. min = Number(min);
  194. max = Number(max);
  195. data.min = min;
  196. data.max = max;
  197. Cache$1.set(__0x3f_problmes_solution__, data);
  198. for (let i = 0; i < A.length; i++) {
  199. if (!(A[i] instanceof HTMLAnchorElement)) {
  200. continue;
  201. }
  202. let d = (_a = A[i]) == null ? void 0 : _a.parentNode;
  203. if (!d) {
  204. continue;
  205. }
  206. let none = false;
  207. let Nohidden = isShow(d.textContent, min, max);
  208. d.style.display = Nohidden ? "" : "none";
  209. if (!Nohidden) {
  210. continue;
  211. }
  212. if (hiddenAc) {
  213. const svg = d.querySelector("svg");
  214. if (svg && svg.getAttribute("status")) {
  215. d.style.display = svg.getAttribute("status") == STATUS["AC"] ? "none" : "";
  216. }
  217. } else {
  218. d.style.display = "";
  219. }
  220. let c = d.textContent && d.textContent.indexOf("会员") != -1;
  221. if (!c) {
  222. continue;
  223. }
  224. d.style.display = visiableMember ? "" : "none";
  225. }
  226. } catch (e) {
  227. console.log("error", e);
  228. }
  229. }
  230. const initUrls = () => Cache$1.get(__0x3f_problmes_update__, true, Boolean.name) ? Cache$1.get(__0x3f_problmes_urls__, true, Array.name) : defaultUrls;
  231. const initObj = () => Cache$1.get(__0x3f_problmes_solution__) ? Object.assign(defaultObj, Cache$1.get(__0x3f_problmes_solution__)) : defaultObj;
  232. const support_plugins = () => {
  233. const u = initObj();
  234. if (!u || !u.onlyUrls) return true;
  235. let url = window.location.href;
  236. if (isLeetCodeCircleUrl(url) && url.indexOf("view") != -1) {
  237. try {
  238. url = url.split("view")[0];
  239. } catch (e) {
  240. url = window.location.href;
  241. }
  242. }
  243. const urls = initUrls();
  244. for (let info of urls) {
  245. if (!info || !(info == null ? void 0 : info.link)) {
  246. continue;
  247. }
  248. if (info.link.indexOf(url) != -1) {
  249. return true;
  250. }
  251. }
  252. return false;
  253. };
  254. const defaultUrls = [
  255. {
  256. title: "贪心算法(基本贪心策略/反悔/区间/字典序/数学/思维/构造)",
  257. link: "https://leetcode.cn/circle/discuss/g6KTKL/"
  258. },
  259. {
  260. title: "滑动窗口(定长/不定长/多指针)",
  261. link: "https://leetcode.cn/circle/discuss/0viNMK/"
  262. },
  263. {
  264. title: "二分算法(二分答案/最小化最大值/最大化最小值/第K小)",
  265. link: "https://leetcode.cn/circle/discuss/SqopEo/"
  266. },
  267. {
  268. title: "单调栈(矩形面积/贡献法/最小字典序)",
  269. link: "https://leetcode.cn/circle/discuss/9oZFK9/"
  270. },
  271. {
  272. title: "网格图(DFS/BFS/综合应用)",
  273. link: "https://leetcode.cn/circle/discuss/YiXPXW/"
  274. },
  275. {
  276. title: "位运算(基础/性质/拆位/试填/恒等式/贪心/脑筋急转弯)",
  277. link: "https://leetcode.cn/circle/discuss/dHn9Vk/"
  278. },
  279. {
  280. title: "图论算法(DFS/BFS/拓扑排序/最短路/最小生成树/二分图/基环树/欧拉路径)",
  281. link: "https://leetcode.cn/circle/discuss/01LUak/"
  282. },
  283. {
  284. title: "动态规划(入门/背包/状态机/划分/区间/状压/数位/树形/数据结构优化)",
  285. link: "https://leetcode.cn/circle/discuss/tXLS3i/"
  286. },
  287. {
  288. title: "常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)",
  289. link: "https://leetcode.cn/circle/discuss/mOr1u6/"
  290. },
  291. {
  292. title: "数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)",
  293. link: "https://leetcode.cn/circle/discuss/IYT3ss/"
  294. }
  295. ];
  296. function getId(problemUrl) {
  297. if (isContest(problemUrl) || isProblem(problemUrl)) {
  298. try {
  299. return problemUrl.split("problems")[1].split("/")[1];
  300. } catch (e) {
  301. return "";
  302. }
  303. }
  304. return "";
  305. }
  306. const local_ok_problem_key = "__local_ok_problem_key__";
  307. const STATUS = {
  308. "AC": "ac",
  309. "NO": "null",
  310. "notac": "notac"
  311. };
  312. function postData(ID) {
  313. return {
  314. "query": "\n query userQuestionStatus($titleSlug: String!) {\n question(titleSlug: $titleSlug) {\n status\n }\n}\n ",
  315. "variables": {
  316. "titleSlug": ID
  317. },
  318. "operationName": "userQuestionStatus"
  319. };
  320. }
  321. function addProcess(reload = true) {
  322. var _a;
  323. loadProblems();
  324. let problems_doms = A;
  325. const cache = getLocalProblemStatus();
  326. let uid = 0;
  327. let updateCnt = 0;
  328. for (let i = 0; i < problems_doms.length; i++) {
  329. let cur = problems_doms[i].parentElement;
  330. if (!(cur instanceof HTMLElement)) {
  331. continue;
  332. }
  333. const ID = getId((_a = problems_doms[i]) == null ? void 0 : _a.href);
  334. if (!ID) {
  335. continue;
  336. }
  337. if (install_pos()) {
  338. cur.style.listStyleType = "none";
  339. }
  340. if (cache[ID]) {
  341. let status = cache[ID];
  342. uid++;
  343. const svg = cur.querySelector("svg");
  344. if (svg) {
  345. if (svg.getAttribute("status") == status) {
  346. continue;
  347. }
  348. svg.remove();
  349. updateCnt++;
  350. }
  351. if (install_pos()) {
  352. cur.innerHTML = (status == STATUS["AC"] ? problemFinsh() : status == STATUS["notac"] ? problemsTry() : problemsNo()) + cur.innerHTML;
  353. } else {
  354. cur.innerHTML = cur.innerHTML + (status == STATUS["AC"] ? problemFinsh() : status == STATUS["notac"] ? problemsTry() : problemsNo());
  355. }
  356. } else {
  357. fetch("https://leetcode.cn/graphql/", {
  358. method: "POST",
  359. credentials: "include",
  360. headers: {
  361. "Content-Type": "application/json"
  362. },
  363. body: JSON.stringify(postData(ID))
  364. }).then((res) => res.json()).then((response) => {
  365. var _a2, _b;
  366. const status = (_b = (_a2 = response == null ? void 0 : response.data) == null ? void 0 : _a2.question) == null ? void 0 : _b.status;
  367. if (status == STATUS["AC"]) {
  368. cur.innerHTML = install_pos() ? problemFinsh() + cur.innerHTML : cur.innerHTML + problemFinsh();
  369. } else if (status == STATUS["notac"]) {
  370. cur.innerHTML = install_pos() ? problemsTry() + cur.innerHTML : cur.innerHTML + problemsTry();
  371. } else {
  372. if (problemsNo()) {
  373. cur.innerHTML = install_pos() ? problemsNo() + cur.innerHTML : cur.innerHTML + problemsNo();
  374. }
  375. }
  376. cache[ID] = status == null ? "null" : status;
  377. if (cur.parentElement) {
  378. cur.parentElement.status = cache[ID];
  379. }
  380. }).catch((ignore) => {
  381. });
  382. }
  383. }
  384. console.log("cache num :", uid, ",update cnt", updateCnt, ",tot:", A.length);
  385. if (reload) {
  386. let cnt = 10;
  387. let timeId = setInterval(() => {
  388. Cache$1.set(local_ok_problem_key, cache);
  389. cnt--;
  390. if (cnt == 0) {
  391. window.clearInterval(timeId);
  392. }
  393. }, 3e3);
  394. }
  395. }
  396. const submitProblems = (url = window.location.href) => {
  397. const ID = getId(url);
  398. if (!ID) {
  399. return;
  400. }
  401. setTimeout(() => {
  402. const cache = getLocalProblemStatus();
  403. console.log("ID:", ID, "query status: ", cache[ID]);
  404. if (cache[ID] == void 0 || cache[ID] != STATUS["AC"]) {
  405. fetch("https://leetcode.cn/graphql/", {
  406. method: "POST",
  407. credentials: "include",
  408. headers: {
  409. "Content-Type": "application/json"
  410. },
  411. body: JSON.stringify(postData(ID))
  412. }).then((res) => res.json()).then((response) => {
  413. var _a, _b;
  414. const status = (_b = (_a = response == null ? void 0 : response.data) == null ? void 0 : _a.question) == null ? void 0 : _b.status;
  415. if (cache[ID] != status) {
  416. cache[ID] = status == null ? "null" : status;
  417. console.log("save local status :", cache[ID]);
  418. Cache$1.set(local_ok_problem_key, cache);
  419. }
  420. }).catch((ignore) => {
  421. });
  422. }
  423. }, 500);
  424. };
  425. function getProcess() {
  426. loadProblems();
  427. const cache = getLocalProblemStatus();
  428. let cnt = 0;
  429. for (let i = 0; i < A.length; i++) {
  430. let ID = getId(A[i].href);
  431. if (ID && cache[ID] == STATUS["AC"]) {
  432. cnt++;
  433. }
  434. }
  435. return [cnt, A.length];
  436. }
  437. function getLocalProblemStatus() {
  438. return Cache$1.get(local_ok_problem_key, true, Object.name);
  439. }
  440. const _hoisted_1 = { class: "processs-flex" };
  441. const _hoisted_2 = { style: { "text-align": "center", "color": "#121212" } };
  442. const _hoisted_3 = { class: "dialog-footer" };
  443. const formLabelWidth = "44px";
  444. const _sfc_main = {
  445. __name: "App",
  446. setup(__props) {
  447. let totProblem = vue.ref(0);
  448. let finishProblem = vue.ref(0);
  449. const drawer = vue.ref(false);
  450. const viewSetting = () => {
  451. drawer.value = !drawer.value;
  452. let [cur, tot] = getProcess();
  453. finishProblem.value = cur;
  454. totProblem.value = tot;
  455. };
  456. const finishProcess = vue.computed(() => {
  457. try {
  458. const s = String(finishProblem.value / totProblem.value);
  459. let x1 = s.split(".")[1].padEnd(3).substring(0, 3);
  460. return Math.min(100, Number(x1) / 10);
  461. } catch (e) {
  462. return (finishProblem.value / totProblem.value).toFixed(3) * 100;
  463. }
  464. });
  465. const processColors = [
  466. { color: "#f56c6c", percentage: 20 },
  467. { color: "#1989fa", percentage: 40 },
  468. { color: "#e6a23c", percentage: 60 },
  469. { color: "#6f7ad3", percentage: 80 },
  470. { color: "#5cb87a", percentage: 100 }
  471. ];
  472. const fromData = vue.reactive(initObj());
  473. vue.watch(fromData, () => {
  474. handlerProblem(vue.toRaw(Object.assign({}, fromData)));
  475. });
  476. let tableData = vue.reactive(initUrls());
  477. const keywords = vue.ref("");
  478. const dialogTableVisible = vue.ref(false);
  479. const urlsData = vue.computed(() => tableData.filter((v) => v && v.title && v.title.indexOf(keywords.value) != -1));
  480. const isDisabbled = vue.computed(() => !!tableData.find((v) => (v == null ? void 0 : v.link) && (v == null ? void 0 : v.link.indexOf(window.location.href)) != -1));
  481. const dialogFormVisible = vue.ref(false);
  482. const info = vue.reactive({
  483. title: "",
  484. link: "",
  485. status: "add"
  486. });
  487. const addlocal = () => {
  488. if (!isDisabbled) {
  489. return;
  490. }
  491. tableData.unshift({ title: document.title, link: window.location.href });
  492. };
  493. const updateIndex = vue.ref(-1);
  494. const showProblems = () => {
  495. dialogTableVisible.value = true;
  496. let o = Cache$1.get(__add_cur__) == "true" || Cache$1.get(__add_cur__) == true;
  497. if (o) {
  498. addlocal();
  499. }
  500. };
  501. const handlerProblems = (status, updateInfo = { title: "", link: "" }, index = -1) => {
  502. dialogFormVisible.value = true;
  503. info.status = status;
  504. updateIndex.value = index;
  505. Object.assign(info, updateInfo);
  506. };
  507. const handlerMessage = (u, title, link) => {
  508. const a = u ? "添加" : "修改";
  509. const error = !title || !/https?:\/\/.*/.test(link);
  510. if (error) {
  511. ElementPlus.ElMessage.error(`${a} 失败 请保证标题或者链接有效 `);
  512. } else {
  513. ElementPlus.ElMessage.success(`${a} 成功 `);
  514. }
  515. return !error;
  516. };
  517. const addOrUpdate = () => {
  518. if (!handlerMessage(info.status == "add", info.title, info.link)) {
  519. return;
  520. }
  521. if (info.status == "add") {
  522. tableData.unshift({ title: info.title, link: info.link });
  523. } else {
  524. let index = updateIndex.value;
  525. if (index != -1 && index < tableData.length) {
  526. tableData[index].link = info.link;
  527. tableData[index].title = info.title;
  528. }
  529. }
  530. dialogFormVisible.value = false;
  531. };
  532. const deleteProblems = (index) => {
  533. tableData.splice(index, 1);
  534. Cache$1.set(__0x3f_problmes_urls__, vue.toRaw(tableData));
  535. };
  536. const handlerDefault = () => {
  537. ElementPlus.ElMessageBox.confirm(
  538. "确认使用默认题单,将会重置题单?",
  539. "警告",
  540. {
  541. confirmButtonText: "确认",
  542. cancelButtonText: "取消",
  543. type: "warning"
  544. }
  545. ).then(() => {
  546. for (let i = 0; i < tableData.length; i++) {
  547. delete tableData[i];
  548. }
  549. for (let item of defaultUrls) {
  550. tableData.unshift(item);
  551. }
  552. ElementPlus.ElMessage({
  553. type: "success",
  554. message: "重置成功"
  555. });
  556. }).catch(() => {
  557. ElementPlus.ElMessage({
  558. type: "info",
  559. message: "取消重置"
  560. });
  561. });
  562. };
  563. window.addEventListener("beforeunload", () => {
  564. Cache$1.set(__0x3f_problmes_urls__, vue.toRaw(tableData).filter((u) => u != null && u != void 0));
  565. Cache$1.set(__0x3f_problmes_update__, true);
  566. Cache$1.set(__add_cur__, false);
  567. });
  568. vue.onMounted(() => {
  569. if (support_plugins()) {
  570. let times = 30;
  571. let loadTimeId = setInterval(() => {
  572. let a = queryProblem();
  573. times--;
  574. if (Array.isArray(a) && a.length > 0) {
  575. handlerProblem(vue.toRaw(Object.assign({}, fromData)));
  576. addProcess();
  577. window.clearInterval(loadTimeId);
  578. }
  579. if (times == 0) {
  580. window.clearInterval(loadTimeId);
  581. }
  582. }, 200);
  583. setInterval(() => {
  584. addProcess(false);
  585. }, 1e3 * 30);
  586. }
  587. });
  588. const q1 = vue.ref(false);
  589. return (_ctx, _cache) => {
  590. const _component_el_button = vue.resolveComponent("el-button");
  591. const _component_el_progress = vue.resolveComponent("el-progress");
  592. const _component_el_divider = vue.resolveComponent("el-divider");
  593. const _component_el_input = vue.resolveComponent("el-input");
  594. const _component_el_col = vue.resolveComponent("el-col");
  595. const _component_el_form_item = vue.resolveComponent("el-form-item");
  596. const _component_el_switch = vue.resolveComponent("el-switch");
  597. const _component_el_tooltip = vue.resolveComponent("el-tooltip");
  598. const _component_el_form = vue.resolveComponent("el-form");
  599. const _component_el_dialog = vue.resolveComponent("el-dialog");
  600. const _component_el_row = vue.resolveComponent("el-row");
  601. const _component_el_link = vue.resolveComponent("el-link");
  602. const _component_el_table_column = vue.resolveComponent("el-table-column");
  603. const _component_el_table = vue.resolveComponent("el-table");
  604. const _component_el_drawer = vue.resolveComponent("el-drawer");
  605. return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
  606. vue.createElementVNode("div", null, [
  607. vue.createVNode(_component_el_button, {
  608. type: "primary",
  609. style: {},
  610. onClick: viewSetting,
  611. class: "m-setting-button m-button",
  612. circle: "",
  613. size: "large"
  614. }, {
  615. default: vue.withCtx(() => [
  616. vue.createTextVNode(" 0X3F ")
  617. ]),
  618. _: 1
  619. })
  620. ]),
  621. vue.createVNode(_component_el_drawer, {
  622. modelValue: drawer.value,
  623. "onUpdate:modelValue": _cache[17] || (_cache[17] = ($event) => drawer.value = $event),
  624. "with-header": false,
  625. size: "30%"
  626. }, {
  627. default: vue.withCtx(() => [
  628. vue.createElementVNode("div", _hoisted_1, [
  629. vue.createVNode(_component_el_progress, {
  630. type: "circle",
  631. percentage: finishProcess.value,
  632. color: processColors
  633. }, {
  634. default: vue.withCtx(({ percentage }) => [
  635. vue.createElementVNode("p", null, vue.toDisplayString(percentage) + "%", 1)
  636. ]),
  637. _: 1
  638. }, 8, ["percentage"])
  639. ]),
  640. vue.createElementVNode("p", _hoisted_2, vue.toDisplayString(vue.unref(finishProblem)) + " / " + vue.toDisplayString(vue.unref(totProblem)), 1),
  641. vue.createCommentVNode("", true),
  642. vue.createVNode(_component_el_divider),
  643. vue.createVNode(_component_el_form, {
  644. "label-position": "left",
  645. "label-width": "auto",
  646. model: fromData,
  647. style: { "max-width": "600px" }
  648. }, {
  649. default: vue.withCtx(() => [
  650. vue.createVNode(_component_el_form_item, { label: "分数区间" }, {
  651. default: vue.withCtx(() => [
  652. vue.createVNode(_component_el_col, { span: 10 }, {
  653. default: vue.withCtx(() => [
  654. vue.createVNode(_component_el_input, {
  655. modelValue: fromData.min,
  656. "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => fromData.min = $event),
  657. "aria-placeholder": "",
  658. placeholder: " min "
  659. }, null, 8, ["modelValue"])
  660. ]),
  661. _: 1
  662. }),
  663. vue.createVNode(_component_el_col, {
  664. class: "text-center",
  665. span: 1,
  666. style: { "margin": "0 0.5rem" }
  667. }, {
  668. default: vue.withCtx(() => [
  669. vue.createTextVNode("-")
  670. ]),
  671. _: 1
  672. }),
  673. vue.createVNode(_component_el_col, { span: 10 }, {
  674. default: vue.withCtx(() => [
  675. vue.createVNode(_component_el_input, {
  676. modelValue: fromData.max,
  677. "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => fromData.max = $event),
  678. "aria-placeholder": "",
  679. placeholder: " max"
  680. }, null, 8, ["modelValue"])
  681. ]),
  682. _: 1
  683. })
  684. ]),
  685. _: 1
  686. }),
  687. vue.createVNode(_component_el_form_item, { label: "显示会员题" }, {
  688. default: vue.withCtx(() => [
  689. vue.createVNode(_component_el_switch, {
  690. modelValue: fromData.visiableMember,
  691. "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => fromData.visiableMember = $event)
  692. }, null, 8, ["modelValue"])
  693. ]),
  694. _: 1
  695. }),
  696. vue.createVNode(_component_el_form_item, { label: "隐藏AC题目" }, {
  697. default: vue.withCtx(() => [
  698. vue.createVNode(_component_el_switch, {
  699. modelValue: fromData.hiddenAc,
  700. "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => fromData.hiddenAc = $event)
  701. }, null, 8, ["modelValue"])
  702. ]),
  703. _: 1
  704. }),
  705. vue.createVNode(_component_el_form_item, { label: "收藏题单中生效" }, {
  706. default: vue.withCtx(() => [
  707. vue.createVNode(_component_el_tooltip, {
  708. content: "插件只在收藏题单中生效,刷新生效 ",
  709. placement: "bottom-end"
  710. }, {
  711. default: vue.withCtx(() => [
  712. vue.createVNode(_component_el_switch, {
  713. modelValue: fromData.onlyUrls,
  714. "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => fromData.onlyUrls = $event)
  715. }, null, 8, ["modelValue"])
  716. ]),
  717. _: 1
  718. })
  719. ]),
  720. _: 1
  721. }),
  722. vue.createVNode(_component_el_form_item, { label: "使用题单" }, {
  723. default: vue.withCtx(() => [
  724. vue.createVNode(_component_el_switch, {
  725. modelValue: fromData.useDefaultSetting,
  726. "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => fromData.useDefaultSetting = $event)
  727. }, null, 8, ["modelValue"])
  728. ]),
  729. _: 1
  730. })
  731. ]),
  732. _: 1
  733. }, 8, ["model"]),
  734. fromData.useDefaultSetting ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
  735. vue.createVNode(_component_el_divider),
  736. vue.createVNode(_component_el_button, {
  737. plain: "",
  738. onClick: showProblems
  739. }, {
  740. default: vue.withCtx(() => [
  741. vue.createTextVNode(" 查看收藏的题单 ")
  742. ]),
  743. _: 1
  744. }),
  745. vue.createVNode(_component_el_divider)
  746. ], 64)) : vue.createCommentVNode("", true),
  747. vue.createVNode(_component_el_button, {
  748. plain: "",
  749. onClick: _cache[8] || (_cache[8] = ($event) => q1.value = !q1.value)
  750. }, {
  751. default: vue.withCtx(() => [
  752. vue.createTextVNode(" 问题1 ")
  753. ]),
  754. _: 1
  755. }),
  756. vue.createVNode(_component_el_divider),
  757. vue.createVNode(_component_el_dialog, {
  758. modelValue: q1.value,
  759. "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => q1.value = $event),
  760. title: "关于查询状态会不会被封号 ?"
  761. }, {
  762. default: vue.withCtx(() => [
  763. vue.createVNode(Q1)
  764. ]),
  765. _: 1
  766. }, 8, ["modelValue"]),
  767. vue.createVNode(_component_el_dialog, {
  768. modelValue: dialogTableVisible.value,
  769. "onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => dialogTableVisible.value = $event),
  770. title: "题单"
  771. }, {
  772. default: vue.withCtx(() => [
  773. vue.createVNode(_component_el_row, { gutter: 10 }, {
  774. default: vue.withCtx(() => [
  775. vue.createVNode(_component_el_col, { span: 8 }, {
  776. default: vue.withCtx(() => [
  777. vue.createVNode(_component_el_input, {
  778. modelValue: keywords.value,
  779. "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => keywords.value = $event),
  780. placeholder: "请输入关键词过滤",
  781. clearable: ""
  782. }, null, 8, ["modelValue"])
  783. ]),
  784. _: 1
  785. }),
  786. vue.createVNode(_component_el_col, { span: 16 }, {
  787. default: vue.withCtx(() => [
  788. vue.createVNode(_component_el_button, {
  789. plain: "",
  790. onClick: addlocal,
  791. disabled: isDisabbled.value
  792. }, {
  793. default: vue.withCtx(() => [
  794. vue.createTextVNode(" 添加本页 ")
  795. ]),
  796. _: 1
  797. }, 8, ["disabled"]),
  798. vue.createVNode(_component_el_button, {
  799. plain: "",
  800. onClick: _cache[11] || (_cache[11] = ($event) => handlerProblems("add"))
  801. }, {
  802. default: vue.withCtx(() => [
  803. vue.createTextVNode(" 自定义 ")
  804. ]),
  805. _: 1
  806. }),
  807. vue.createVNode(_component_el_button, {
  808. plain: "",
  809. onClick: handlerDefault
  810. }, {
  811. default: vue.withCtx(() => [
  812. vue.createTextVNode(" 默认 ")
  813. ]),
  814. _: 1
  815. })
  816. ]),
  817. _: 1
  818. })
  819. ]),
  820. _: 1
  821. }),
  822. vue.createVNode(_component_el_table, {
  823. data: urlsData.value,
  824. height: "300",
  825. style: { "width": "100%", "margin-top": "10px" }
  826. }, {
  827. default: vue.withCtx(() => [
  828. vue.createVNode(_component_el_table_column, {
  829. label: "标题",
  830. width: "auto",
  831. align: "center"
  832. }, {
  833. default: vue.withCtx((scope) => [
  834. vue.createVNode(_component_el_link, {
  835. href: scope.row.link,
  836. target: "_blank",
  837. type: "default"
  838. }, {
  839. default: vue.withCtx(() => [
  840. vue.createTextVNode(vue.toDisplayString(scope.row.title), 1)
  841. ]),
  842. _: 2
  843. }, 1032, ["href"])
  844. ]),
  845. _: 1
  846. }),
  847. vue.createVNode(_component_el_table_column, {
  848. label: "操作",
  849. width: "auto",
  850. align: "center"
  851. }, {
  852. default: vue.withCtx((scope) => [
  853. vue.createVNode(_component_el_button, {
  854. type: "primary",
  855. size: "small",
  856. onClick: ($event) => handlerProblems("update", scope.row, scope.$index)
  857. }, {
  858. default: vue.withCtx(() => [
  859. vue.createTextVNode("编辑")
  860. ]),
  861. _: 2
  862. }, 1032, ["onClick"]),
  863. vue.createVNode(_component_el_button, {
  864. type: "danger",
  865. size: "small",
  866. onClick: ($event) => deleteProblems(scope.$index)
  867. }, {
  868. default: vue.withCtx(() => [
  869. vue.createTextVNode("删除")
  870. ]),
  871. _: 2
  872. }, 1032, ["onClick"])
  873. ]),
  874. _: 1
  875. })
  876. ]),
  877. _: 1
  878. }, 8, ["data"])
  879. ]),
  880. _: 1
  881. }, 8, ["modelValue"]),
  882. vue.createVNode(_component_el_dialog, {
  883. modelValue: dialogFormVisible.value,
  884. "onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => dialogFormVisible.value = $event),
  885. title: `${info.status == "add" ? "添加" : "编辑"}`,
  886. width: "400"
  887. }, {
  888. footer: vue.withCtx(() => [
  889. vue.createElementVNode("div", _hoisted_3, [
  890. vue.createVNode(_component_el_button, {
  891. onClick: _cache[15] || (_cache[15] = ($event) => dialogFormVisible.value = false)
  892. }, {
  893. default: vue.withCtx(() => [
  894. vue.createTextVNode("取消")
  895. ]),
  896. _: 1
  897. }),
  898. vue.createVNode(_component_el_button, {
  899. type: "primary",
  900. onClick: addOrUpdate
  901. }, {
  902. default: vue.withCtx(() => [
  903. vue.createTextVNode(" 确认 ")
  904. ]),
  905. _: 1
  906. })
  907. ])
  908. ]),
  909. default: vue.withCtx(() => [
  910. vue.createVNode(_component_el_form, null, {
  911. default: vue.withCtx(() => [
  912. vue.createVNode(_component_el_form_item, {
  913. label: "标题",
  914. "label-width": formLabelWidth
  915. }, {
  916. default: vue.withCtx(() => [
  917. vue.createVNode(_component_el_input, {
  918. modelValue: info.title,
  919. "onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => info.title = $event),
  920. autocomplete: "off"
  921. }, null, 8, ["modelValue"])
  922. ]),
  923. _: 1
  924. }),
  925. vue.createVNode(_component_el_form_item, {
  926. label: "链接",
  927. "label-width": formLabelWidth
  928. }, {
  929. default: vue.withCtx(() => [
  930. vue.createVNode(_component_el_input, {
  931. modelValue: info.link,
  932. "onUpdate:modelValue": _cache[14] || (_cache[14] = ($event) => info.link = $event),
  933. autocomplete: "off"
  934. }, null, 8, ["modelValue"])
  935. ]),
  936. _: 1
  937. })
  938. ]),
  939. _: 1
  940. })
  941. ]),
  942. _: 1
  943. }, 8, ["modelValue", "title"])
  944. ]),
  945. _: 1
  946. }, 8, ["modelValue"])
  947. ], 64);
  948. };
  949. }
  950. };
  951. const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-37449578"]]);
  952. const cssLoader = (e) => {
  953. const t = GM_getResourceText(e);
  954. return GM_addStyle(t), t;
  955. };
  956. cssLoader("elementPlusCss");
  957. const stopRankingKey = "__is_stop_rating_ranking__";
  958. let conetstTimeId = null;
  959. function run$1() {
  960. const container = document.querySelector(".contest-question-info .list-group");
  961. if (!container) return;
  962. const ls = Array.from(container.querySelectorAll(".list-group-item .pull-right"));
  963. for (let i = 0; i < 4; i++) {
  964. if (i >= ls.length) {
  965. break;
  966. }
  967. if (ls[i] instanceof HTMLElement) {
  968. ls[i].textContent = "0";
  969. }
  970. }
  971. window.clearInterval(conetstTimeId);
  972. }
  973. function startStopRanking() {
  974. if (!isContest(window.location.href)) {
  975. return;
  976. }
  977. const isNext = !!document.querySelector("#__next");
  978. if (isNext) {
  979. return;
  980. }
  981. const use = Cache$1.get(stopRankingKey);
  982. _GM_registerMenuCommand(`${use ? "使用" : "关闭"} 排行榜`, () => {
  983. Cache$1.set(stopRankingKey, !use);
  984. window.location.reload();
  985. }, { title: "对于不想看到排行榜的可以使用此功能 默认开启" });
  986. if (!use) {
  987. return;
  988. }
  989. conetstTimeId = setInterval(() => {
  990. run$1();
  991. }, 10);
  992. }
  993. const local_url = window.location.href;
  994. let loadID = 0;
  995. let submitCnt = 0;
  996. function watchDom(dom) {
  997. if (!(dom instanceof HTMLElement)) {
  998. return;
  999. }
  1000. let m = new MutationObserver(() => {
  1001. if (submitCnt % 2 == 1) {
  1002. submitProblems(local_url);
  1003. }
  1004. submitCnt++;
  1005. });
  1006. m.observe(dom, {
  1007. childList: true,
  1008. attributes: true
  1009. });
  1010. }
  1011. function run() {
  1012. loadID++;
  1013. if (isProblem(local_url) || isContest(local_url)) {
  1014. if (isProblem(local_url) && loadID == 1) {
  1015. submitProblems(local_url);
  1016. }
  1017. setTimeout(() => {
  1018. let submitbutton = null;
  1019. const isNext = !!document.querySelector("#__next");
  1020. if (isProblem(local_url) || isNext) {
  1021. submitbutton = document.querySelector("div [data-e2e-locator=console-submit-button]");
  1022. } else {
  1023. let buttons = Array.from(document.querySelectorAll(".question-detail-bottom .pull-right button"));
  1024. for (let i = buttons.length - 1; i >= 0; i--) {
  1025. if (buttons[i].textContent.indexOf("提交解答") != -1) {
  1026. submitbutton = buttons[i];
  1027. break;
  1028. }
  1029. }
  1030. }
  1031. if (submitbutton) {
  1032. watchDom(submitbutton);
  1033. } else if (loadID < 10) {
  1034. run();
  1035. }
  1036. }, 3e3);
  1037. } else if (isLeetCodeCircleUrl(local_url)) {
  1038. let Container = null;
  1039. let ok = Cache$1.get(__is_none_0x3f_problmes_button__, true, Boolean.name);
  1040. const start = () => {
  1041. Container = document.createElement("div");
  1042. const body = document.querySelector("body");
  1043. body.append(Container);
  1044. Container.style.display = ok && support_plugins() ? "block" : "none";
  1045. return Container;
  1046. };
  1047. let dom = start();
  1048. const VueApp = vue.createApp(App);
  1049. _GM_registerMenuCommand(`${ok ? "隐藏按钮" : "显示按钮"}`, () => {
  1050. ok = !ok;
  1051. Container.style.display = ok ? "block" : "none";
  1052. Cache$1.set(__is_none_0x3f_problmes_button__, ok);
  1053. }, { title: "可以手动关闭或者显示按钮 默认显示 刷新生效" });
  1054. _GM_registerMenuCommand(`安装到${install_pos() ? "右侧" : "左侧"}`, () => {
  1055. Cache$1.set(__0x3f_problmes_ok_insert_pos__, install_pos());
  1056. window.location.reload();
  1057. }, { title: "AC标记安装位置,默认左侧,刷新生效" });
  1058. _GM_registerMenuCommand(`${initObj().onlyUrls ? "仅在收藏题单页面生效" : "所有题单生效"}`, () => {
  1059. const u = initObj();
  1060. u.onlyUrls = !u.onlyUrls;
  1061. Container.style.display = support_plugins() ? "block" : "none";
  1062. Cache$1.set(__0x3f_problmes_solution__, u);
  1063. });
  1064. _GM_registerMenuCommand(`添加本页`, () => {
  1065. const urls = initUrls();
  1066. let ok2 = false;
  1067. let url = window.location.href;
  1068. for (let info of urls) {
  1069. if (!info || !(info == null ? void 0 : info.link)) {
  1070. continue;
  1071. }
  1072. if (info.link.indexOf(url) != -1) {
  1073. ok2 = true;
  1074. break;
  1075. }
  1076. }
  1077. if (ok2) {
  1078. ElementPlus.ElMessage({
  1079. message: "收藏失败,链接已经存在!",
  1080. type: "error"
  1081. });
  1082. } else {
  1083. if (isLeetCodeCircleUrl(url) && url.indexOf("view") != -1) {
  1084. try {
  1085. url = url.split("view")[0];
  1086. } catch (e) {
  1087. url = window.location.href;
  1088. }
  1089. }
  1090. urls.unshift({
  1091. title: document.title,
  1092. link: url
  1093. });
  1094. Container.style.display = "block";
  1095. Cache$1.set(__0x3f_problmes_urls__, urls);
  1096. Cache$1.set(__0x3f_problmes_update__, true);
  1097. Cache$1.set(__add_cur__, true);
  1098. ElementPlus.ElMessage({
  1099. message: "收藏成功!刷新生效",
  1100. type: "success"
  1101. });
  1102. }
  1103. });
  1104. VueApp.use(ElementPlus).mount(dom);
  1105. }
  1106. }
  1107. run();
  1108. startStopRanking();
  1109.  
  1110. })(Vue, ElementPlus);

QingJ © 2025

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