BetterLeetcode

力扣 - 页面清理 | 隐藏会员题目 | 隐藏已完成题目 | 窗口宽度限制 | 去除复制的版权信息 | 中二标题

  1. // ==UserScript==
  2. // @name BetterLeetcode
  3. // @namespace Ninkror
  4. // @version 1.0
  5. // @author Ninkror
  6.  
  7. // @description 力扣 - 页面清理 | 隐藏会员题目 | 隐藏已完成题目 | 窗口宽度限制 | 去除复制的版权信息 | 中二标题
  8.  
  9. // @match https://leetcode.cn/*
  10.  
  11. // @icon https://leetcode.cn/favicon.ico
  12.  
  13. // @grant GM_addStyle
  14. // @grant GM_setValue
  15. // @grant GM_getValue
  16. // @grant GM_registerMenuCommand
  17.  
  18. // @license GPL
  19.  
  20. // @require https://greatest.deepsurf.us/scripts/463455-nelementgetter/code/NElementGetter.js?version=1172110
  21. // ==/UserScript==
  22.  
  23. function problemSetClear() {
  24. const blockList_problemset = [
  25. "#leetcode-navbar > div.display-none.m-auto.h-\\[50px\\].w-full.items-center.justify-center.px-6.md\\:flex.max-w-\\[1200px\\] > ul > li:nth-child(6)", //顶栏 左侧 商店
  26. "#leetcode-navbar > div.display-none.m-auto.h-\\[50px\\].w-full.items-center.justify-center.px-6.md\\:flex.max-w-\\[1200px\\] > div > div > a", //顶栏 右侧 Plus会员
  27.  
  28. "#__next > div.flex.min-h-screen.min-w-\\[360px\\].flex-col.text-label-1.dark\\:text-dark-label-1 > div.mx-auto.w-full.grow.p-4.md\\:mt-0.md\\:max-w-\\[888px\\].md\\:p-6.lg\\:max-w-screen-xl.mt-\\[50px\\].dark\\:bg-dark-layer-bg.bg-white > div.grid.grid-cols-4.gap-4.md\\:grid-cols-3.lg\\:grid-cols-4.lg\\:gap-6 > div.z-base.col-span-4.md\\:col-span-2.lg\\:col-span-3 > div.-mr-2.md\\:mr-0", //主栏 推荐
  29. "#__next > div.flex.min-h-screen.min-w-\\[360px\\].flex-col.text-label-1.dark\\:text-dark-label-1 > div.mx-auto.w-full.grow.p-4.md\\:mt-0.md\\:max-w-\\[888px\\].md\\:p-6.lg\\:max-w-screen-xl.mt-\\[50px\\].dark\\:bg-dark-layer-bg.bg-white > div.grid.grid-cols-4.gap-4.md\\:grid-cols-3.lg\\:grid-cols-4.lg\\:gap-6 > div.z-base.col-span-4.md\\:col-span-2.lg\\:col-span-3 > div:nth-child(2)", //主栏 学习计划
  30.  
  31. "#__next > div.flex.min-h-screen.min-w-\\[360px\\].flex-col.text-label-1.dark\\:text-dark-label-1 > div.mx-auto.w-full.grow.p-4.md\\:mt-0.md\\:max-w-\\[888px\\].md\\:p-6.lg\\:max-w-screen-xl.mt-\\[50px\\].dark\\:bg-dark-layer-bg.bg-white > div.grid.grid-cols-4.gap-4.md\\:grid-cols-3.lg\\:grid-cols-4.lg\\:gap-6 > div.z-base.col-span-4.md\\:col-span-2.lg\\:col-span-3 > div:nth-child(4) > div.-mx-4.transition-opacity.md\\:mx-0 > div > div > div.border-divider-border-2.dark\\:border-dark-divider-border-2.border-b > div > div:nth-child(6)", //主栏 题目列表 表头 出现频率
  32. "#__next > div.flex.min-h-screen.min-w-\\[360px\\].flex-col.text-label-1.dark\\:text-dark-label-1 > div.mx-auto.w-full.grow.p-4.md\\:mt-0.md\\:max-w-\\[888px\\].md\\:p-6.lg\\:max-w-screen-xl.mt-\\[50px\\].dark\\:bg-dark-layer-bg.bg-white > div.grid.grid-cols-4.gap-4.md\\:grid-cols-3.lg\\:grid-cols-4.lg\\:gap-6 > div.z-base.col-span-4.md\\:col-span-2.lg\\:col-span-3 > div:nth-child(4) > div.-mx-4.transition-opacity.md\\:mx-0 > div > div > div:nth-child(2) > div:nth-child(n) > div:nth-child(6)", //主栏 题目列表 表项 出现频率
  33.  
  34. "#__next > div.flex.min-h-screen.min-w-\\[360px\\].flex-col.text-label-1.dark\\:text-dark-label-1 > div.mx-auto.w-full.grow.p-4.md\\:mt-0.md\\:max-w-\\[888px\\].md\\:p-6.lg\\:max-w-screen-xl.mt-\\[50px\\].dark\\:bg-dark-layer-bg.bg-white > div.grid.grid-cols-4.gap-4.md\\:grid-cols-3.lg\\:grid-cols-4.lg\\:gap-6 > div.col-span-4.md\\:col-span-1 > div:nth-child(1) > div > div.mb-2.mt-1.min-h-\\[77px\\].px-4", //右侧栏 日历 Plus会员挑战
  35. "#__next > div.flex.min-h-screen.min-w-\\[360px\\].flex-col.text-label-1.dark\\:text-dark-label-1 > div.mx-auto.w-full.grow.p-4.md\\:mt-0.md\\:max-w-\\[888px\\].md\\:p-6.lg\\:max-w-screen-xl.mt-\\[50px\\].dark\\:bg-dark-layer-bg.bg-white > div.grid.grid-cols-4.gap-4.md\\:grid-cols-3.lg\\:grid-cols-4.lg\\:gap-6 > div.col-span-4.md\\:col-span-1 > div:nth-child(1) > div > div.flex.h-9.items-center.px-4.text-xs.text-label-2.dark\\:text-dark-label-2", //右侧栏 补卡券
  36. "#__next > div.flex.min-h-screen.min-w-\\[360px\\].flex-col.text-label-1.dark\\:text-dark-label-1 > div.mx-auto.w-full.grow.p-4.md\\:mt-0.md\\:max-w-\\[888px\\].md\\:p-6.lg\\:max-w-screen-xl.mt-\\[50px\\].dark\\:bg-dark-layer-bg.bg-white > div.grid.grid-cols-4.gap-4.md\\:grid-cols-3.lg\\:grid-cols-4.lg\\:gap-6 > div.col-span-4.md\\:col-span-1 > div.mt-4.pt-0\\.5.md\\:top-3", //右侧栏 热门企业题库
  37.  
  38. "#__next > div.flex.min-h-screen.min-w-\\[360px\\].flex-col.text-label-1.dark\\:text-dark-label-1 > div.mx-auto.w-full.grow.p-4.md\\:mt-0.md\\:max-w-\\[888px\\].md\\:p-6.lg\\:max-w-screen-xl.mt-\\[50px\\].dark\\:bg-dark-layer-bg.bg-white > div.z-overlay.fixed.bottom-4.right-4.md\\:bottom-\\[31px\\].md\\:right-\\[30px\\]", //右下角浮窗 反馈
  39.  
  40. "#__next > div.flex.min-h-screen.min-w-\\[360px\\].flex-col.text-label-1.dark\\:text-dark-label-1 > footer", //底部
  41. ];
  42. GM_addStyle(blockList_problemset.join(', ') + '{display: none !important}');
  43. }
  44. function vipProblemHide() {
  45. GM_addStyle(`
  46. div[role="row"]:has(.text-brand-orange) {
  47. display: none !important;
  48. }
  49. `);
  50. }
  51. function doneProblemHide() {
  52. GM_addStyle(`
  53. div[role="row"]:has(.text-lc-green-60){
  54. display: none !important;
  55. }
  56. `);
  57. }
  58. function problemClear() {
  59. const globalBlockList = [
  60. "#__next > div.flex.min-w-\\[360px\\].flex-col.overflow-x-auto.text-label-1.dark\\:text-dark-label-1.h-\\[100vh\\] > div > div > div.relative > nav > div > div > div.relative.ml-4.flex.items-center.gap-2 > a", //顶栏右侧 Plus会员
  61. ]
  62. const descriptionBlockList = [
  63. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.flex.gap-1 > div.relative.inline-flex.items-center.justify-center.text-caption.px-2.py-1.gap-1.rounded-full.bg-fill-secondary.cursor-pointer.transition-colors.hover\\:bg-fill-primary.hover\\:text-text-primary.text-sd-secondary-foreground.hover\\:opacity-80", //标题下Tag 相关标签、相关企业、提示
  64.  
  65. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.mt-6.flex.flex-col.gap-3 > div:nth-child(2)", //请问您在哪类招聘中遇到此题?
  66. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.mt-6.flex.flex-col.gap-3 > div:nth-child(5)", //相关标签
  67. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.mt-6.flex.flex-col.gap-3 > hr:nth-child(6)", //相关标签后分隔线
  68. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.mt-6.flex.flex-col.gap-3 > div:nth-child(7)", //相关企业
  69. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.mt-6.flex.flex-col.gap-3 > hr:nth-child(8)", //相关企业后分隔线
  70.  
  71. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.mt-6.flex.flex-col.gap-3 > div:nth-child(19) > div > div.overflow-hidden.transition-all > div > div > div.mt-4.flex-1 > div > div:nth-child(n) > div > div.mt-2.flex.w-full.flex-col.text-label-2.dark\\:text-dark-label-2 > div.mt-4.flex.items-center.gap-4 > div > div.flex.items-center.gap-4.text-xs.opacity-100", //主评论 分享和更多
  72. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.mt-6.flex.flex-col.gap-3 > div:nth-child(19) > div > div.overflow-hidden.transition-all > div > div > div.mt-4.flex-1 > div > div:nth-child(n) > div:nth-child(2) > div.flex.flex-col:nth-child(n) > div > div > div.mt-4.flex.items-center.gap-4.text-xs.text-label-2.dark\\:text-dark-label-2 > div > div.flex.items-center.gap-4.text-xs.opacity-100", //楼中楼 分享和更多
  73.  
  74. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.mt-6.flex.flex-col.gap-3 > div.flex.items-center.justify-between", //贡献者
  75. "div.flexlayout__tab[data-layout-path] > div > div.flex.w-full.flex-1.flex-col.gap-4.overflow-y-auto.px-4.py-5 > div.mt-8", //© 2024 领扣网络(上海)有限公司
  76.  
  77. "div.flexlayout__tab[data-layout-path] > div > div.flex-none > div > div.flex.gap-2 > div:nth-child(2)", //底栏 分享
  78. "div.flexlayout__tab[data-layout-path] > div > div.flex-none > div > div.flex.gap-2 > button", //底栏 反馈
  79. ]
  80. const solutionsBlockList = [
  81. "div.flexlayout__tab[data-layout-path] > div.h-full.w-full.\\!min-w-\\[440px\\] > div > div > div > div.relative.flex.w-full.flex-1.flex-col.overflow-y-auto > div > div:nth-child(2) > div > div.mt-4.flex-1 > div > div:nth-child(n) > div.flex.w-full.flex-col.py-3 > div.mt-2.flex.w-full.flex-col.text-label-2.dark\\:text-dark-label-2 > div.mt-4.flex.items-center.gap-4 > div > div.flex.items-center.gap-4.text-xs.opacity-100", //主评论 分享和更多
  82. "div.flexlayout__tab[data-layout-path] > div.h-full.w-full.\\!min-w-\\[440px\\] > div > div > div > div.relative.flex.w-full.flex-1.flex-col.overflow-y-auto > div > div:nth-child(2) > div > div.mt-4.flex-1 > div > div:nth-child(n) > div:nth-child(2) > div:nth-child(n) > div > div > div.mt-4.flex.items-center.gap-4.text-xs.text-label-2.dark\\:text-dark-label-2 > div > div.flex.items-center.gap-4.text-xs.opacity-100", //楼中楼 分享和更多
  83. ]
  84. const codeBlockList = [
  85. "div.flexlayout__tab[data-layout-path] > #editor > div.flex.h-8.items-center.justify-between.border-b.p-1.border-border-quaternary.dark\\:border-border-quaternary > div.flex.flex-nowrap.items-center > div.group.rounded.px-2.py-0.hover\\:bg-fill-secondary.dark\\:hover\\:bg-fill-secondary", //顶栏 左侧 智能模式
  86. "div.flexlayout__tab[data-layout-path] > #editor > div.flex.justify-between.py-1.pl-3.pr-1 > div.flex.items-center > div.text-caption.flex.items-center.gap-2.text-text-tertiary.dark\\:text-text-tertiary > div", //底栏 左侧 升级云端代码存储
  87. "div.flexlayout__tab[data-layout-path] > #editor > div.flex.justify-between.py-1.pl-3.pr-1 > div.relative.flex.overflow-hidden.rounded.bg-fill-tertiary.dark\\:bg-fill-tertiary.\\!bg-transparent > div.flex-none.flex > div.group.flex.flex-none.items-center.justify-center", //底栏 右侧 Debug按钮
  88. ]
  89. const articleBlockList = [
  90. "div.flexlayout__tab[data-layout-path] > div.h-full.w-full.\\!min-w-\\[440px\\] > div > div > div > div.relative.flex.w-full.flex-1.flex-col.overflow-y-auto > div > div:nth-child(2) > div > div.mt-4.flex-1 > div > div:nth-child(n) > div.flex.w-full.flex-col.py-3 > div.mt-2.flex.w-full.flex-col.text-label-2.dark\\:text-dark-label-2 > div.mt-4.flex.items-center.gap-4 > div > div.flex.items-center.gap-4.text-xs.opacity-100", //主评论 分享和更多
  91. "div.flexlayout__tab[data-layout-path] > div.h-full.w-full.\\!min-w-\\[440px\\] > div > div > div > div.relative.flex.w-full.flex-1.flex-col.overflow-y-auto > div > div:nth-child(2) > div > div.mt-4.flex-1 > div > div:nth-child(n) > div:nth-child(2) > div:nth-child(n) > div > div > div.mt-4.flex.items-center.gap-4.text-xs.text-label-2.dark\\:text-dark-label-2 > div > div.flex.items-center.gap-4.text-xs.opacity-100", //楼中楼 分享和更多
  92. ]
  93.  
  94. GM_addStyle(globalBlockList.join(', ') + '{display: none !important}');
  95. GM_addStyle(descriptionBlockList.join(', ') + '{display: none !important}');
  96. GM_addStyle(solutionsBlockList.join(', ') + '{display:none!important}')
  97. GM_addStyle(codeBlockList.join(', ') + '{display:none!important}')
  98. GM_addStyle(articleBlockList.join(', ') + '{display:none!important}')
  99. }
  100. function widthLimit() {
  101. GM_addStyle(`
  102. * {
  103. max-width: 100vw !important;
  104. }
  105. `)
  106. }
  107. function copyNoRight() {
  108. GM_addStyle(
  109. '.FN9Jv.WRmCx div.h-4.w-4.cursor-pointer.fill-gray-6.hover\\:fill-gray-7.dark\\:fill-dark-gray-6.dark\\:hover\\:fill-dark-gray-7.absolute.right-0.top-0 {display: none !important}'
  110. );
  111. new ElementGetter().each('.FN9Jv.WRmCx > div:has(code)', document, (item) => {
  112. var copyButton = document.createElement('div');
  113. copyButton.className = 'px-3 py-3 text-label-4 dark:text-dark-label-4 hover:text-label-1 dark:hover:text-dark-label-1';
  114. copyButton.style = 'margin-left: auto;';
  115. copyButton.textContent = '复制';
  116. copyButton.onclick = function () {
  117. var nowShow = item.querySelector('div:not(.hidden) > div.group.relative > pre > code');
  118. nowShow.parentElement.nextElementSibling.click();
  119. var assistEle = document.createElement('textarea');
  120. assistEle.value = nowShow.textContent;
  121. document.body.appendChild(assistEle);
  122. assistEle.select();
  123. document.execCommand('copy');
  124. document.body.removeChild(assistEle);
  125. };
  126. item.firstChild.appendChild(copyButton);
  127. });
  128. document.addEventListener('copy', function (e) {
  129. e.preventDefault();
  130. e.stopImmediatePropagation();
  131. e.clipboardData.setData('Text', window.getSelection().toString());
  132. });
  133. }
  134. function handsomeTitle() {
  135. var exchangeList = {
  136. "题目描述": {
  137. "icon": '🏹',
  138. "text": '大军来袭'
  139. },
  140. "题解": {
  141. "icon": '📚',
  142. "text": '先贤之力'
  143. },
  144. "提交记录": {
  145. "icon": '🎖',
  146. "text": '战争勋章'
  147. },
  148. "代码": {
  149. "icon": '🗡',
  150. "text": '前线战场'
  151. },
  152. "题解文章": {
  153. "icon": '',
  154. "text": ''
  155. },
  156. "测试用例": {
  157. "icon": '🎯',
  158. "text": '后方靶场'
  159. },
  160. "测试结果": {
  161. "icon": '🔪',
  162. "text": '刀光剑影'
  163. },
  164. }
  165. new ElementGetter().each('div.flexlayout__tab_button[data-layout-path]', document, (item) => {
  166. var baseDiv = item.querySelector('div.flexlayout__tab_button_content > div.relative.flex.items-center.gap-1.overflow-hidden.text-sm.capitalize')
  167. var iconDiv = baseDiv.children[0]
  168. var textBaseDiv = baseDiv.children[1]
  169. var textFirstDiv = textBaseDiv.children[0]
  170. var textSecondDiv = textBaseDiv.children[1]
  171.  
  172. const title = textFirstDiv.textContent
  173. const exchangeIcon = exchangeList[title] ? exchangeList[title]['icon'] : exchangeList['题解文章']['icon']
  174. const exchangeText = exchangeList[title] ? exchangeList[title]['text'] : exchangeList['题解文章']['text']
  175.  
  176. if(exchangeIcon != '') {
  177. iconDiv.style = "padding-bottom: 14px"
  178. iconDiv.innerHTML = exchangeIcon
  179. }
  180. if(exchangeText != '') {
  181. textFirstDiv.textContent = textSecondDiv.textContent = exchangeText
  182. }
  183. })
  184. }
  185. function contestClear() {
  186. const blockElement = [
  187. "#leetcode-navbar > div.display-none.m-auto.h-\\[50px\\].w-full.items-center.justify-center.px-6.md\\:flex.max-w-\\[1200px\\] > ul > li:nth-child(6)", //顶栏 左侧 商店
  188. "#leetcode-navbar > div.display-none.m-auto.h-\\[50px\\].w-full.items-center.justify-center.px-6.md\\:flex.max-w-\\[1200px\\] > div > div > button", //顶栏 右侧 Plus会员
  189.  
  190. "#lc-footer", //底部
  191. ]
  192. GM_addStyle(blockElement.join(', ') + '{display:none!important}')
  193. }
  194.  
  195. const pathName = window.location.pathname;
  196. const problemSet = pathName.startsWith('/problemset/');
  197. const problems = pathName.startsWith('/problems/');
  198. const contest = pathName.startsWith('/contest/');
  199.  
  200. const funcList = [
  201. {
  202. name: 'problemSetClear',
  203. menu: '题目集页面清理',
  204. match: problemSet,
  205. func: problemSetClear,
  206. },
  207. {
  208. name: 'vipProblemHide',
  209. menu: '隐藏VIP题目',
  210. match: problemSet,
  211. func: vipProblemHide,
  212. },
  213. {
  214. name: 'doneProblemHide',
  215. menu: '隐藏已完成题目',
  216. match: problemSet,
  217. func: doneProblemHide,
  218. },
  219. {
  220. name: 'problemClear',
  221. menu: '题目页面清理',
  222. match: problems,
  223. func: problemClear,
  224. },
  225. {
  226. name: 'widthLimit',
  227. menu: '窗口宽度限制',
  228. match: problems,
  229. func: widthLimit,
  230. },
  231. {
  232. name: 'copyNoRight',
  233. menu: '没有版权信息的复制',
  234. match: problems,
  235. func: copyNoRight,
  236. },
  237. {
  238. name: 'handsomeTitle',
  239. menu: '中二标题',
  240. match: problems,
  241. func: handsomeTitle,
  242. },
  243. {
  244. name: 'contestClear',
  245. menu: '竞赛主页面清理',
  246. match: contest,
  247. func: contestClear,
  248. },
  249. ];
  250.  
  251. funcList.forEach((item) => {
  252. if (item.match) {
  253. const name = item.name;
  254. const menu = item.menu;
  255. if (GM_getValue(name) == undefined) {
  256. GM_setValue(name, true);
  257. }
  258. const open = GM_getValue(name);
  259. GM_registerMenuCommand(`${open ? '✅' : '❌'}${menu}`, function () {
  260. GM_setValue(name, !open);
  261. window.location.reload();
  262. });
  263. if (open) {
  264. item.func();
  265. console.log(`${name} - ${menu} - 已开启`);
  266. }
  267. }
  268. });