CSDN优化

支持手机端和PC端,屏蔽广告,优化浏览体验,自动跳转拦截的URL

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

  1. // ==UserScript==
  2. // @name CSDN优化
  3. // @namespace https://github.com/WhiteSevs/TamperMonkeyScript
  4. // @version 2024.7.5
  5. // @author WhiteSevs
  6. // @description 支持手机端和PC端,屏蔽广告,优化浏览体验,自动跳转拦截的URL
  7. // @license GPL-3.0-only
  8. // @icon https://www.csdn.net/favicon.ico
  9. // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues
  10. // @match *://*.csdn.net/*
  11. // @require https://update.greasyfork.org/scripts/494167/1376186/CoverUMD.js
  12. // @require https://update.greasyfork.org/scripts/456485/1405857/pops.js
  13. // @require https://fastly.jsdelivr.net/npm/qmsg@1.1.2/dist/index.umd.js
  14. // @require https://fastly.jsdelivr.net/npm/@whitesev/utils@1.5.9/dist/index.umd.js
  15. // @require https://fastly.jsdelivr.net/npm/@whitesev/domutils@1.1.2/dist/index.umd.js
  16. // @grant GM_addStyle
  17. // @grant GM_cookie
  18. // @grant GM_deleteValue
  19. // @grant GM_getValue
  20. // @grant GM_info
  21. // @grant GM_registerMenuCommand
  22. // @grant GM_setValue
  23. // @grant GM_unregisterMenuCommand
  24. // @grant GM_xmlhttpRequest
  25. // @grant unsafeWindow
  26. // @run-at document-start
  27. // ==/UserScript==
  28.  
  29. (function (Qmsg, DOMUtils, Utils) {
  30. 'use strict';
  31.  
  32. var _a;
  33. var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
  34. var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  35. var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
  36. var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  37. var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  38. var _GM_unregisterMenuCommand = /* @__PURE__ */ (() => typeof GM_unregisterMenuCommand != "undefined" ? GM_unregisterMenuCommand : void 0)();
  39. var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
  40. var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  41. var _monkeyWindow = /* @__PURE__ */ (() => window)();
  42. const _SCRIPT_NAME_ = "CSDN优化";
  43. const utils = Utils.noConflict();
  44. const domutils = DOMUtils.noConflict();
  45. const pops = _monkeyWindow.pops || _unsafeWindow.pops;
  46. const log = new utils.Log(
  47. _GM_info,
  48. _unsafeWindow.console || _monkeyWindow.console
  49. );
  50. const SCRIPT_NAME = ((_a = _GM_info == null ? void 0 : _GM_info.script) == null ? void 0 : _a.name) || _SCRIPT_NAME_;
  51. const DEBUG = false;
  52. log.config({
  53. debug: DEBUG,
  54. logMaxCount: 1e3,
  55. autoClearConsole: true,
  56. tag: true
  57. });
  58. Qmsg.config(
  59. Object.defineProperties(
  60. {
  61. html: true,
  62. autoClose: true,
  63. showClose: false
  64. },
  65. {
  66. position: {
  67. get() {
  68. return PopsPanel.getValue("qmsg-config-position", "bottom");
  69. }
  70. },
  71. maxNums: {
  72. get() {
  73. return PopsPanel.getValue("qmsg-config-maxnums", 5);
  74. }
  75. },
  76. showReverse: {
  77. get() {
  78. return PopsPanel.getValue("qmsg-config-showreverse", true);
  79. }
  80. },
  81. zIndex: {
  82. get() {
  83. let maxZIndex = Utils.getMaxZIndex();
  84. let popsMaxZIndex = pops.config.Utils.getPopsMaxZIndex(maxZIndex).zIndex;
  85. return Utils.getMaxValue(maxZIndex, popsMaxZIndex) + 100;
  86. }
  87. }
  88. }
  89. )
  90. );
  91. const GM_Menu = new utils.GM_Menu({
  92. GM_getValue: _GM_getValue,
  93. GM_setValue: _GM_setValue,
  94. GM_registerMenuCommand: _GM_registerMenuCommand,
  95. GM_unregisterMenuCommand: _GM_unregisterMenuCommand
  96. });
  97. const httpx = new utils.Httpx(_GM_xmlhttpRequest);
  98. httpx.interceptors.response.use(void 0, (data) => {
  99. log.error(["拦截器-请求错误", data]);
  100. if (data.type === "onabort") {
  101. Qmsg.warning("请求取消");
  102. } else if (data.type === "onerror") {
  103. Qmsg.error("请求异常");
  104. } else if (data.type === "ontimeout") {
  105. Qmsg.error("请求超时");
  106. } else {
  107. Qmsg.error("其它错误");
  108. }
  109. return data;
  110. });
  111. httpx.config({
  112. logDetails: DEBUG
  113. });
  114. ({
  115. Object: {
  116. defineProperty: _unsafeWindow.Object.defineProperty
  117. },
  118. Function: {
  119. apply: _unsafeWindow.Function.prototype.apply,
  120. call: _unsafeWindow.Function.prototype.call
  121. },
  122. Element: {
  123. appendChild: _unsafeWindow.Element.prototype.appendChild
  124. },
  125. setTimeout: _unsafeWindow.setTimeout
  126. });
  127. const addStyle = utils.addStyle;
  128. const KEY = "GM_Panel";
  129. const ATTRIBUTE_KEY = "data-key";
  130. const ATTRIBUTE_DEFAULT_VALUE = "data-default-value";
  131. const CSDNRouter = {
  132. /**
  133. * 判断是否是华为云联盟
  134. * + huaweicloud.csdn.net
  135. */
  136. isHuaWeiCloudBlog() {
  137. return Boolean(/huaweicloud.csdn.net/i.test(window.location.origin));
  138. },
  139. /**
  140. * 判断是否是博客
  141. * + blog.csdn.net
  142. */
  143. isBlog() {
  144. return Boolean(/blog.csdn.net/i.test(window.location.origin));
  145. },
  146. /**
  147. * 判断是否是文库
  148. * + wenku.csdn.net
  149. */
  150. isWenKu() {
  151. return Boolean(/wenku.csdn.net/i.test(window.location.origin));
  152. },
  153. /**
  154. * 判断是否是链接
  155. * + link.csdn.net
  156. */
  157. isLink() {
  158. return window.location.hostname === "link.csdn.net";
  159. },
  160. /**
  161. * 判断是否是搜索
  162. * + so.csdn.net
  163. */
  164. isSo() {
  165. return window.location.hostname === "so.csdn.net";
  166. },
  167. /**
  168. * 判断是否是C知道
  169. * + so.csdn.net/know
  170. * + /chat
  171. * + /so/ai
  172. */
  173. isSoCKnow() {
  174. return this.isSo() && (window.location.pathname.startsWith("/chat") || window.location.pathname.startsWith("/so/ai"));
  175. },
  176. /**
  177. * 判断是否是资源页面
  178. * + download.csdn.net
  179. */
  180. isDownload() {
  181. return window.location.hostname === "download.csdn.net";
  182. }
  183. };
  184. const UISlider = function(text, key, defaultValue, min, max, changeCallBack, getToolTipContent, description) {
  185. let result = {
  186. text,
  187. type: "slider",
  188. description,
  189. attributes: {},
  190. getValue() {
  191. return PopsPanel.getValue(key, defaultValue);
  192. },
  193. getToolTipContent(value) {
  194. if (typeof getToolTipContent === "function") {
  195. return getToolTipContent(value);
  196. } else {
  197. return `${value}`;
  198. }
  199. },
  200. callback(event, value) {
  201. if (typeof changeCallBack === "function") {
  202. if (changeCallBack(event, value)) {
  203. return;
  204. }
  205. }
  206. PopsPanel.setValue(key, value);
  207. },
  208. min,
  209. max
  210. };
  211. if (result.attributes) {
  212. result.attributes[ATTRIBUTE_KEY] = key;
  213. result.attributes[ATTRIBUTE_DEFAULT_VALUE] = defaultValue;
  214. }
  215. return result;
  216. };
  217. const UISwitch = function(text, key, defaultValue, clickCallBack, description) {
  218. let result = {
  219. text,
  220. type: "switch",
  221. description,
  222. attributes: {},
  223. getValue() {
  224. return Boolean(PopsPanel.getValue(key, defaultValue));
  225. },
  226. callback(event, value) {
  227. log.success(`${value ? "开启" : "关闭"} ${text}`);
  228. if (typeof clickCallBack === "function") {
  229. if (clickCallBack(event, value)) {
  230. return;
  231. }
  232. }
  233. PopsPanel.setValue(key, Boolean(value));
  234. },
  235. afterAddToUListCallBack: void 0
  236. };
  237. if (result.attributes) {
  238. result.attributes[ATTRIBUTE_KEY] = key;
  239. result.attributes[ATTRIBUTE_DEFAULT_VALUE] = Boolean(defaultValue);
  240. }
  241. return result;
  242. };
  243. const SettingUIBlog = {
  244. id: "panel-blog",
  245. title: "博客",
  246. isDefault() {
  247. return CSDNRouter.isBlog();
  248. },
  249. forms: [
  250. {
  251. text: "屏蔽",
  252. type: "forms",
  253. forms: [
  254. UISwitch("【屏蔽】登录弹窗", "csdn-blog-shieldLoginDialog", true),
  255. UISwitch(
  256. "【屏蔽】左侧博客信息",
  257. "csdn-blog-shieldLeftBlogContainerAside",
  258. false
  259. ),
  260. UISwitch(
  261. "【屏蔽】右侧目录信息",
  262. "csdn-blog-shieldRightDirectoryInformation",
  263. false
  264. ),
  265. UISwitch("【屏蔽】顶部工具栏", "csdn-blog-shieldTopToolbar", false),
  266. UISwitch(
  267. "【屏蔽】底部的悬浮工具栏",
  268. "csdn-blog-shieldBottomFloatingToolbar",
  269. false
  270. )
  271. ]
  272. },
  273. {
  274. text: "右侧悬浮工具栏",
  275. type: "forms",
  276. forms: [
  277. UISwitch(
  278. "启用",
  279. "csdn-blog-rightToolbarEnable",
  280. true,
  281. void 0,
  282. "创作中心,隐藏/显示侧栏,新手引导,客服、举报..."
  283. ),
  284. UISwitch(
  285. "【添加按钮】前往评论",
  286. "csdn-blog-addGotoRecommandButton",
  287. true,
  288. void 0,
  289. "在悬浮工具栏最后面添加"
  290. ),
  291. UISlider(
  292. "right偏移",
  293. "csdn-blog-rightToolbarRightOffset",
  294. 90,
  295. 0,
  296. document.documentElement.clientWidth,
  297. (event, value) => {
  298. let csdnSideToolbar = document.querySelector(
  299. ".csdn-side-toolbar"
  300. );
  301. domutils.css(csdnSideToolbar, {
  302. right: value + "px"
  303. });
  304. },
  305. (value) => {
  306. return `当前:${value}px,默认:90px`;
  307. }
  308. ),
  309. UISlider(
  310. "top偏移",
  311. "csdn-blog-rightToolbarTopOffset",
  312. 140,
  313. 0,
  314. document.documentElement.clientHeight,
  315. (event, value) => {
  316. let csdnSideToolbar = document.querySelector(
  317. ".csdn-side-toolbar"
  318. );
  319. domutils.css(csdnSideToolbar, {
  320. top: value + "px"
  321. });
  322. },
  323. (value) => {
  324. return `当前:${value}px,默认:90px`;
  325. }
  326. ),
  327. UISwitch(
  328. "【屏蔽】创作中心",
  329. "csdn-blog-rightToolbarCreativeCenter",
  330. false
  331. ),
  332. UISwitch(
  333. "【屏蔽】显示/隐藏侧栏",
  334. "csdn-blog-rightToolbarShowOrSidebar",
  335. false
  336. ),
  337. UISwitch(
  338. "【屏蔽】新手引导",
  339. "csdn-blog-rightToolbarBeginnerGuidance",
  340. false
  341. ),
  342. UISwitch(
  343. "【屏蔽】客服",
  344. "csdn-blog-rightToolbarCustomerService",
  345. false
  346. ),
  347. UISwitch("【屏蔽】举报", "csdn-blog-rightToolbarReport", false),
  348. UISwitch("【屏蔽】返回顶部", "csdn-blog-rightToolbarBackToTop", false)
  349. ]
  350. },
  351. {
  352. text: "内容",
  353. type: "forms",
  354. forms: [
  355. UISwitch(
  356. "【屏蔽】底部xx技能树",
  357. "csdn-blog-shieldBottomSkillTree",
  358. false
  359. ),
  360. UISwitch(
  361. "【屏蔽】选中文字悬浮栏",
  362. "csdn-blog-shieldArticleSearchTip",
  363. false,
  364. void 0,
  365. "选中文字弹出的,例如:搜索、评论、笔记"
  366. ),
  367. UISwitch(
  368. "点击代码块自动展开",
  369. "csdn-blog-clickPreCodeAutomatically",
  370. true,
  371. void 0,
  372. "当鼠标点击代码块区域时,将自动展开内容"
  373. ),
  374. UISwitch(
  375. "自动展开代码块",
  376. "csdn-blog-autoExpandCodeContent",
  377. true,
  378. void 0,
  379. "懒人操作,免手动点击展开"
  380. ),
  381. UISwitch(
  382. "自动展开内容",
  383. "csdn-blog-autoExpandContent",
  384. true,
  385. void 0,
  386. "懒人操作,免手动点击展开"
  387. ),
  388. UISwitch(
  389. "全文居中",
  390. "csdn-blog-articleCenter",
  391. true,
  392. function(event, enable) {
  393. if (enable) {
  394. alert(
  395. "为了更好的呈现效果,请开启功能:【屏蔽】左侧博客信息、【屏蔽】右侧目录信息"
  396. );
  397. }
  398. },
  399. "自动屏蔽左侧和右侧的信息,且将文章居中"
  400. ),
  401. UISwitch("允许选择内容", "csdn-blog-allowSelectContent", true, void 0)
  402. ]
  403. },
  404. {
  405. text: "评论",
  406. type: "forms",
  407. forms: [
  408. UISwitch("屏蔽", "csdn-blog-blockComment", false, void 0, "屏蔽评论"),
  409. UISwitch("优化评论的位置", "csdn-blog-restoreComments", true)
  410. ]
  411. },
  412. {
  413. text: "底部文章",
  414. type: "forms",
  415. forms: [
  416. UISwitch(
  417. "屏蔽",
  418. "csdn-blog-shieldBottomRecommendArticle",
  419. false,
  420. void 0,
  421. "屏蔽底部文章"
  422. ),
  423. UISwitch(
  424. "标识CSDN下载",
  425. "csdn-blog-identityCSDNDownload",
  426. true,
  427. void 0,
  428. "使用红框标识"
  429. ),
  430. UISwitch(
  431. "移除资源下载的文章",
  432. "csdn-blog-removeResourceDownloadArticle",
  433. false,
  434. void 0,
  435. "移除download.csdn.net、www.iteye.com、edu.csdn.net的文章链接"
  436. )
  437. ]
  438. },
  439. {
  440. text: "劫持/拦截",
  441. type: "forms",
  442. forms: [
  443. UISwitch(
  444. "拦截-复制的小尾巴",
  445. "csdn-blog-removeClipboardHijacking",
  446. true
  447. ),
  448. UISwitch(
  449. "劫持-禁止复制",
  450. "csdn-blog-unBlockCopy",
  451. true,
  452. void 0,
  453. "允许点击复制按钮进行复制"
  454. )
  455. ]
  456. }
  457. ]
  458. };
  459. const SettingUILink = {
  460. id: "panel-link",
  461. title: "链接",
  462. isDefault() {
  463. return CSDNRouter.isLink();
  464. },
  465. forms: [
  466. {
  467. text: "功能",
  468. type: "forms",
  469. forms: [
  470. UISwitch(
  471. "重定向链接",
  472. "csdn-link-jumpRedirect",
  473. true,
  474. void 0,
  475. "自动跳转至被拦截的Url链接"
  476. )
  477. ]
  478. }
  479. ]
  480. };
  481. const SettingUIHuaWeiCloud = {
  482. id: "panel-hua-wei-cloud",
  483. title: "华为云开发者联盟",
  484. isDefault() {
  485. return CSDNRouter.isHuaWeiCloudBlog();
  486. },
  487. forms: [
  488. {
  489. text: "功能",
  490. type: "forms",
  491. forms: [
  492. UISwitch(
  493. "自动展开全文",
  494. "csdn-hua-wei-cloud-autoExpandContent",
  495. true
  496. )
  497. ]
  498. },
  499. {
  500. text: "屏蔽",
  501. type: "forms",
  502. forms: [
  503. UISwitch(
  504. "【屏蔽】云开发者任务挑战活动",
  505. "csdn-hua-wei-cloud-shieldCloudDeveloperTaskChallengeEvent",
  506. true
  507. ),
  508. UISwitch(
  509. "【屏蔽】左侧悬浮按钮",
  510. "csdn-hua-wei-cloud-shieldLeftFloatingButton",
  511. false,
  512. function(event, enable) {
  513. if (enable) {
  514. alert(
  515. "开启后将屏蔽【当前阅读量】、【点赞按钮】、【评论按钮】、【分享按钮】"
  516. );
  517. }
  518. }
  519. ),
  520. UISwitch(
  521. "【屏蔽】右侧栏",
  522. "csdn-hua-wei-cloud-blockRightColumn",
  523. false,
  524. function(event, enable) {
  525. if (enable) {
  526. alert(
  527. "开启后将屏蔽【相关产品】-【活动日历】-【运营活动】-【热门标签】"
  528. );
  529. }
  530. }
  531. ),
  532. UISwitch(
  533. "【屏蔽】底部推荐内容",
  534. "csdn-hua-wei-cloud-blockRecommendedContentAtTheBottom",
  535. false
  536. ),
  537. UISwitch(
  538. "【屏蔽】底部更多推荐",
  539. "csdn-hua-wei-cloud-shieldTheBottomForMoreRecommendations",
  540. false
  541. )
  542. ]
  543. }
  544. ]
  545. };
  546. const SettingUIWenKu = {
  547. id: "panel-wenku",
  548. title: "资源",
  549. isDefault() {
  550. return CSDNRouter.isLink();
  551. },
  552. forms: [
  553. {
  554. text: "屏蔽",
  555. type: "forms",
  556. forms: [
  557. UISwitch(
  558. "【屏蔽】资源推荐",
  559. "csdn-wenku-shieldResourceRecommend",
  560. false
  561. ),
  562. UISwitch(
  563. "【屏蔽】右侧用户信息",
  564. "csdn-wenku-shieldRightUserInfo",
  565. false
  566. ),
  567. UISwitch(
  568. "【屏蔽】右侧悬浮工具栏",
  569. "csdn-wenku-shieldRightToolBar",
  570. false
  571. )
  572. ]
  573. }
  574. ]
  575. };
  576. const SettingUISo = {
  577. id: "panel-so",
  578. title: "搜索",
  579. isDefault() {
  580. return CSDNRouter.isSo();
  581. },
  582. forms: [
  583. {
  584. text: "C知道-功能",
  585. type: "forms",
  586. forms: [
  587. UISwitch(
  588. "去除水印",
  589. "csdn-so-cknow-removeMaskCover",
  590. true
  591. )
  592. ]
  593. }
  594. ]
  595. };
  596. const MSettingUIBlog = {
  597. id: "m-panel-blog",
  598. title: "博客",
  599. isDefault() {
  600. return CSDNRouter.isBlog();
  601. },
  602. forms: [
  603. {
  604. text: "屏蔽",
  605. type: "forms",
  606. forms: [
  607. UISwitch(
  608. "【屏蔽】广告",
  609. "m-csdn-blog-removeAds",
  610. true,
  611. void 0,
  612. "包括:登录弹窗、打开APP、ios版本提示等"
  613. ),
  614. UISwitch(
  615. "【屏蔽】顶部Toolbar",
  616. "m-csdn-blog-shieldTopToolbar",
  617. false
  618. )
  619. ]
  620. },
  621. {
  622. text: "内容",
  623. type: "forms",
  624. forms: [
  625. UISwitch(
  626. "允许选中文字",
  627. "m-csdn-blog-allowSelectText",
  628. true,
  629. void 0,
  630. "设置user-select: text;"
  631. ),
  632. UISwitch(
  633. "自动展开",
  634. "m-csdn-blog-autoExpandContent",
  635. true,
  636. void 0,
  637. "包括内容、代码块"
  638. ),
  639. UISwitch(
  640. "不限制代码块的最大高度",
  641. "m-csdn-blog-notLimitCodePreMaxHeight",
  642. false,
  643. void 0,
  644. "让代码块的高度直接被撑开"
  645. )
  646. ]
  647. },
  648. {
  649. text: "评论",
  650. type: "forms",
  651. forms: [
  652. UISwitch(
  653. "屏蔽",
  654. "m-csdn-blog-blockComment",
  655. false,
  656. void 0,
  657. "屏蔽评论区"
  658. ),
  659. UISwitch(
  660. "不限制评论区的最大高度",
  661. "m-csdn-blog-notLimitCommentMaxHeight",
  662. true,
  663. void 0,
  664. "让评论区高度直接被撑开"
  665. )
  666. ]
  667. },
  668. {
  669. text: "底部文章",
  670. type: "forms",
  671. forms: [
  672. UISwitch(
  673. "屏蔽",
  674. "m-csdn-blog-blockBottomArticle",
  675. false,
  676. void 0,
  677. "屏蔽底部文章"
  678. ),
  679. UISwitch(
  680. "移除资源下载的文章",
  681. "m-csdn-blog-removeResourceArticle",
  682. false,
  683. void 0,
  684. "移除download.csdn.net、www.iteye.com、edu.csdn.net的文章链接"
  685. ),
  686. UISwitch(
  687. "重构",
  688. "m-csdn-blog-refactoringRecommendation",
  689. true,
  690. void 0,
  691. "样式统一化"
  692. ),
  693. UISwitch(
  694. "新标签页打开",
  695. "m-csdn-blog-openNewTab",
  696. true,
  697. void 0,
  698. "点击文章,新标签页打开"
  699. )
  700. ]
  701. },
  702. {
  703. text: "劫持/拦截",
  704. type: "forms",
  705. forms: [
  706. UISwitch(
  707. "劫持-禁止复制",
  708. "m-csdn-blog-unBlockCopy",
  709. true,
  710. void 0,
  711. "允许点击复制按钮进行复制"
  712. )
  713. ]
  714. }
  715. ]
  716. };
  717. const MSettingUILink = {
  718. id: "m-panel-link",
  719. title: "链接",
  720. isDefault() {
  721. return CSDNRouter.isLink();
  722. },
  723. forms: [
  724. {
  725. text: "功能",
  726. type: "forms",
  727. forms: [
  728. UISwitch(
  729. "重定向链接",
  730. "m-csdn-link-jumpRedirect",
  731. true,
  732. void 0,
  733. "自动跳转至被拦截的Url链接"
  734. )
  735. ]
  736. }
  737. ]
  738. };
  739. const MSettingUISo = {
  740. id: "panel-so",
  741. title: "搜索",
  742. isDefault() {
  743. return CSDNRouter.isSo();
  744. },
  745. forms: [
  746. {
  747. text: "C知道-功能",
  748. type: "forms",
  749. forms: [
  750. UISwitch(
  751. "去除水印",
  752. "m-csdn-so-cknow-removeMaskCover",
  753. true
  754. )
  755. ]
  756. }
  757. ]
  758. };
  759. const MSettingUIWenKu = {
  760. id: "m-panel-wenku",
  761. title: "文库",
  762. isDefault() {
  763. return CSDNRouter.isWenKu();
  764. },
  765. forms: [
  766. {
  767. text: "屏蔽",
  768. type: "forms",
  769. forms: [
  770. UISwitch(
  771. "【屏蔽】底部工具栏",
  772. "m-csdn-wenku-shieldBottomToolbar",
  773. false
  774. )
  775. ]
  776. }
  777. ]
  778. };
  779. const MSettingUIHuaWeiCloud = {
  780. id: "m-panel-hua-wei-cloud",
  781. title: "华为云开发者联盟",
  782. isDefault() {
  783. return CSDNRouter.isHuaWeiCloudBlog();
  784. },
  785. forms: [
  786. {
  787. text: "功能",
  788. type: "forms",
  789. forms: [
  790. UISwitch(
  791. "自动展开全文",
  792. "m-csdn-hua-wei-cloud-autoExpandContent",
  793. true
  794. )
  795. ]
  796. }
  797. ]
  798. };
  799. const MSettingUIDownload = {
  800. id: "m-panel-download",
  801. title: "资源",
  802. isDefault() {
  803. return CSDNRouter.isDownload();
  804. },
  805. forms: [
  806. {
  807. text: "功能",
  808. type: "forms",
  809. forms: [
  810. UISwitch(
  811. "自动展开资源介绍",
  812. "m-csdn-download-automaticallyExpandResourceIntroduction",
  813. true,
  814. void 0,
  815. "屏蔽资源介绍【展开全部】按钮并展开资源介绍"
  816. )
  817. ]
  818. },
  819. {
  820. text: "屏蔽",
  821. type: "forms",
  822. forms: [
  823. UISwitch(
  824. "【屏蔽】广告",
  825. "m-csdn-download-removeAds",
  826. true,
  827. void 0,
  828. "包括:登录弹窗、会员降价等"
  829. )
  830. ]
  831. }
  832. ]
  833. };
  834. const UISelect = function(text, key, defaultValue, data, callback, description) {
  835. let selectData = [];
  836. if (typeof data === "function") {
  837. selectData = data();
  838. } else {
  839. selectData = data;
  840. }
  841. let result = {
  842. text,
  843. type: "select",
  844. description,
  845. attributes: {},
  846. getValue() {
  847. return PopsPanel.getValue(key, defaultValue);
  848. },
  849. callback(event, isSelectedValue, isSelectedText) {
  850. PopsPanel.setValue(key, isSelectedValue);
  851. if (typeof callback === "function") {
  852. callback(event, isSelectedValue, isSelectedText);
  853. }
  854. },
  855. data: selectData
  856. };
  857. if (result.attributes) {
  858. result.attributes[ATTRIBUTE_KEY] = key;
  859. result.attributes[ATTRIBUTE_DEFAULT_VALUE] = defaultValue;
  860. }
  861. return result;
  862. };
  863. const SettingUICommon = {
  864. id: "component-common",
  865. title: "通用",
  866. forms: [
  867. {
  868. text: "Toast配置",
  869. type: "forms",
  870. forms: [
  871. UISelect(
  872. "Toast位置",
  873. "qmsg-config-position",
  874. "bottom",
  875. [
  876. {
  877. value: "topleft",
  878. text: "左上角"
  879. },
  880. {
  881. value: "top",
  882. text: "顶部"
  883. },
  884. {
  885. value: "topright",
  886. text: "右上角"
  887. },
  888. {
  889. value: "left",
  890. text: "左边"
  891. },
  892. {
  893. value: "center",
  894. text: "中间"
  895. },
  896. {
  897. value: "right",
  898. text: "右边"
  899. },
  900. {
  901. value: "bottomleft",
  902. text: "左下角"
  903. },
  904. {
  905. value: "bottom",
  906. text: "底部"
  907. },
  908. {
  909. value: "bottomright",
  910. text: "右下角"
  911. }
  912. ],
  913. (event, isSelectValue, isSelectText) => {
  914. log.info("设置当前Qmsg弹出位置" + isSelectText);
  915. },
  916. "Toast显示在页面九宫格的位置"
  917. ),
  918. UISelect(
  919. "最多显示的数量",
  920. "qmsg-config-maxnums",
  921. 3,
  922. [
  923. {
  924. value: 1,
  925. text: "1"
  926. },
  927. {
  928. value: 2,
  929. text: "2"
  930. },
  931. {
  932. value: 3,
  933. text: "3"
  934. },
  935. {
  936. value: 4,
  937. text: "4"
  938. },
  939. {
  940. value: 5,
  941. text: "5"
  942. }
  943. ],
  944. void 0,
  945. "限制Toast显示的数量"
  946. ),
  947. UISwitch(
  948. "逆序弹出",
  949. "qmsg-config-showreverse",
  950. false,
  951. void 0,
  952. "修改Toast弹出的顺序"
  953. )
  954. ]
  955. }
  956. // {
  957. // text: "Cookie配置",
  958. // type: "forms",
  959. // forms: [
  960. // UISwitch(
  961. // "启用",
  962. // "httpx-use-cookie-enable",
  963. // false,
  964. // void 0,
  965. // "启用后,将根据下面的配置进行添加cookie"
  966. // ),
  967. // UISwitch(
  968. // "使用document.cookie",
  969. // "httpx-use-document-cookie",
  970. // false,
  971. // void 0,
  972. // "自动根据请求的域名来设置对应的cookie"
  973. // ),
  974. // UITextArea(
  975. // "tieba.baidu.com",
  976. // "httpx-cookie-tieba.baidu.com",
  977. // "",
  978. // void 0,
  979. // void 0,
  980. // "Cookie格式:xxx=xxxx;xxx=xxxx"
  981. // ),
  982. // ],
  983. // },
  984. ]
  985. };
  986. const MSettingUICommon = {
  987. id: "component-common",
  988. title: "通用",
  989. forms: [
  990. {
  991. text: "Toast配置",
  992. type: "forms",
  993. forms: [
  994. UISelect(
  995. "Toast位置",
  996. "qmsg-config-position",
  997. "bottom",
  998. [
  999. {
  1000. value: "topleft",
  1001. text: "左上角"
  1002. },
  1003. {
  1004. value: "top",
  1005. text: "顶部"
  1006. },
  1007. {
  1008. value: "topright",
  1009. text: "右上角"
  1010. },
  1011. {
  1012. value: "left",
  1013. text: "左边"
  1014. },
  1015. {
  1016. value: "center",
  1017. text: "中间"
  1018. },
  1019. {
  1020. value: "right",
  1021. text: "右边"
  1022. },
  1023. {
  1024. value: "bottomleft",
  1025. text: "左下角"
  1026. },
  1027. {
  1028. value: "bottom",
  1029. text: "底部"
  1030. },
  1031. {
  1032. value: "bottomright",
  1033. text: "右下角"
  1034. }
  1035. ],
  1036. (event, isSelectValue, isSelectText) => {
  1037. log.info("设置当前Qmsg弹出位置" + isSelectText);
  1038. },
  1039. "Toast显示在页面九宫格的位置"
  1040. ),
  1041. UISelect(
  1042. "最多显示的数量",
  1043. "qmsg-config-maxnums",
  1044. 3,
  1045. [
  1046. {
  1047. value: 1,
  1048. text: "1"
  1049. },
  1050. {
  1051. value: 2,
  1052. text: "2"
  1053. },
  1054. {
  1055. value: 3,
  1056. text: "3"
  1057. },
  1058. {
  1059. value: 4,
  1060. text: "4"
  1061. },
  1062. {
  1063. value: 5,
  1064. text: "5"
  1065. }
  1066. ],
  1067. void 0,
  1068. "限制Toast显示的数量"
  1069. ),
  1070. UISwitch(
  1071. "逆序弹出",
  1072. "qmsg-config-showreverse",
  1073. false,
  1074. void 0,
  1075. "修改Toast弹出的顺序"
  1076. )
  1077. ]
  1078. }
  1079. // {
  1080. // text: "Cookie配置",
  1081. // type: "forms",
  1082. // forms: [
  1083. // UISwitch(
  1084. // "启用",
  1085. // "httpx-use-cookie-enable",
  1086. // false,
  1087. // void 0,
  1088. // "启用后,将根据下面的配置进行添加cookie"
  1089. // ),
  1090. // UISwitch(
  1091. // "使用document.cookie",
  1092. // "httpx-use-document-cookie",
  1093. // false,
  1094. // void 0,
  1095. // "自动根据请求的域名来设置对应的cookie"
  1096. // ),
  1097. // UITextArea(
  1098. // "tieba.baidu.com",
  1099. // "httpx-cookie-tieba.baidu.com",
  1100. // "",
  1101. // void 0,
  1102. // void 0,
  1103. // "Cookie格式:xxx=xxxx;xxx=xxxx"
  1104. // ),
  1105. // ],
  1106. // },
  1107. ]
  1108. };
  1109. const __PopsPanel__ = {
  1110. data: null,
  1111. oneSuccessExecMenu: null,
  1112. onceExec: null,
  1113. listenData: null
  1114. };
  1115. const PopsPanel = {
  1116. /** 数据 */
  1117. $data: {
  1118. /**
  1119. * 菜单项的默认值
  1120. */
  1121. get data() {
  1122. if (__PopsPanel__.data == null) {
  1123. __PopsPanel__.data = new utils.Dictionary();
  1124. }
  1125. return __PopsPanel__.data;
  1126. },
  1127. /**
  1128. * 成功只执行了一次的项
  1129. */
  1130. get oneSuccessExecMenu() {
  1131. if (__PopsPanel__.oneSuccessExecMenu == null) {
  1132. __PopsPanel__.oneSuccessExecMenu = new utils.Dictionary();
  1133. }
  1134. return __PopsPanel__.oneSuccessExecMenu;
  1135. },
  1136. /**
  1137. * 成功只执行了一次的项
  1138. */
  1139. get onceExec() {
  1140. if (__PopsPanel__.onceExec == null) {
  1141. __PopsPanel__.onceExec = new utils.Dictionary();
  1142. }
  1143. return __PopsPanel__.onceExec;
  1144. },
  1145. /** 脚本名,一般用在设置的标题上 */
  1146. get scriptName() {
  1147. return SCRIPT_NAME;
  1148. },
  1149. /** 菜单项的总值在本地数据配置的键名 */
  1150. key: KEY,
  1151. /** 菜单项在attributes上配置的菜单键 */
  1152. attributeKeyName: ATTRIBUTE_KEY,
  1153. /** 菜单项在attributes上配置的菜单默认值 */
  1154. attributeDefaultValueName: ATTRIBUTE_DEFAULT_VALUE
  1155. },
  1156. /** 监听器 */
  1157. $listener: {
  1158. /**
  1159. * 值改变的监听器
  1160. */
  1161. get listenData() {
  1162. if (__PopsPanel__.listenData == null) {
  1163. __PopsPanel__.listenData = new utils.Dictionary();
  1164. }
  1165. return __PopsPanel__.listenData;
  1166. }
  1167. },
  1168. init() {
  1169. this.initPanelDefaultValue();
  1170. this.initExtensionsMenu();
  1171. },
  1172. initExtensionsMenu() {
  1173. if (_unsafeWindow.top !== _unsafeWindow.self) {
  1174. return;
  1175. }
  1176. GM_Menu.add([
  1177. {
  1178. key: "show_pops_panel_setting",
  1179. text: "⚙ PC端设置",
  1180. autoReload: false,
  1181. isStoreValue: false,
  1182. showText(text) {
  1183. return text;
  1184. },
  1185. callback: () => {
  1186. this.showPanel();
  1187. }
  1188. },
  1189. {
  1190. key: "m_show_pops_panel_setting",
  1191. text: "⚙ 移动端端设置",
  1192. autoReload: false,
  1193. isStoreValue: false,
  1194. showText(text) {
  1195. return text;
  1196. },
  1197. callback: () => {
  1198. this.showMPanel();
  1199. }
  1200. },
  1201. {
  1202. key: "gotoCSDNCKnow",
  1203. text: "⚙ 前往C知道",
  1204. isStoreValue: false,
  1205. autoReload: false,
  1206. showText(text) {
  1207. return text;
  1208. },
  1209. callback() {
  1210. window.open("https://so.csdn.net/chat", "_blank");
  1211. }
  1212. }
  1213. ]);
  1214. },
  1215. /** 初始化本地设置默认的值 */
  1216. initPanelDefaultValue() {
  1217. let that = this;
  1218. function initDefaultValue(config) {
  1219. if (!config["attributes"]) {
  1220. return;
  1221. }
  1222. let key = config.attributes[ATTRIBUTE_KEY];
  1223. let defaultValue = config["attributes"][ATTRIBUTE_DEFAULT_VALUE];
  1224. if (key == null) {
  1225. log.warn(["请先配置键", config]);
  1226. return;
  1227. }
  1228. if (that.$data.data.has(key)) {
  1229. log.warn("请检查该key(已存在): " + key);
  1230. }
  1231. that.$data.data.set(key, defaultValue);
  1232. }
  1233. function loopInitDefaultValue(configList) {
  1234. for (let index = 0; index < configList.length; index++) {
  1235. let configItem = configList[index];
  1236. initDefaultValue(configItem);
  1237. let childForms = configItem.forms;
  1238. if (childForms && Array.isArray(childForms)) {
  1239. loopInitDefaultValue(childForms);
  1240. }
  1241. }
  1242. }
  1243. let contentConfigList = this.getPanelContentConfig().concat(
  1244. this.getMPanelContentConfig()
  1245. );
  1246. for (let index = 0; index < contentConfigList.length; index++) {
  1247. let leftContentConfigItem = contentConfigList[index];
  1248. if (!leftContentConfigItem.forms) {
  1249. continue;
  1250. }
  1251. let rightContentConfigList = leftContentConfigItem.forms;
  1252. if (rightContentConfigList && Array.isArray(rightContentConfigList)) {
  1253. loopInitDefaultValue(rightContentConfigList);
  1254. }
  1255. }
  1256. },
  1257. /**
  1258. * 设置值
  1259. * @param key 键
  1260. * @param value 值
  1261. */
  1262. setValue(key, value) {
  1263. let locaData = _GM_getValue(KEY, {});
  1264. let oldValue = locaData[key];
  1265. locaData[key] = value;
  1266. _GM_setValue(KEY, locaData);
  1267. if (this.$listener.listenData.has(key)) {
  1268. this.$listener.listenData.get(key).callback(key, oldValue, value);
  1269. }
  1270. },
  1271. /**
  1272. * 判断该键是否存在
  1273. * @param key 键
  1274. */
  1275. hasKey(key) {
  1276. let locaData = _GM_getValue(KEY, {});
  1277. return key in locaData;
  1278. },
  1279. /**
  1280. * 获取值
  1281. * @param key 键
  1282. * @param defaultValue 默认值
  1283. */
  1284. getValue(key, defaultValue) {
  1285. let locaData = _GM_getValue(KEY, {});
  1286. let localValue = locaData[key];
  1287. if (localValue == null) {
  1288. if (this.$data.data.has(key)) {
  1289. return this.$data.data.get(key);
  1290. }
  1291. return defaultValue;
  1292. }
  1293. return localValue;
  1294. },
  1295. /**
  1296. * 删除值
  1297. * @param key 键
  1298. */
  1299. deleteValue(key) {
  1300. let locaData = _GM_getValue(KEY, {});
  1301. let oldValue = locaData[key];
  1302. Reflect.deleteProperty(locaData, key);
  1303. _GM_setValue(KEY, locaData);
  1304. if (this.$listener.listenData.has(key)) {
  1305. this.$listener.listenData.get(key).callback(key, oldValue, void 0);
  1306. }
  1307. },
  1308. /**
  1309. * 监听调用setValue、deleteValue
  1310. * @param key 需要监听的键
  1311. * @param callback
  1312. */
  1313. addValueChangeListener(key, callback) {
  1314. let listenerId = Math.random();
  1315. this.$listener.listenData.set(key, {
  1316. id: listenerId,
  1317. key,
  1318. callback
  1319. });
  1320. return listenerId;
  1321. },
  1322. /**
  1323. * 移除监听
  1324. * @param listenerId 监听的id
  1325. */
  1326. removeValueChangeListener(listenerId) {
  1327. let deleteKey = null;
  1328. for (const [key, value] of this.$listener.listenData.entries()) {
  1329. if (value.id === listenerId) {
  1330. deleteKey = key;
  1331. break;
  1332. }
  1333. }
  1334. if (typeof deleteKey === "string") {
  1335. this.$listener.listenData.delete(deleteKey);
  1336. } else {
  1337. console.warn("没有找到对应的监听器");
  1338. }
  1339. },
  1340. /**
  1341. * 自动判断菜单是否启用,然后执行回调
  1342. * @param key
  1343. * @param callback 回调
  1344. */
  1345. execMenu(key, callback) {
  1346. if (typeof key !== "string") {
  1347. throw new TypeError("key 必须是字符串");
  1348. }
  1349. if (!this.$data.data.has(key)) {
  1350. log.warn(`${key} 键不存在`);
  1351. return;
  1352. }
  1353. let value = PopsPanel.getValue(key);
  1354. if (value) {
  1355. callback(value);
  1356. }
  1357. },
  1358. /**
  1359. * 自动判断菜单是否启用,然后执行回调,只会执行一次
  1360. * @param key
  1361. * @param callback 回调
  1362. */
  1363. execMenuOnce(key, callback) {
  1364. if (typeof key !== "string") {
  1365. throw new TypeError("key 必须是字符串");
  1366. }
  1367. if (!this.$data.data.has(key)) {
  1368. log.warn(`${key} 键不存在`);
  1369. return;
  1370. }
  1371. let value = PopsPanel.getValue(key);
  1372. if (value) {
  1373. if (this.$data.oneSuccessExecMenu.has(key)) {
  1374. return;
  1375. }
  1376. callback(value);
  1377. this.$data.oneSuccessExecMenu.set(key, 1);
  1378. }
  1379. },
  1380. /**
  1381. * 根据key执行一次
  1382. * @param key
  1383. */
  1384. onceExec(key, callback) {
  1385. if (typeof key !== "string") {
  1386. throw new TypeError("key 必须是字符串");
  1387. }
  1388. if (this.$data.onceExec.has(key)) {
  1389. return;
  1390. }
  1391. callback();
  1392. this.$data.onceExec.set(key, 1);
  1393. },
  1394. /**
  1395. * 显示设置面板
  1396. */
  1397. showPanel() {
  1398. pops.panel({
  1399. title: {
  1400. text: `${SCRIPT_NAME}-PC端设置`,
  1401. position: "center",
  1402. html: false,
  1403. style: ""
  1404. },
  1405. content: this.getPanelContentConfig(),
  1406. mask: {
  1407. enable: true,
  1408. clickEvent: {
  1409. toClose: true,
  1410. toHide: false
  1411. }
  1412. },
  1413. isMobile: this.isMobile(),
  1414. width: this.getWidth(),
  1415. height: this.getHeight(),
  1416. drag: true,
  1417. only: true
  1418. });
  1419. },
  1420. /**
  1421. * 显示设置面板
  1422. */
  1423. showMPanel() {
  1424. pops.panel({
  1425. title: {
  1426. text: `${SCRIPT_NAME}-移动端设置`,
  1427. position: "center",
  1428. html: false,
  1429. style: ""
  1430. },
  1431. content: this.getMPanelContentConfig(),
  1432. mask: {
  1433. enable: true,
  1434. clickEvent: {
  1435. toClose: true,
  1436. toHide: false
  1437. }
  1438. },
  1439. isMobile: this.isMobile(),
  1440. width: this.getWidth(),
  1441. height: this.getHeight(),
  1442. drag: true,
  1443. only: true
  1444. });
  1445. },
  1446. isMobile() {
  1447. return window.outerWidth < 550;
  1448. },
  1449. /**
  1450. * 获取设置面板的宽度
  1451. */
  1452. getWidth() {
  1453. if (window.outerWidth < 800) {
  1454. return "92dvw";
  1455. } else {
  1456. return "800px";
  1457. }
  1458. },
  1459. /**
  1460. * 获取设置面板的高度
  1461. */
  1462. getHeight() {
  1463. if (window.outerHeight > 450) {
  1464. return "80dvh";
  1465. } else {
  1466. return "450px";
  1467. }
  1468. },
  1469. /**
  1470. * 获取配置内容
  1471. */
  1472. getPanelContentConfig() {
  1473. let configList = [
  1474. SettingUICommon,
  1475. SettingUIBlog,
  1476. SettingUILink,
  1477. SettingUIHuaWeiCloud,
  1478. SettingUIWenKu,
  1479. SettingUISo
  1480. ];
  1481. return configList;
  1482. },
  1483. /**
  1484. * 获取配置内容
  1485. */
  1486. getMPanelContentConfig() {
  1487. let configList = [
  1488. MSettingUICommon,
  1489. MSettingUIBlog,
  1490. MSettingUILink,
  1491. MSettingUIHuaWeiCloud,
  1492. MSettingUIWenKu,
  1493. MSettingUISo,
  1494. MSettingUIDownload
  1495. ];
  1496. return configList;
  1497. }
  1498. };
  1499. const ShieldCSS$4 = "/* 底部免费抽xxx奖品广告 */\r\ndiv.siderbar-box,\r\n/* 华为开发者联盟加入社区 */\r\ndiv.user-desc.user-desc-fix {\r\n display: none !important;\r\n}\r\n";
  1500. const CSDNUtils = {
  1501. /**
  1502. * 移除元素(未出现也可以等待出现)
  1503. * @param selectorText 元素选择器
  1504. */
  1505. waitForElementToRemove(selectorText = "") {
  1506. utils.waitNodeList(selectorText).then((nodeList) => {
  1507. nodeList.forEach((item) => item.remove());
  1508. });
  1509. },
  1510. /**
  1511. * 添加屏蔽CSS
  1512. * @param args
  1513. * @example
  1514. * addBlockCSS("")
  1515. * addBlockCSS("","")
  1516. * addBlockCSS(["",""])
  1517. */
  1518. addBlockCSS(...args) {
  1519. let selectorList = [];
  1520. if (args.length === 0) {
  1521. return;
  1522. }
  1523. if (args.length === 1 && typeof args[0] === "string" && args[0].trim() === "") {
  1524. return;
  1525. }
  1526. args.forEach((selector) => {
  1527. if (Array.isArray(selector)) {
  1528. selectorList = selectorList.concat(selector);
  1529. } else {
  1530. selectorList.push(selector);
  1531. }
  1532. });
  1533. addStyle(`${selectorList.join(",\n")}{display: none !important;}`);
  1534. }
  1535. };
  1536. const CSDNHuaWeiCloud = {
  1537. init() {
  1538. addStyle(ShieldCSS$4);
  1539. PopsPanel.execMenu(
  1540. "csdn-hua-wei-cloud-shieldCloudDeveloperTaskChallengeEvent",
  1541. () => {
  1542. this.shieldCloudDeveloperTaskChallengeEvent();
  1543. }
  1544. );
  1545. PopsPanel.execMenu("csdn-hua-wei-cloud-autoExpandContent", () => {
  1546. this.autoExpandContent();
  1547. });
  1548. PopsPanel.execMenu("csdn-hua-wei-cloud-shieldLeftFloatingButton", () => {
  1549. this.shieldLeftFloatingButton();
  1550. });
  1551. PopsPanel.execMenu("csdn-hua-wei-cloud-blockRightColumn", () => {
  1552. this.blockRightColumn();
  1553. });
  1554. PopsPanel.execMenu(
  1555. "csdn-hua-wei-cloud-blockRecommendedContentAtTheBottom",
  1556. () => {
  1557. this.blockRecommendedContentAtTheBottom();
  1558. }
  1559. );
  1560. PopsPanel.execMenu(
  1561. "csdn-hua-wei-cloud-shieldTheBottomForMoreRecommendations",
  1562. () => {
  1563. this.shieldTheBottomForMoreRecommendations();
  1564. }
  1565. );
  1566. },
  1567. /**
  1568. * 自动展开内容
  1569. */
  1570. autoExpandContent() {
  1571. log.info("自动展开全文");
  1572. CSDNUtils.addBlockCSS("div.article-show-more");
  1573. addStyle(`
  1574. /* 自动展开全文 */
  1575. .main-content .user-article{
  1576. height: auto !important;
  1577. overflow: auto !important;
  1578. }
  1579. `);
  1580. },
  1581. /**
  1582. * 屏蔽云开发者任务挑战活动
  1583. */
  1584. shieldCloudDeveloperTaskChallengeEvent() {
  1585. let GM_cookie = new utils.GM_Cookie();
  1586. GM_cookie.set({ name: "show_join_group_index", value: 1 });
  1587. log.info("设置Cookie 屏蔽云开发者任务挑战活动");
  1588. },
  1589. /**
  1590. * 屏蔽左侧悬浮按钮
  1591. */
  1592. shieldLeftFloatingButton() {
  1593. log.info("屏蔽左侧悬浮按钮,包括当前阅读量、点赞按钮、评论按钮、分享按钮");
  1594. CSDNUtils.addBlockCSS("div.toolbar-wrapper.article-interact-bar");
  1595. },
  1596. /**
  1597. * 屏蔽右侧栏
  1598. */
  1599. blockRightColumn() {
  1600. log.info("屏蔽右侧栏,包括相关产品-活动日历-运营活动-热门标签");
  1601. CSDNUtils.addBlockCSS("div.page-home-right.dp-aside-right");
  1602. },
  1603. /**
  1604. * 屏蔽底部推荐内容
  1605. */
  1606. blockRecommendedContentAtTheBottom() {
  1607. log.info("屏蔽底部推荐内容");
  1608. CSDNUtils.addBlockCSS("div.recommend-card-box");
  1609. },
  1610. /**
  1611. * 屏蔽底部更多推荐
  1612. */
  1613. shieldTheBottomForMoreRecommendations() {
  1614. log.info("屏蔽底部更多推荐");
  1615. CSDNUtils.addBlockCSS("div.more-article");
  1616. }
  1617. };
  1618. const BlogShieldCSS = ".ecommend-item-box.recommend-recommend-box,\r\n.login-mark,\r\n.opt-box.text-center,\r\n.leftPop,\r\n#csdn-shop-window,\r\n.toolbar-advert,\r\n.hide-article-box,\r\n.user-desc.user-desc-fix,\r\n.recommend-card-box,\r\n.more-article,\r\n.article-show-more,\r\n#csdn-toolbar-profile-nologin,\r\n.guide-rr-first,\r\n#recommend-item-box-tow,\r\n/* 发文章得原力分图片提示 */\r\ndiv.csdn-toolbar-creative-mp,\r\n/* 阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。 */\r\n#toolBarBox div.write-guide-buttom-box,\r\n/* 觉得还不错? 一键收藏 */\r\nul.toolbox-list div.tool-active-list,\r\n/* 右边按钮组的最上面的创作话题 */\r\ndiv.csdn-side-toolbar .activity-swiper-box,\r\n.sidetool-writeguide-box .tip-box,\r\n/* 右下角的登录提示 */\r\n.passport-login-tip-container {\r\n display: none !important;\r\n}\r\n\r\n\r\n";
  1619. const BlogCSS = "/*.blog_container_aside,\r\n#nav {\r\n margin-left: -45px;\r\n}\r\n.recommend-right.align-items-stretch.clearfix,\r\n.dl_right_fixed {\r\n margin-left: 45px;\r\n}*/\r\n";
  1620. const BlogArticleCenterCSS = '#mainBox main {\r\n width: inherit !important;\r\n}\r\n/* 当文章向下滚动时,触发左侧信息悬浮 */\r\naside.blog_container_aside[style*="position: fixed;"] {\r\n display: none !important;\r\n}\r\n\r\n@media (min-width: 1320px) and (max-width: 1380px) {\r\n .nodata .container {\r\n width: 900px !important;\r\n }\r\n\r\n .nodata .container main {\r\n width: 900px;\r\n }\r\n\r\n .nodata .container main #pcCommentBox pre > ol.hljs-ln {\r\n width: 490px !important;\r\n }\r\n\r\n .nodata .container main .articleConDownSource {\r\n width: 500px;\r\n }\r\n}\r\n\r\n@media screen and (max-width: 1320px) {\r\n .nodata .container {\r\n width: 760px !important;\r\n }\r\n\r\n .nodata .container main {\r\n width: 760px;\r\n }\r\n\r\n .nodata .container main #pcCommentBox pre > ol.hljs-ln {\r\n width: 490px !important;\r\n }\r\n\r\n .nodata .container main .toolbox-list .tool-reward {\r\n display: none;\r\n }\r\n\r\n .nodata\r\n .container\r\n main\r\n .more-toolbox-new\r\n .toolbox-left\r\n .profile-box\r\n .profile-name {\r\n max-width: 128px;\r\n }\r\n\r\n .nodata .container main .articleConDownSource {\r\n width: 420px;\r\n }\r\n}\r\n\r\n@media screen and (min-width: 1380px) {\r\n .nodata .container {\r\n width: 1010px !important;\r\n }\r\n\r\n .nodata .container main {\r\n width: 1010px;\r\n }\r\n\r\n .nodata .container main #pcCommentBox pre > ol.hljs-ln {\r\n width: 490px !important;\r\n }\r\n\r\n .nodata .container main .articleConDownSource {\r\n width: 560px;\r\n }\r\n}\r\n\r\n@media (min-width: 1550px) and (max-width: 1700px) {\r\n .nodata .container {\r\n width: 820px !important;\r\n }\r\n\r\n .nodata .container main {\r\n width: 820px;\r\n }\r\n\r\n .nodata .container main #pcCommentBox pre > ol.hljs-ln {\r\n width: 690px !important;\r\n }\r\n\r\n .nodata .container main .articleConDownSource {\r\n width: 500px;\r\n }\r\n}\r\n\r\n@media screen and (min-width: 1700px) {\r\n .nodata .container {\r\n width: 1010px !important;\r\n }\r\n\r\n .nodata .container main {\r\n width: 1010px;\r\n }\r\n\r\n .nodata .container main #pcCommentBox pre > ol.hljs-ln {\r\n width: 690px !important;\r\n }\r\n\r\n .nodata .container main .articleConDownSource {\r\n width: 560px;\r\n }\r\n}\r\n';
  1621. const CSDNBlogRightToolBar = {
  1622. init() {
  1623. if (!PopsPanel.getValue("csdn-blog-rightToolbarEnable")) {
  1624. this.shieldRightToolbar();
  1625. }
  1626. PopsPanel.execMenuOnce("csdn-blog-rightToolbarCreativeCenter", () => {
  1627. this.shieldCreativeCenter();
  1628. });
  1629. PopsPanel.execMenuOnce("csdn-blog-rightToolbarShowOrSidebar", () => {
  1630. this.shieldShowOrSidebar();
  1631. });
  1632. PopsPanel.execMenuOnce("csdn-blog-rightToolbarBeginnerGuidance", () => {
  1633. this.shieldBeginnerGuidance();
  1634. });
  1635. PopsPanel.execMenuOnce("csdn-blog-rightToolbarCustomerService", () => {
  1636. this.shieldCustomerService();
  1637. });
  1638. PopsPanel.execMenuOnce("csdn-blog-rightToolbarReport", () => {
  1639. this.shieldReport();
  1640. });
  1641. PopsPanel.execMenuOnce("csdn-blog-rightToolbarBackToTop", () => {
  1642. this.shieldBackToTop();
  1643. });
  1644. this.initRightToolbarOffset();
  1645. domutils.ready(() => {
  1646. PopsPanel.execMenu("csdn-blog-addGotoRecommandButton", () => {
  1647. this.addGotoRecommandButton();
  1648. });
  1649. });
  1650. },
  1651. /**
  1652. * 屏蔽右侧工具栏
  1653. */
  1654. shieldRightToolbar() {
  1655. log.info("屏蔽右侧工具栏");
  1656. CSDNUtils.addBlockCSS(`div.csdn-side-toolbar`);
  1657. },
  1658. /**
  1659. * 【添加】前往评论按钮,在返回顶部的下面
  1660. */
  1661. addGotoRecommandButton() {
  1662. log.info("【添加】前往评论按钮,在返回顶部的上面");
  1663. let gotoRecommandNode = document.createElement("a");
  1664. gotoRecommandNode.className = "option-box";
  1665. gotoRecommandNode.setAttribute("data-type", "gorecommand");
  1666. gotoRecommandNode.innerHTML = `<span class="show-txt" style="display:flex;opacity:100;">前往<br>评论</span>`;
  1667. gotoRecommandNode.addEventListener("click", function() {
  1668. let toolbarBoxElement = document.querySelector(
  1669. "#toolBarBox"
  1670. );
  1671. if (!toolbarBoxElement.getClientRects().length) {
  1672. log.error("评论区处于隐藏状态");
  1673. return;
  1674. }
  1675. log.info("滚动到评论");
  1676. let toolbarBoxOffsetTop = toolbarBoxElement.getBoundingClientRect().top + window.scrollY;
  1677. let csdnToolBarElement = document.querySelector(
  1678. "#csdn-toolbar"
  1679. );
  1680. let csdnToolBarStyles = window.getComputedStyle(csdnToolBarElement);
  1681. let csdnToolBarHeight = csdnToolBarElement.clientHeight - parseFloat(csdnToolBarStyles.paddingTop) - parseFloat(csdnToolBarStyles.paddingBottom);
  1682. window.scrollTo({
  1683. top: toolbarBoxOffsetTop - csdnToolBarHeight - 8,
  1684. left: 0,
  1685. behavior: "smooth"
  1686. });
  1687. });
  1688. utils.waitNode(".csdn-side-toolbar").then(() => {
  1689. let targetElement = document.querySelector(
  1690. ".csdn-side-toolbar a:nth-last-child(2)"
  1691. );
  1692. targetElement.parentElement.insertBefore(
  1693. gotoRecommandNode,
  1694. targetElement.nextSibling
  1695. );
  1696. });
  1697. },
  1698. /**
  1699. * 初始化右侧工具栏的偏移(top、right)
  1700. */
  1701. initRightToolbarOffset() {
  1702. log.info("初始化右侧工具栏的偏移(top、right)");
  1703. addStyle(`
  1704. .csdn-side-toolbar{
  1705. left: unset !important;
  1706. }
  1707. `);
  1708. utils.waitNode(".csdn-side-toolbar").then(($sideToolbar) => {
  1709. domutils.css($sideToolbar, {
  1710. top: parseInt(PopsPanel.getValue("csdn-blog-rightToolbarTopOffset")) + "px",
  1711. right: parseInt(PopsPanel.getValue("csdn-blog-rightToolbarRightOffset")) + "px"
  1712. });
  1713. });
  1714. },
  1715. /**
  1716. * 【屏蔽】创作中心
  1717. */
  1718. shieldCreativeCenter() {
  1719. log.info("【屏蔽】创作中心");
  1720. CSDNUtils.addBlockCSS(".csdn-side-toolbar .sidetool-writeguide-box");
  1721. },
  1722. /**
  1723. * 【屏蔽】显示/隐藏侧栏
  1724. */
  1725. shieldShowOrSidebar() {
  1726. log.info("【屏蔽】显示/隐藏侧栏");
  1727. CSDNUtils.addBlockCSS(".csdn-side-toolbar a.sidecolumn");
  1728. },
  1729. /**
  1730. * 【屏蔽】新手引导
  1731. */
  1732. shieldBeginnerGuidance() {
  1733. log.info("【屏蔽】新手引导");
  1734. CSDNUtils.addBlockCSS('.csdn-side-toolbar a.option-box[data-type="guide"]');
  1735. },
  1736. /**
  1737. * 【屏蔽】客服
  1738. */
  1739. shieldCustomerService() {
  1740. log.info("【屏蔽】客服");
  1741. CSDNUtils.addBlockCSS('.csdn-side-toolbar a.option-box[data-type="cs"]');
  1742. },
  1743. /**
  1744. * 【屏蔽】举报
  1745. */
  1746. shieldReport() {
  1747. log.info("【屏蔽】举报");
  1748. CSDNUtils.addBlockCSS(
  1749. '.csdn-side-toolbar a.option-box[data-type="report"]'
  1750. );
  1751. },
  1752. /**
  1753. * 【屏蔽】返回顶部
  1754. */
  1755. shieldBackToTop() {
  1756. log.info("【屏蔽】返回顶部");
  1757. CSDNUtils.addBlockCSS('.csdn-side-toolbar a.option-box[data-type="gotop"]');
  1758. }
  1759. };
  1760. const CSDNBlog = {
  1761. init() {
  1762. this.addCSS();
  1763. CSDNBlogRightToolBar.init();
  1764. PopsPanel.execMenu("csdn-blog-articleCenter", () => {
  1765. this.articleCenter();
  1766. });
  1767. PopsPanel.execMenu("csdn-blog-shieldLoginDialog", () => {
  1768. this.shieldLoginDialog();
  1769. });
  1770. PopsPanel.execMenu("csdn-blog-autoExpandContent", () => {
  1771. this.autoExpandContent();
  1772. });
  1773. PopsPanel.execMenu("csdn-blog-autoExpandCodeContent", () => {
  1774. this.autoExpandCodeContent();
  1775. });
  1776. PopsPanel.execMenu("csdn-blog-blockComment", () => {
  1777. this.blockComment();
  1778. });
  1779. PopsPanel.execMenu("csdn-blog-shieldBottomRecommendArticle", () => {
  1780. this.shieldBottomRecommendArticle();
  1781. });
  1782. PopsPanel.execMenu("csdn-blog-shieldBottomSkillTree", () => {
  1783. this.shieldBottomSkillTree();
  1784. });
  1785. PopsPanel.execMenu("csdn-blog-shieldBottomFloatingToolbar", () => {
  1786. this.shieldBottomFloatingToolbar();
  1787. });
  1788. PopsPanel.execMenu("csdn-blog-shieldLeftBlogContainerAside", () => {
  1789. this.shieldLeftBlogContainerAside();
  1790. });
  1791. PopsPanel.execMenu("csdn-blog-shieldRightDirectoryInformation", () => {
  1792. this.shieldRightDirectoryInformation();
  1793. });
  1794. PopsPanel.execMenu("csdn-blog-shieldTopToolbar", () => {
  1795. this.shieldTopToolbar();
  1796. });
  1797. PopsPanel.execMenu("csdn-blog-shieldArticleSearchTip", () => {
  1798. this.shieldArticleSearchTip();
  1799. });
  1800. PopsPanel.execMenu("csdn-blog-allowSelectContent", () => {
  1801. this.allowSelectContent();
  1802. });
  1803. domutils.ready(() => {
  1804. PopsPanel.execMenu("csdn-blog-removeClipboardHijacking", () => {
  1805. this.removeClipboardHijacking();
  1806. });
  1807. PopsPanel.execMenuOnce("csdn-blog-unBlockCopy", () => {
  1808. this.unBlockCopy();
  1809. });
  1810. PopsPanel.execMenu("csdn-blog-identityCSDNDownload", () => {
  1811. this.identityCSDNDownload();
  1812. });
  1813. PopsPanel.execMenuOnce("csdn-blog-clickPreCodeAutomatically", () => {
  1814. this.clickPreCodeAutomatically();
  1815. });
  1816. PopsPanel.execMenu("csdn-blog-restoreComments", () => {
  1817. this.restoreComments();
  1818. });
  1819. });
  1820. },
  1821. /**
  1822. * 添加屏蔽CSS和功能CSS
  1823. */
  1824. addCSS() {
  1825. log.info("添加屏蔽CSS和功能CSS");
  1826. addStyle(BlogShieldCSS);
  1827. addStyle(BlogCSS);
  1828. },
  1829. /**
  1830. * 去除剪贴板劫持
  1831. */
  1832. removeClipboardHijacking() {
  1833. var _a2;
  1834. log.info("去除剪贴板劫持");
  1835. (_a2 = document.querySelector(".article-copyright")) == null ? void 0 : _a2.remove();
  1836. if (_unsafeWindow.articleType) {
  1837. _unsafeWindow.articleType = 0;
  1838. }
  1839. if (_unsafeWindow.csdn && _unsafeWindow.csdn.copyright && _unsafeWindow.csdn.copyright.textData) {
  1840. _unsafeWindow.csdn.copyright.textData = "";
  1841. }
  1842. if (_unsafeWindow.csdn && _unsafeWindow.csdn.copyright && _unsafeWindow.csdn.copyright.htmlData) {
  1843. _unsafeWindow.csdn.copyright.htmlData = "";
  1844. }
  1845. },
  1846. /**
  1847. * 取消禁止复制
  1848. */
  1849. unBlockCopy() {
  1850. log.info("取消禁止复制");
  1851. domutils.on(
  1852. document,
  1853. "click",
  1854. function(event) {
  1855. let $click = event.target;
  1856. let $parent = $click.parentElement;
  1857. if (!$click.classList.contains("hljs-button")) {
  1858. return;
  1859. }
  1860. utils.preventEvent(event);
  1861. let copyText = ($parent.innerText || $parent.textContent || "").toString();
  1862. log.info(
  1863. "点击复制按钮复制内容:" + (copyText.length > 8 ? copyText.substring(0, 8) + "..." : copyText)
  1864. );
  1865. utils.setClip(copyText);
  1866. $click.setAttribute("data-title", "复制成功");
  1867. },
  1868. {
  1869. capture: true
  1870. }
  1871. );
  1872. let changeDataTitle = new utils.LockFunction(function(event) {
  1873. let $mouse = event.target;
  1874. if ($mouse.localName !== "pre") {
  1875. return;
  1876. }
  1877. let $hljsBtn = $mouse.querySelector(".hljs-button");
  1878. if ($hljsBtn) {
  1879. $hljsBtn.setAttribute("data-title", "复制");
  1880. }
  1881. });
  1882. domutils.on(
  1883. document,
  1884. ["mouseenter", "mouseleave"],
  1885. function(event) {
  1886. changeDataTitle.run(event);
  1887. },
  1888. {
  1889. capture: true
  1890. }
  1891. );
  1892. utils.waitNode("#content_views").then(($content_views) => {
  1893. var _a2;
  1894. if (_unsafeWindow.$) {
  1895. (_a2 = _unsafeWindow.$("#content_views")) == null ? void 0 : _a2.unbind("copy");
  1896. }
  1897. domutils.on(
  1898. $content_views,
  1899. "copy",
  1900. function(event) {
  1901. utils.preventEvent(event);
  1902. let selectText = _unsafeWindow.getSelection();
  1903. let copyText = selectText == null ? void 0 : selectText.toString();
  1904. log.info(
  1905. "Ctrl+C复制内容:" + (copyText.length > 8 ? copyText.substring(0, 8) + "..." : copyText)
  1906. );
  1907. utils.setClip(copyText);
  1908. return false;
  1909. },
  1910. {
  1911. capture: true
  1912. }
  1913. );
  1914. });
  1915. utils.waitNode(".hljs-button").then(() => {
  1916. setTimeout(() => {
  1917. document.querySelectorAll(".hljs-button").forEach((element) => {
  1918. element.removeAttribute("onclick");
  1919. element.removeAttribute("data-report-click");
  1920. element.setAttribute("data-title", "复制");
  1921. });
  1922. }, 250);
  1923. });
  1924. },
  1925. /**
  1926. * 点击代码块自动展开
  1927. */
  1928. clickPreCodeAutomatically() {
  1929. log.info("点击代码块自动展开");
  1930. document.addEventListener("click", function(event) {
  1931. var _a2;
  1932. let $click = event.target;
  1933. if ($click.localName !== "pre") {
  1934. return;
  1935. }
  1936. $click.style.setProperty("height", "auto");
  1937. (_a2 = $click.querySelector(".hide-preCode-box")) == null ? void 0 : _a2.remove();
  1938. });
  1939. },
  1940. /**
  1941. * 恢复评论到正确位置
  1942. */
  1943. restoreComments() {
  1944. log.info("恢复评论到正确位置-第一条评论");
  1945. utils.waitNode(".first-recommend-box").then(($firstRecommendBox) => {
  1946. let recommendBoxElement = document.querySelector(
  1947. ".recommend-box.insert-baidu-box.recommend-box-style"
  1948. );
  1949. recommendBoxElement.insertBefore(
  1950. $firstRecommendBox,
  1951. recommendBoxElement.firstChild
  1952. );
  1953. });
  1954. log.info("恢复评论到正确位置-第二条评论");
  1955. utils.waitNode(".second-recommend-box").then(($secondRecommendBox) => {
  1956. let recommendBoxElement = document.querySelector(
  1957. ".recommend-box.insert-baidu-box.recommend-box-style"
  1958. );
  1959. recommendBoxElement.insertBefore(
  1960. $secondRecommendBox,
  1961. recommendBoxElement.firstChild
  1962. );
  1963. });
  1964. },
  1965. /**
  1966. * 标识CSDN下载的链接
  1967. */
  1968. identityCSDNDownload() {
  1969. log.info("标识CSDN下载的链接");
  1970. document.querySelectorAll(
  1971. ".recommend-item-box[data-url*='https://download.csdn.net/']"
  1972. ).forEach((item) => {
  1973. if (PopsPanel.getValue("csdn-blog-removeResourceDownloadArticle")) {
  1974. item.remove();
  1975. } else {
  1976. item.querySelector(".content-box").style.setProperty("border", "2px solid red");
  1977. }
  1978. });
  1979. },
  1980. /**
  1981. * 全文居中
  1982. */
  1983. articleCenter() {
  1984. log.info("全文居中");
  1985. addStyle(BlogArticleCenterCSS);
  1986. },
  1987. /**
  1988. * 屏蔽登录弹窗
  1989. */
  1990. shieldLoginDialog() {
  1991. log.info("屏蔽登录弹窗");
  1992. CSDNUtils.addBlockCSS(`.passport-login-container`);
  1993. },
  1994. /**
  1995. * 自动展开代码块
  1996. */
  1997. autoExpandCodeContent() {
  1998. log.info("自动展开代码块");
  1999. CSDNUtils.addBlockCSS("pre.set-code-hide .hide-preCode-box");
  2000. addStyle(`
  2001. pre.set-code-hide{
  2002. height: auto !important;
  2003. }
  2004. /* 自动展开代码块 */
  2005. .comment-list-box,
  2006. main div.blog-content-box pre {
  2007. max-height: none !important;
  2008. }
  2009. `);
  2010. },
  2011. /**
  2012. * 自动展开全文
  2013. */
  2014. autoExpandContent() {
  2015. log.info("自动展开全文");
  2016. addStyle(`
  2017. /* 自动展开全文 */
  2018. #article_content,
  2019. .user-article.user-article-hide {
  2020. height: auto !important;
  2021. overflow: auto !important;
  2022. }
  2023. `);
  2024. },
  2025. /**
  2026. * 屏蔽评论区
  2027. */
  2028. blockComment() {
  2029. log.info("屏蔽评论区");
  2030. CSDNUtils.addBlockCSS(`#pcCommentBox`);
  2031. },
  2032. /**
  2033. * 屏蔽底部推荐文章
  2034. */
  2035. shieldBottomRecommendArticle() {
  2036. log.info("屏蔽底部推荐文章");
  2037. CSDNUtils.addBlockCSS(`main > div.recommend-box`);
  2038. },
  2039. /**
  2040. * 屏蔽底部xx技能树
  2041. */
  2042. shieldBottomSkillTree() {
  2043. log.info("屏蔽底部xx技能树");
  2044. CSDNUtils.addBlockCSS(`#treeSkill`);
  2045. },
  2046. /**
  2047. * 屏蔽底部悬浮工具栏
  2048. */
  2049. shieldBottomFloatingToolbar() {
  2050. log.info("屏蔽底部悬浮工具栏");
  2051. CSDNUtils.addBlockCSS(`#toolBarBox`);
  2052. },
  2053. /**
  2054. * 屏蔽左侧博客信息
  2055. */
  2056. shieldLeftBlogContainerAside() {
  2057. log.info("【屏蔽】左侧博客信息");
  2058. CSDNUtils.addBlockCSS(`aside.blog_container_aside`);
  2059. },
  2060. /**
  2061. * 【屏蔽】右侧目录信息
  2062. */
  2063. shieldRightDirectoryInformation() {
  2064. log.info("【屏蔽】右侧目录信息");
  2065. CSDNUtils.addBlockCSS("#rightAsideConcision", "#rightAside");
  2066. },
  2067. /**
  2068. * 屏蔽顶部Toolbar
  2069. */
  2070. shieldTopToolbar() {
  2071. log.info("屏蔽顶部Toolbar");
  2072. CSDNUtils.addBlockCSS(`#toolbarBox`);
  2073. },
  2074. /**
  2075. * 屏蔽文章内的选中搜索悬浮提示
  2076. */
  2077. shieldArticleSearchTip() {
  2078. log.info("屏蔽文章内的选中搜索悬浮提示");
  2079. CSDNUtils.addBlockCSS(`#articleSearchTip`);
  2080. },
  2081. /**
  2082. * 允许选择内容
  2083. */
  2084. allowSelectContent() {
  2085. log.info("允许选择内容");
  2086. addStyle(`
  2087. #content_views,
  2088. #content_views pre,
  2089. #content_views pre code {
  2090. user-select: text !important;
  2091. }
  2092. `);
  2093. }
  2094. };
  2095. const WenkuCSS = "#chatgpt-article-detail\r\n > div.layout-center\r\n > div.main\r\n > div.article-box\r\n > div.cont.first-show.forbid {\r\n max-height: unset !important;\r\n height: auto !important;\r\n overflow: auto !important;\r\n}\r\n\r\n.forbid {\r\n user-select: text !important;\r\n}\r\n";
  2096. const ShieldCSS$3 = "/* wenku顶部横幅 */\r\n#app > div > div.main.pb-32 > div > div.top-bar,\r\n/* 底部展开全文 */\r\n#chatgpt-article-detail > div.layout-center > div.main > div.article-box > div.cont.first-show.forbid > div.open {\r\n display: none !important;\r\n}";
  2097. const CSDNWenKu = {
  2098. init() {
  2099. addStyle(WenkuCSS);
  2100. addStyle(ShieldCSS$3);
  2101. PopsPanel.execMenu("csdn-wenku-shieldResourceRecommend", () => {
  2102. this.shieldResourceRecommend();
  2103. });
  2104. PopsPanel.execMenu("csdn-wenku-shieldRightUserInfo", () => {
  2105. this.shieldRightUserInfo();
  2106. });
  2107. PopsPanel.execMenu("csdn-wenku-shieldRightToolBar", () => {
  2108. this.shieldRightToolBar();
  2109. });
  2110. },
  2111. /**
  2112. * 【屏蔽】资源推荐
  2113. */
  2114. shieldResourceRecommend() {
  2115. log.info("【屏蔽】资源推荐");
  2116. CSDNUtils.addBlockCSS("#recommend");
  2117. },
  2118. /**
  2119. * 【屏蔽】右侧用户信息
  2120. */
  2121. shieldRightUserInfo() {
  2122. log.info("【屏蔽】右侧用户信息");
  2123. CSDNUtils.addBlockCSS(".layout-right");
  2124. },
  2125. /**
  2126. * 【屏蔽】右侧悬浮工具栏
  2127. */
  2128. shieldRightToolBar() {
  2129. log.info("【屏蔽】右侧悬浮工具栏");
  2130. CSDNUtils.addBlockCSS(".csdn-side-toolbar");
  2131. }
  2132. };
  2133. const CSDNLink = {
  2134. init() {
  2135. PopsPanel.execMenu("csdn-link-jumpRedirect", () => {
  2136. this.jumpRedirect();
  2137. });
  2138. },
  2139. /**
  2140. * 去除CSDN拦截其它网址的url并自动跳转
  2141. */
  2142. jumpRedirect() {
  2143. if (window.location.hostname === "link.csdn.net" && window.location.search.startsWith("?target")) {
  2144. window.stop();
  2145. let search = window.location.search.replace(/^\?target=/gi, "");
  2146. search = decodeURIComponent(search);
  2147. let newURL = search;
  2148. log.success(`跳转链接 ${newURL}`);
  2149. window.location.href = newURL;
  2150. }
  2151. }
  2152. };
  2153. const CSDN = {
  2154. init() {
  2155. if (CSDNRouter.isLink()) {
  2156. log.info("Router: 中转链接");
  2157. CSDNLink.init();
  2158. } else if (CSDNRouter.isHuaWeiCloudBlog()) {
  2159. log.info("Router: 华为云联盟");
  2160. CSDNHuaWeiCloud.init();
  2161. } else if (CSDNRouter.isBlog()) {
  2162. log.info("Router: 博客");
  2163. CSDNBlog.init();
  2164. } else if (CSDNRouter.isWenKu()) {
  2165. log.info("Router: 文库");
  2166. CSDNWenKu.init();
  2167. } else {
  2168. log.error("暂未适配,请反馈开发者:" + globalThis.location.href);
  2169. }
  2170. }
  2171. };
  2172. const M_CSDNLink = {
  2173. init() {
  2174. PopsPanel.execMenu("m-csdn-link-jumpRedirect", () => {
  2175. CSDNLink.jumpRedirect();
  2176. });
  2177. }
  2178. };
  2179. const ShieldCSS$2 = "/* 右下角的 免费赢华为平板xxxx */\r\n.org-main-content .siderbar-box {\r\n display: none !important;\r\n}\r\n";
  2180. const M_CSDNHuaWeiCloud = {
  2181. init() {
  2182. addStyle(ShieldCSS$2);
  2183. PopsPanel.execMenu("m-csdn-hua-wei-cloud-autoExpandContent", () => {
  2184. CSDNHuaWeiCloud.autoExpandContent();
  2185. });
  2186. }
  2187. };
  2188. const ShieldCSS$1 = "#operate,.feed-Sign-span,\r\n.view_comment_box,\r\n.weixin-shadowbox.wap-shadowbox,\r\n.feed-Sign-span,\r\n.user-desc.user-desc-fix,\r\n.comment_read_more_box,\r\n#content_views pre.set-code-hide .hide-preCode-box,\r\n/* 登录弹窗 */\r\n.passport-login-container,\r\n.hljs-button[data-title='登录后复制'],\r\n.article-show-more,\r\n#treeSkill,\r\ndiv.btn_open_app_prompt_div,\r\ndiv.readall_box,\r\ndiv.aside-header-fixed,\r\ndiv.feed-Sign-weixin,\r\ndiv.ios-shadowbox {\r\n display: none !important;\r\n}\r\n";
  2189. const MBlogCSS = "#mainBox {\r\n width: auto;\r\n}\r\n.user-desc.user-desc-fix {\r\n height: auto !important;\r\n overflow: auto !important;\r\n}\r\n.component-box .praise {\r\n background: #ff5722;\r\n border-radius: 5px;\r\n padding: 0px 8px;\r\n height: auto;\r\n}\r\n.component-box .praise,\r\n.component-box .share {\r\n color: #fff;\r\n}\r\n.component-box a {\r\n display: inline-block;\r\n font-size: xx-small;\r\n}\r\n.component-box {\r\n display: inline;\r\n margin: 0;\r\n position: relative;\r\n white-space: nowrap;\r\n}\r\n.csdn-edu-title {\r\n background: #4d6de1;\r\n border-radius: 5px;\r\n padding: 0px 8px;\r\n height: auto;\r\n color: #fff !important;\r\n}\r\n\r\n.GM-csdn-dl {\r\n padding: 0.24rem 0.32rem;\r\n width: 100%;\r\n justify-content: space-between;\r\n -webkit-box-pack: justify;\r\n border-bottom: 1px solid #f5f6f7 !important;\r\n}\r\n.GM-csdn-title {\r\n font-size: 0.3rem;\r\n color: #222226;\r\n letter-spacing: 0;\r\n line-height: 0.44rem;\r\n font-weight: 600;\r\n /*max-height: .88rem;*/\r\n word-break: break-all;\r\n overflow: hidden;\r\n display: -webkit-box;\r\n -webkit-box-orient: vertical;\r\n -webkit-line-clamp: 2;\r\n}\r\n.GM-csdn-title a {\r\n word-break: break-all;\r\n color: #222226;\r\n font-weight: 600;\r\n}\r\n.GM-csdn-title em,\r\n.GM-csdn-content em {\r\n font-style: normal;\r\n color: #fc5531;\r\n}\r\n.GM-csdn-content {\r\n /*max-width: 5.58rem;*/\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n display: -webkit-box;\r\n -webkit-line-clamp: 1;\r\n -webkit-box-orient: vertical;\r\n color: #555666;\r\n font-size: 0.24rem;\r\n line-height: 0.34rem;\r\n max-height: 0.34rem;\r\n word-break: break-all;\r\n -webkit-box-flex: 1;\r\n -ms-flex: 1;\r\n flex: 1;\r\n margin-top: 0.16rem;\r\n}\r\n.GM-csdn-img img {\r\n width: 2.18rem;\r\n height: 1.58rem;\r\n /*margin-left: .16rem*/\r\n}\r\n";
  2190. const M_CSDNBlog = {
  2191. init() {
  2192. this.addCSS();
  2193. PopsPanel.execMenu("m-csdn-blog-shieldTopToolbar", () => {
  2194. this.shieldTopToolbar();
  2195. });
  2196. PopsPanel.execMenu("m-csdn-blog-notLimitCodePreMaxHeight", () => {
  2197. this.notLimitCodePreMaxHeight();
  2198. });
  2199. PopsPanel.execMenu("m-csdn-blog-notLimitCommentMaxHeight", () => {
  2200. this.notLimitCommentMaxHeight();
  2201. });
  2202. PopsPanel.execMenu("m-csdn-blog-allowSelectText", () => {
  2203. this.allowSelectText();
  2204. });
  2205. PopsPanel.execMenu("m-csdn-blog-autoExpandContent", () => {
  2206. this.autoExpandContent();
  2207. });
  2208. PopsPanel.execMenu("m-csdn-blog-blockBottomArticle", () => {
  2209. this.blockBottomArticle();
  2210. });
  2211. PopsPanel.execMenu("m-csdn-blog-blockComment", () => {
  2212. this.blockComment();
  2213. });
  2214. domutils.ready(() => {
  2215. PopsPanel.execMenu("m-csdn-blog-removeAds", () => {
  2216. this.removeAds();
  2217. });
  2218. PopsPanel.execMenu("m-csdn-blog-refactoringRecommendation", () => {
  2219. this.refactoringRecommendation();
  2220. });
  2221. PopsPanel.execMenu("m-csdn-blog-unBlockCopy", () => {
  2222. CSDNBlog.unBlockCopy();
  2223. });
  2224. });
  2225. },
  2226. addCSS() {
  2227. addStyle(ShieldCSS$1);
  2228. addStyle(MBlogCSS);
  2229. },
  2230. /**
  2231. * 屏蔽顶部Toolbar
  2232. */
  2233. shieldTopToolbar() {
  2234. log.info("屏蔽顶部Toolbar");
  2235. CSDNUtils.addBlockCSS("#csdn-toolbar");
  2236. addStyle(`
  2237. /* 内容顶部要归位 */
  2238. body #main,
  2239. .margin_sides{
  2240. margin-top: unset !important;
  2241. padding-top: unset !important;
  2242. }
  2243. #article .article_title{
  2244. margin-top: .32rem !important;
  2245. padding-top: unset !important;
  2246. }
  2247. `);
  2248. },
  2249. /**
  2250. * 重构底部推荐
  2251. */
  2252. refactoringRecommendation() {
  2253. function refactoring() {
  2254. log.info("重构底部推荐");
  2255. document.querySelectorAll(
  2256. ".container-fluid"
  2257. ).forEach((item) => {
  2258. var _a2, _b;
  2259. let url = "";
  2260. let title = "";
  2261. let content = "";
  2262. let img = "";
  2263. let isCSDNDownload = false;
  2264. let isCSDNEduDownload = false;
  2265. if (item.hasAttribute("data-url")) {
  2266. url = item.getAttribute("data-url");
  2267. title = (_a2 = item.querySelector(".recommend_title div.left")) == null ? void 0 : _a2.innerHTML;
  2268. if (!item.querySelector(".text")) {
  2269. return;
  2270. }
  2271. content = (_b = item.querySelector(".text")) == null ? void 0 : _b.innerHTML;
  2272. if (item.querySelectorAll(".recommend-img").length) {
  2273. item.querySelectorAll(".recommend-img").forEach((item2) => {
  2274. img += item2.innerHTML;
  2275. });
  2276. }
  2277. } else {
  2278. log.info("节点上无data-url");
  2279. url = item.querySelector("a[data-type]").getAttribute("href");
  2280. title = item.querySelector(".recommend_title div.left").innerHTML;
  2281. content = item.querySelector(".text").innerHTML;
  2282. }
  2283. var _URL_ = new URL(url);
  2284. if (_URL_.host === "download.csdn.net" || _URL_.host === "www.iteye.com" && _URL_.pathname.match(/^\/resource/gi)) {
  2285. log.info("该链接为csdn资源下载");
  2286. isCSDNDownload = true;
  2287. title = `<div class="component-box"><a class="praise" href="javascript:;">CSDN下载</a></div>` + title;
  2288. } else if (_URL_.origin.match(/edu.csdn.net/gi)) {
  2289. isCSDNEduDownload = true;
  2290. log.info("该链接为csdn学院下载");
  2291. title = `<div class="component-box"><a class="csdn-edu-title" href="javascript:;">CSDN学院</a></div>` + title;
  2292. }
  2293. item.setAttribute("class", "GM-csdn-dl");
  2294. item.setAttribute("data-url", url);
  2295. item.innerHTML = `<div class="GM-csdn-title"><div class="left">${title}</div></div><div class="GM-csdn-content">${content}</div><div class="GM-csdn-img">${img}</div>`;
  2296. item.addEventListener("click", function() {
  2297. if (PopsPanel.getValue("m-csdn-blog-openNewTab")) {
  2298. window.open(url, "_blank");
  2299. } else {
  2300. window.location.href = url;
  2301. }
  2302. });
  2303. if ((isCSDNDownload || isCSDNEduDownload) && PopsPanel.getValue("m-csdn-blog-removeResourceArticle")) {
  2304. item.remove();
  2305. }
  2306. });
  2307. }
  2308. let lockFunction = new utils.LockFunction(refactoring, 50);
  2309. utils.waitNode("#recommend").then(($recommend) => {
  2310. log.info("重构底部推荐");
  2311. lockFunction.run();
  2312. utils.mutationObserver($recommend, {
  2313. callback: () => {
  2314. lockFunction.run();
  2315. },
  2316. config: { childList: true, subtree: true, attributes: true }
  2317. });
  2318. });
  2319. },
  2320. /**
  2321. * 屏蔽底部文章
  2322. */
  2323. blockBottomArticle() {
  2324. log.info("屏蔽底部文章");
  2325. CSDNUtils.addBlockCSS("#recommend");
  2326. },
  2327. /**
  2328. * 屏蔽评论
  2329. */
  2330. blockComment() {
  2331. log.info("屏蔽评论");
  2332. CSDNUtils.addBlockCSS("#comment");
  2333. },
  2334. /**
  2335. * 去除广告
  2336. */
  2337. removeAds() {
  2338. log.info("去除广告");
  2339. CSDNUtils.waitForElementToRemove(".passport-login-container");
  2340. CSDNUtils.waitForElementToRemove(
  2341. ".btn_open_app_prompt_box.detail-open-removed"
  2342. );
  2343. CSDNUtils.waitForElementToRemove(".add-firstAd");
  2344. CSDNUtils.waitForElementToRemove("div.feed-Sign-weixin");
  2345. CSDNUtils.waitForElementToRemove("div.ios-shadowbox");
  2346. },
  2347. /**
  2348. * 不限制代码块最大高度
  2349. */
  2350. notLimitCodePreMaxHeight() {
  2351. log.info("不限制代码块最大高度");
  2352. addStyle(`
  2353. pre{
  2354. max-height: unset !important;
  2355. }
  2356. `);
  2357. },
  2358. /**
  2359. * 不限制评论区最大高度
  2360. */
  2361. notLimitCommentMaxHeight() {
  2362. log.info("不限制评论区最大高度");
  2363. addStyle(`
  2364. #comment{
  2365. max-height: none !important;
  2366. }
  2367. `);
  2368. },
  2369. /**
  2370. * 允许选择文字
  2371. */
  2372. allowSelectText() {
  2373. log.info("允许选择文字");
  2374. addStyle(`
  2375. #content_views,
  2376. #content_views pre,
  2377. #content_views pre code{
  2378. webkit-touch-callout: text !important;
  2379. -webkit-user-select: text !important;
  2380. -khtml-user-select: text !important;
  2381. -moz-user-select: text !important;
  2382. -ms-user-select: text !important;
  2383. user-select: text !important;
  2384. }
  2385. `);
  2386. },
  2387. /**
  2388. * 自动展开内容
  2389. */
  2390. autoExpandContent() {
  2391. log.info("自动展开内容");
  2392. addStyle(`
  2393. #content_views pre.set-code-hide,
  2394. .article_content{
  2395. height: 100% !important;
  2396. overflow: auto !important;
  2397. }
  2398. `);
  2399. }
  2400. };
  2401. const ShieldCSS = "/* 右下角的买一年送3个月的广告图标 */\r\n.blind_box {\r\n display: none !important;\r\n}\r\n";
  2402. const M_CSDNWenKu = {
  2403. init() {
  2404. addStyle(ShieldCSS);
  2405. PopsPanel.execMenu("m-csdn-wenku-shieldBottomToolbar", () => {
  2406. this.shieldBottomToolbar();
  2407. });
  2408. },
  2409. /**
  2410. * 【屏蔽】底部工具栏
  2411. */
  2412. shieldBottomToolbar() {
  2413. log.info("【屏蔽】底部工具栏");
  2414. CSDNUtils.addBlockCSS(`.page-container > div.btn`);
  2415. }
  2416. };
  2417. const CSDNBlockCSS = "/* 右下角悬浮图标 买1年送3个月 */\r\n.page-container .blind_box,\r\n/* 底部工具栏右边的 开会员按钮(低至xx元/次) */\r\n.page-container .btn .ml-12,\r\n/* 登录弹窗 */\r\n.passport-login-container,\r\n/* 通用广告className匹配 */\r\n.ads {\r\n display: none !important;\r\n}\r\n";
  2418. const M_CSDNDownload = {
  2419. init() {
  2420. PopsPanel.execMenu("m-csdn-download-removeAds", () => {
  2421. addStyle(CSDNBlockCSS);
  2422. });
  2423. PopsPanel.execMenuOnce(
  2424. "m-csdn-download-automaticallyExpandResourceIntroduction",
  2425. () => {
  2426. this.automaticallyExpandResourceIntroduction();
  2427. }
  2428. );
  2429. },
  2430. /**
  2431. * 自动展开资源介绍
  2432. */
  2433. automaticallyExpandResourceIntroduction() {
  2434. log.info("自动展开资源介绍");
  2435. CSDNUtils.addBlockCSS("label.unfold-font");
  2436. addStyle(`
  2437. .resource-desc{
  2438. max-height: unset !important;
  2439. overflow: unset !important;
  2440. }
  2441. `);
  2442. }
  2443. };
  2444. const M_CSDN = {
  2445. init() {
  2446. if (CSDNRouter.isLink()) {
  2447. log.info("Router: 中转链接");
  2448. M_CSDNLink.init();
  2449. } else if (CSDNRouter.isHuaWeiCloudBlog()) {
  2450. log.info("Router: 华为云联盟");
  2451. M_CSDNHuaWeiCloud.init();
  2452. } else if (CSDNRouter.isBlog()) {
  2453. log.info("Router: 博客");
  2454. M_CSDNBlog.init();
  2455. } else if (CSDNRouter.isWenKu()) {
  2456. log.info("Router: 文库");
  2457. M_CSDNWenKu.init();
  2458. } else if (CSDNRouter.isDownload()) {
  2459. log.info("Router: 资源下载");
  2460. M_CSDNDownload.init();
  2461. } else {
  2462. log.error("暂未适配,请反馈开发者:" + globalThis.location.href);
  2463. }
  2464. }
  2465. };
  2466. PopsPanel.init();
  2467. let isMobile = utils.isPhone();
  2468. let CHANGE_ENV_SET_KEY = "change_env_set";
  2469. let chooseMode = _GM_getValue(CHANGE_ENV_SET_KEY);
  2470. GM_Menu.add({
  2471. key: CHANGE_ENV_SET_KEY,
  2472. text: `⚙ 自动: ${isMobile ? "移动端" : "PC端"}`,
  2473. autoReload: false,
  2474. isStoreValue: false,
  2475. showText(text) {
  2476. if (chooseMode == null) {
  2477. return text;
  2478. }
  2479. return text + ` 手动: ${chooseMode == 1 ? "移动端" : chooseMode == 2 ? "PC端" : "未知"}`;
  2480. },
  2481. callback: () => {
  2482. let allowValue = [0, 1, 2];
  2483. let chooseText = window.prompt(
  2484. "请输入当前脚本环境判定\n\n自动判断: 0\n移动端: 1\nPC端: 2",
  2485. "0"
  2486. );
  2487. if (!chooseText) {
  2488. return;
  2489. }
  2490. let chooseMode2 = parseInt(chooseText);
  2491. if (isNaN(chooseMode2)) {
  2492. Qmsg.error("输入的不是规范的数字");
  2493. return;
  2494. }
  2495. if (!allowValue.includes(chooseMode2)) {
  2496. Qmsg.error("输入的值必须是0或1或2");
  2497. return;
  2498. }
  2499. if (chooseMode2 == 0) {
  2500. _GM_deleteValue(CHANGE_ENV_SET_KEY);
  2501. } else {
  2502. _GM_setValue(CHANGE_ENV_SET_KEY, chooseMode2);
  2503. }
  2504. }
  2505. });
  2506. if (chooseMode != null) {
  2507. log.info(`手动判定为${chooseMode === 1 ? "移动端" : "PC端"}`);
  2508. if (chooseMode == 1) {
  2509. M_CSDN.init();
  2510. } else if (chooseMode == 2) {
  2511. CSDN.init();
  2512. } else {
  2513. Qmsg.error("意外,手动判定的值不在范围内");
  2514. _GM_deleteValue(CHANGE_ENV_SET_KEY);
  2515. }
  2516. } else {
  2517. if (isMobile) {
  2518. log.info("自动判定为移动端");
  2519. M_CSDN.init();
  2520. } else {
  2521. log.info("自动判定为PC端");
  2522. CSDN.init();
  2523. }
  2524. }
  2525.  
  2526. })(Qmsg, DOMUtils, Utils);