LeetCode Turbo

Replace monaco with vanilla textarea.

2023-11-14 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

  1. // ==UserScript==
  2. // @name LeetCode Turbo
  3. // @description Replace monaco with vanilla textarea.
  4. // @namespace https://greatest.deepsurf.us/users/197529
  5. // @version 0.1.3
  6. // @author kkocdko
  7. // @license Unlicense
  8. // @match *://leetcode.com/problems/*
  9. // @match *://leetcode.cn/problems/*
  10. // @run-at document-start
  11. // ==/UserScript==
  12. "use strict";
  13.  
  14. const globalThis = this.unsafeWindow || this;
  15. const originFetch = globalThis.fetch;
  16. const textarea = document.createElement("textarea");
  17. // textarea.className =
  18. // "monaco-editor no-user-select showUnused showDeprecated vs";
  19. // textarea.style =
  20. // "font-family: monospace; height: calc(100% + 34px); width: 100%; padding: 6px 10px; white-space: pre; outline: none; margin-top: -34px; ";
  21. // const replaceEditorTimer = setInterval(() => {
  22. // try {
  23. // document
  24. // .querySelector("#editor")
  25. // .children[0].children[1].children[0].replaceWith(textarea);
  26. // clearInterval(replaceEditorTimer);
  27. // } catch (_) {}
  28. // }, 500);
  29. textarea.style =
  30. "font-family: monospace; height: 100%; width: 100%; padding: 6px 10px; white-space: pre; outline: none;";
  31. const replaceEditorTimer = setInterval(() => {
  32. try {
  33. document.querySelector("#editor").replaceWith(textarea);
  34. clearInterval(replaceEditorTimer);
  35. } catch (_) {}
  36. }, 500);
  37. globalThis.fetch = (input, init) => {
  38. if (input?.includes("/lc-monaco/") || input?.includes("/monaco-tm/")) {
  39. throw Error("Monaco editor blocked.");
  40. }
  41. if (input?.endsWith("/submit") || input?.endsWith("/submit/")) {
  42. init.body = JSON.stringify({
  43. ...JSON.parse(init.body),
  44. typed_code: textarea.value,
  45. });
  46. }
  47. return originFetch(input, init);
  48. };
  49. const titleSlug = location.href.split("/problems/")[1].split("/")[0];
  50. fetch("https://leetcode.cn/graphql/", {
  51. headers: { "content-type": "application/json" },
  52. method: "POST",
  53. body: JSON.stringify({
  54. operationName: "questionEditorData",
  55. variables: { titleSlug },
  56. query: `
  57. query questionEditorData($titleSlug: String!) {
  58. question(titleSlug: $titleSlug) {
  59. codeSnippets {
  60. langSlug
  61. code
  62. }
  63. }
  64. }
  65. `,
  66. }),
  67. })
  68. .then((v) => v.json())
  69. .then((v) => {
  70. textarea.value = v.data.question.codeSnippets.find(
  71. (v) => v.langSlug == "cpp"
  72. ).code;
  73. });
  74. // just block the requestAnimationFrame is ok?
  75. globalThis.requestAnimationFrame = () => {};
  76. // make a LRU cache for getComputedStyle
  77. /*
  78. const cache4gcs = new Map();
  79. const originGetComputedStyle = globalThis.getComputedStyle;
  80. globalThis.getComputedStyle = (elt, pseudoElt) => {
  81. if (pseudoElt !== undefined) return originGetComputedStyle(elt, pseudoElt);
  82. let pair = cache4gcs.get(elt);
  83. const now = Date.now();
  84. if (pair === undefined || pair[0] + 900 < now) {
  85. pair = [now, originGetComputedStyle(elt, pseudoElt)];
  86. console.log("miss " + now);
  87. }
  88. cache4gcs.delete(elt);
  89. cache4gcs.set(elt, pair);
  90. if (cache4gcs.size > 32) {
  91. const keys = cache4gcs.keys();
  92. for (let i = 0; i < 8; i++) cache4gcs.delete(keys.next().value);
  93. }
  94. return pair[1];
  95. };
  96. */
  97. // more conservative requestAnimationFrame
  98. /*
  99. const cache4raf = new Map();
  100. const originRequestAnimationFrame = globalThis.requestAnimationFrame;
  101. globalThis.requestAnimationFrame = (callback) => {
  102. const k = callback.toString();
  103. const now = Date.now();
  104. const interval = 200;
  105. if (cache4raf.get(k) > now - interval) {
  106. originRequestAnimationFrame(callback);
  107. } else {
  108. setTimeout(() => {
  109. originRequestAnimationFrame(callback);
  110. }, interval);
  111. }
  112. if (cache4raf.size > 32) {
  113. const keys = cache4raf.keys();
  114. for (let i = 0; i < 8; i++) cache4raf.delete(keys.next().value);
  115. }
  116. };
  117. */
  118.  
  119. // https://leetcode.cn/problems/intersection-of-two-arrays-ii/description/
  120.  
  121. // ublock append ||static.leetcode.cn/lc-monaco/
  122.  
  123. /*
  124. fetch("https://leetcode.cn/graphql/", {
  125. headers: { "content-type": "application/json" },
  126. method: "POST",
  127. body: JSON.stringify({
  128. query:
  129. "\n query questionTitle($titleSlug: String!) {\n question(titleSlug: $titleSlug) {\n questionId\n questionFrontendId\n title\n titleSlug\n isPaidOnly\n difficulty\n likes\n dislikes\n categoryTitle\n }\n}\n ",
  130. variables: { titleSlug: "intersection-of-two-arrays-ii" },
  131. operationName: "questionTitle",
  132. }),
  133. })
  134. .then((v) => v.text())
  135. .then((v) => console.log(v));
  136.  
  137. // 获取预设代码片段
  138. fetch("https://leetcode.cn/graphql/", {
  139. headers: { "content-type": "application/json" },
  140. method: "POST",
  141. body: JSON.stringify({
  142. query:
  143. "\n query questionEditorData($titleSlug: String!) {\n question(titleSlug: $titleSlug) {\n questionId\n questionFrontendId\n codeSnippets {\n lang\n langSlug\n code\n }\n envInfo\n enableRunCode\n hasFrontendPreview\n frontendPreviews\n }\n}\n ",
  144. variables: { titleSlug: "intersection-of-two-arrays-ii" },
  145. operationName: "questionEditorData",
  146. }),
  147. })
  148. .then((v) => v.json())
  149. .then((v) => console.log(v));
  150.  
  151. fetch("https://leetcode.cn/graphql/", {
  152. headers: { "content-type": "application/json" },
  153. method: "POST",
  154. body: JSON.stringify({
  155. query:
  156. "\n query questionContent($titleSlug: String!) {\n question(titleSlug: $titleSlug) {\n content\n editorType\n mysqlSchemas\n dataSchemas\n }\n}\n ",
  157. variables: { titleSlug: "intersection-of-two-arrays-ii" },
  158. operationName: "questionContent",
  159. }),
  160. });
  161.  
  162. fetch("https://leetcode.cn/graphql/", {
  163. headers: { "content-type": "application/json" },
  164. method: "POST",
  165. body: JSON.stringify({
  166. query:
  167. "\n query questionTranslations($titleSlug: String!) {\n question(titleSlug: $titleSlug) {\n translatedTitle\n translatedContent\n }\n}\n ",
  168. variables: { titleSlug: "intersection-of-two-arrays-ii" },
  169. operationName: "questionTranslations",
  170. }),
  171. });
  172. */