CSDN优化

支持PC和手机端、屏蔽广告、优化浏览体验、重定向拦截的Url、自动展开全文、自动展开代码块、全文居中、允许复制内容、去除复制内容的小尾巴、自定义屏蔽元素等

  1. // ==UserScript==
  2. // @name CSDN优化
  3. // @namespace https://github.com/WhiteSevs/TamperMonkeyScript
  4. // @version 2025.6.13
  5. // @author WhiteSevs
  6. // @description 支持PC和手机端、屏蔽广告、优化浏览体验、重定向拦截的Url、自动展开全文、自动展开代码块、全文居中、允许复制内容、去除复制内容的小尾巴、自定义屏蔽元素等
  7. // @license GPL-3.0-only
  8. // @icon data:image/png;base64,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
  9. // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues
  10. // @match *://*.csdn.net/*
  11. // @require https://fastly.jsdelivr.net/gh/WhiteSevs/TamperMonkeyScript@86be74b83fca4fa47521cded28377b35e1d7d2ac/lib/CoverUMD/index.js
  12. // @require https://fastly.jsdelivr.net/npm/@whitesev/utils@2.6.9/dist/index.umd.js
  13. // @require https://fastly.jsdelivr.net/npm/@whitesev/domutils@1.5.10/dist/index.umd.js
  14. // @require https://fastly.jsdelivr.net/npm/@whitesev/pops@2.1.2/dist/index.umd.js
  15. // @require https://fastly.jsdelivr.net/npm/qmsg@1.3.8/dist/index.umd.js
  16. // @connect blog.csdn.net
  17. // @connect mp-action.csdn.net
  18. // @grant GM_deleteValue
  19. // @grant GM_getResourceText
  20. // @grant GM_getValue
  21. // @grant GM_info
  22. // @grant GM_registerMenuCommand
  23. // @grant GM_setValue
  24. // @grant GM_unregisterMenuCommand
  25. // @grant GM_xmlhttpRequest
  26. // @grant unsafeWindow
  27. // @run-at document-start
  28. // ==/UserScript==
  29.  
  30. (function (Qmsg, DOMUtils, Utils, pops) {
  31. 'use strict';
  32.  
  33. var __defProp = Object.defineProperty;
  34. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  35. var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  36. var _a;
  37. var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
  38. var _GM_getResourceText = /* @__PURE__ */ (() => typeof GM_getResourceText != "undefined" ? GM_getResourceText : void 0)();
  39. var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  40. var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
  41. var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  42. var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  43. var _GM_unregisterMenuCommand = /* @__PURE__ */ (() => typeof GM_unregisterMenuCommand != "undefined" ? GM_unregisterMenuCommand : void 0)();
  44. var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
  45. var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  46. var _monkeyWindow = /* @__PURE__ */ (() => window)();
  47. const CommonUtil = {
  48. /**
  49. * 移除元素(未出现也可以等待出现)
  50. * @param selector 元素选择器
  51. */
  52. waitRemove(...args) {
  53. args.forEach((selector) => {
  54. if (typeof selector !== "string") {
  55. return;
  56. }
  57. utils.waitNodeList(selector).then((nodeList) => {
  58. nodeList.forEach(($el) => $el.remove());
  59. });
  60. });
  61. },
  62. /**
  63. * 添加屏蔽CSS
  64. * @param args
  65. * @example
  66. * addBlockCSS("")
  67. * addBlockCSS("","")
  68. * addBlockCSS(["",""])
  69. */
  70. addBlockCSS(...args) {
  71. let selectorList = [];
  72. if (args.length === 0) {
  73. return;
  74. }
  75. if (args.length === 1 && typeof args[0] === "string" && args[0].trim() === "") {
  76. return;
  77. }
  78. args.forEach((selector) => {
  79. if (Array.isArray(selector)) {
  80. selectorList = selectorList.concat(selector);
  81. } else {
  82. selectorList.push(selector);
  83. }
  84. });
  85. return addStyle(`${selectorList.join(",\n")}{display: none !important;}`);
  86. },
  87. /**
  88. * 设置GM_getResourceText的style内容
  89. * @param resourceMapData 资源数据
  90. * @example
  91. * setGMResourceCSS({
  92. * keyName: "ViewerCSS",
  93. * url: "https://example.com/example.css",
  94. * })
  95. */
  96. setGMResourceCSS(resourceMapData) {
  97. let cssText = typeof _GM_getResourceText === "function" ? _GM_getResourceText(resourceMapData.keyName) : null;
  98. if (typeof cssText === "string" && cssText) {
  99. addStyle(cssText);
  100. } else {
  101. CommonUtil.loadStyleLink(resourceMapData.url);
  102. }
  103. },
  104. /**
  105. * 添加<link>标签
  106. * @param url
  107. * @example
  108. * loadStyleLink("https://example.com/example.css")
  109. */
  110. async loadStyleLink(url) {
  111. let $link = document.createElement("link");
  112. $link.rel = "stylesheet";
  113. $link.type = "text/css";
  114. $link.href = url;
  115. DOMUtils.ready(() => {
  116. document.head.appendChild($link);
  117. });
  118. },
  119. /**
  120. * 添加<script>标签
  121. * @param url
  122. * @example
  123. * loadStyleLink("https://example.com/example.js")
  124. */
  125. async loadScript(url) {
  126. let $script = document.createElement("script");
  127. $script.src = url;
  128. return new Promise((resolve) => {
  129. $script.onload = () => {
  130. resolve(null);
  131. };
  132. (document.head || document.documentElement).appendChild($script);
  133. });
  134. },
  135. /**
  136. * 将url修复,例如只有search的链接修复为完整的链接
  137. *
  138. * 注意:不包括http转https
  139. * @param url 需要修复的链接
  140. * @example
  141. * 修复前:`/xxx/xxx?ss=ssss`
  142. * 修复后:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  143. * @example
  144. * 修复前:`//xxx/xxx?ss=ssss`
  145. * 修复后:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  146. * @example
  147. * 修复前:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  148. * 修复后:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  149. * @example
  150. * 修复前:`xxx/xxx?ss=ssss`
  151. * 修复后:`https://xxx.xxx.xxx/xxx/xxx?ss=ssss`
  152. */
  153. fixUrl(url) {
  154. url = url.trim();
  155. if (url.match(/^http(s|):\/\//i)) {
  156. return url;
  157. } else {
  158. if (!url.startsWith("/")) {
  159. url += "/";
  160. }
  161. url = window.location.origin + url;
  162. return url;
  163. }
  164. },
  165. /**
  166. * http转https
  167. * @param url 需要修复的链接
  168. * @example
  169. * 修复前:
  170. * 修复后:
  171. * @example
  172. * 修复前:
  173. * 修复后:
  174. */
  175. fixHttps(url) {
  176. if (url.startsWith("https://")) {
  177. return url;
  178. }
  179. if (!url.startsWith("http://")) {
  180. return url;
  181. }
  182. let urlInstance = new URL(url);
  183. urlInstance.protocol = "https:";
  184. return urlInstance.toString();
  185. },
  186. /**
  187. * 禁止页面滚动,默认锁定html和body
  188. * @example
  189. * lockScroll();
  190. * @example
  191. * lockScroll(document.body);
  192. */
  193. lockScroll(...args) {
  194. let $hidden = document.createElement("style");
  195. $hidden.innerHTML = /*css*/
  196. `
  197. .pops-overflow-hidden-important {
  198. overflow: hidden !important;
  199. }
  200. `;
  201. let $elList = [document.documentElement, document.body].concat(
  202. ...args || []
  203. );
  204. $elList.forEach(($el) => {
  205. $el.classList.add("pops-overflow-hidden-important");
  206. });
  207. (document.head || document.documentElement).appendChild($hidden);
  208. return {
  209. /**
  210. * 解除锁定
  211. */
  212. recovery() {
  213. $elList.forEach(($el) => {
  214. $el.classList.remove("pops-overflow-hidden-important");
  215. });
  216. $hidden.remove();
  217. }
  218. };
  219. },
  220. /**
  221. * 获取剪贴板文本
  222. */
  223. async getClipboardText() {
  224. function readClipboardText(resolve) {
  225. navigator.clipboard.readText().then((clipboardText) => {
  226. resolve(clipboardText);
  227. }).catch((error) => {
  228. log.error("读取剪贴板内容失败👉", error);
  229. resolve("");
  230. });
  231. }
  232. function requestPermissionsWithClipboard(resolve) {
  233. navigator.permissions.query({
  234. // @ts-ignore
  235. name: "clipboard-read"
  236. }).then((permissionStatus) => {
  237. readClipboardText(resolve);
  238. }).catch((error) => {
  239. log.error(
  240. "申请剪贴板权限失败,尝试直接读取👉",
  241. error.message ?? error.name ?? error.stack
  242. );
  243. readClipboardText(resolve);
  244. });
  245. }
  246. function checkClipboardApi() {
  247. var _a2, _b;
  248. if (typeof ((_a2 = navigator == null ? void 0 : navigator.clipboard) == null ? void 0 : _a2.readText) !== "function") {
  249. return false;
  250. }
  251. if (typeof ((_b = navigator == null ? void 0 : navigator.permissions) == null ? void 0 : _b.query) !== "function") {
  252. return false;
  253. }
  254. return true;
  255. }
  256. return new Promise((resolve) => {
  257. if (!checkClipboardApi()) {
  258. resolve("");
  259. return;
  260. }
  261. if (document.hasFocus()) {
  262. requestPermissionsWithClipboard(resolve);
  263. } else {
  264. window.addEventListener(
  265. "focus",
  266. () => {
  267. requestPermissionsWithClipboard(resolve);
  268. },
  269. {
  270. once: true
  271. }
  272. );
  273. }
  274. });
  275. },
  276. /**
  277. * html转义
  278. * @param unsafe
  279. */
  280. escapeHtml(unsafe) {
  281. return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;").replace(/©/g, "&copy;").replace(/®/g, "&reg;").replace(/™/g, "&trade;").replace(/→/g, "&rarr;").replace(/←/g, "&larr;").replace(/↑/g, "&uarr;").replace(/↓/g, "&darr;").replace(/—/g, "&mdash;").replace(/–/g, "&ndash;").replace(/…/g, "&hellip;").replace(/ /g, "&nbsp;").replace(/\r\n/g, "<br>").replace(/\r/g, "<br>").replace(/\n/g, "<br>").replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;");
  282. }
  283. };
  284. const PanelSettingConfig = {
  285. /** Toast位置 */
  286. qmsg_config_position: {
  287. key: "qmsg-config-position",
  288. defaultValue: "bottom"
  289. },
  290. /** 最多显示的数量 */
  291. qmsg_config_maxnums: {
  292. key: "qmsg-config-maxnums",
  293. defaultValue: 3
  294. },
  295. /** 逆序弹出 */
  296. qmsg_config_showreverse: {
  297. key: "qmsg-config-showreverse",
  298. defaultValue: false
  299. }
  300. };
  301. const utils = Utils.noConflict();
  302. const domUtils = DOMUtils.noConflict();
  303. const __pops = pops;
  304. const log = new utils.Log(
  305. _GM_info,
  306. _unsafeWindow.console || _monkeyWindow.console
  307. );
  308. let SCRIPT_NAME = ((_a = _GM_info == null ? void 0 : _GM_info.script) == null ? void 0 : _a.name) || void 0;
  309. pops.config.Utils.AnyTouch();
  310. const DEBUG = false;
  311. log.config({
  312. debug: DEBUG,
  313. logMaxCount: 1e3,
  314. autoClearConsole: true,
  315. tag: true
  316. });
  317. Qmsg.config(
  318. Object.defineProperties(
  319. {
  320. html: true,
  321. autoClose: true,
  322. showClose: false
  323. },
  324. {
  325. position: {
  326. get() {
  327. return Panel.getValue(
  328. PanelSettingConfig.qmsg_config_position.key,
  329. PanelSettingConfig.qmsg_config_position.defaultValue
  330. );
  331. }
  332. },
  333. maxNums: {
  334. get() {
  335. return Panel.getValue(
  336. PanelSettingConfig.qmsg_config_maxnums.key,
  337. PanelSettingConfig.qmsg_config_maxnums.defaultValue
  338. );
  339. }
  340. },
  341. showReverse: {
  342. get() {
  343. return Panel.getValue(
  344. PanelSettingConfig.qmsg_config_showreverse.key,
  345. PanelSettingConfig.qmsg_config_showreverse.defaultValue
  346. );
  347. }
  348. },
  349. zIndex: {
  350. get() {
  351. let maxZIndex = Utils.getMaxZIndex();
  352. let popsMaxZIndex = pops.config.InstanceUtils.getPopsMaxZIndex().zIndex;
  353. return Utils.getMaxValue(maxZIndex, popsMaxZIndex) + 100;
  354. }
  355. }
  356. }
  357. )
  358. );
  359. __pops.GlobalConfig.setGlobalConfig({
  360. zIndex: () => {
  361. let maxZIndex = Utils.getMaxZIndex(void 0, void 0, ($ele) => {
  362. var _a2;
  363. if ((_a2 = $ele == null ? void 0 : $ele.classList) == null ? void 0 : _a2.contains("qmsg-shadow-container")) {
  364. return false;
  365. }
  366. if (($ele == null ? void 0 : $ele.closest("qmsg")) && $ele.getRootNode() instanceof ShadowRoot) {
  367. return false;
  368. }
  369. });
  370. let popsMaxZIndex = pops.config.InstanceUtils.getPopsMaxZIndex().zIndex;
  371. return Utils.getMaxValue(maxZIndex, popsMaxZIndex) + 100;
  372. },
  373. mask: {
  374. // 开启遮罩层
  375. enable: true,
  376. // 取消点击遮罩层的事件
  377. clickEvent: {
  378. toClose: false,
  379. toHide: false
  380. }
  381. }
  382. });
  383. const GM_Menu = new utils.GM_Menu({
  384. GM_getValue: _GM_getValue,
  385. GM_setValue: _GM_setValue,
  386. GM_registerMenuCommand: _GM_registerMenuCommand,
  387. GM_unregisterMenuCommand: _GM_unregisterMenuCommand
  388. });
  389. const httpx = new utils.Httpx({
  390. xmlHttpRequest: _GM_xmlhttpRequest,
  391. logDetails: DEBUG
  392. });
  393. httpx.interceptors.request.use((data) => {
  394. return data;
  395. });
  396. httpx.interceptors.response.use(void 0, (data) => {
  397. log.error("拦截器-请求错误", data);
  398. if (data.type === "onabort") {
  399. Qmsg.warning("请求取消", { consoleLogContent: true });
  400. } else if (data.type === "onerror") {
  401. Qmsg.error("请求异常", { consoleLogContent: true });
  402. } else if (data.type === "ontimeout") {
  403. Qmsg.error("请求超时", { consoleLogContent: true });
  404. } else {
  405. Qmsg.error("其它错误", { consoleLogContent: true });
  406. }
  407. return data;
  408. });
  409. ({
  410. Object: {
  411. defineProperty: _unsafeWindow.Object.defineProperty
  412. },
  413. Function: {
  414. apply: _unsafeWindow.Function.prototype.apply,
  415. call: _unsafeWindow.Function.prototype.call
  416. },
  417. Element: {
  418. appendChild: _unsafeWindow.Element.prototype.appendChild
  419. },
  420. setTimeout: _unsafeWindow.setTimeout
  421. });
  422. const addStyle = utils.addStyle.bind(utils);
  423. const $ = document.querySelector.bind(document);
  424. const $$ = document.querySelectorAll.bind(document);
  425. new utils.GM_Cookie();
  426. const KEY = "GM_Panel";
  427. const ATTRIBUTE_INIT = "data-init";
  428. const ATTRIBUTE_KEY = "data-key";
  429. const ATTRIBUTE_DEFAULT_VALUE = "data-default-value";
  430. const ATTRIBUTE_INIT_MORE_VALUE = "data-init-more-value";
  431. const PROPS_STORAGE_API = "data-storage-api";
  432. const PanelUISize = {
  433. /**
  434. * 一般设置界面的尺寸
  435. */
  436. setting: {
  437. get width() {
  438. if (window.innerWidth < 550) {
  439. return "88vw";
  440. } else if (window.innerWidth < 700) {
  441. return "550px";
  442. } else {
  443. return "700px";
  444. }
  445. },
  446. get height() {
  447. if (window.innerHeight < 450) {
  448. return "70vh";
  449. } else if (window.innerHeight < 550) {
  450. return "450px";
  451. } else {
  452. return "550px";
  453. }
  454. }
  455. }
  456. };
  457. class StorageUtils {
  458. /**
  459. * 存储的键名,可以是多层的,如:a.b.c
  460. *
  461. * 那就是
  462. * {
  463. * "a": {
  464. * "b": {
  465. * "c": {
  466. * ...你的数据
  467. * }
  468. * }
  469. * }
  470. * }
  471. * @param key
  472. */
  473. constructor(key) {
  474. /** 存储的键名 */
  475. __publicField(this, "storageKey");
  476. __publicField(this, "listenerData");
  477. if (typeof key === "string") {
  478. let trimKey = key.trim();
  479. if (trimKey == "") {
  480. throw new Error("key参数不能为空字符串");
  481. }
  482. this.storageKey = trimKey;
  483. } else {
  484. throw new Error("key参数类型错误,必须是字符串");
  485. }
  486. this.listenerData = new Utils.Dictionary();
  487. }
  488. /**
  489. * 获取本地值
  490. */
  491. getLocalValue() {
  492. let localValue = _GM_getValue(this.storageKey);
  493. if (localValue == null) {
  494. localValue = {};
  495. this.setLocalValue(localValue);
  496. }
  497. return localValue;
  498. }
  499. /**
  500. * 设置本地值
  501. * @param value
  502. */
  503. setLocalValue(value) {
  504. _GM_setValue(this.storageKey, value);
  505. }
  506. /**
  507. * 设置值
  508. * @param key 键
  509. * @param value 值
  510. */
  511. set(key, value) {
  512. let oldValue = this.get(key);
  513. let localValue = this.getLocalValue();
  514. Reflect.set(localValue, key, value);
  515. this.setLocalValue(localValue);
  516. this.triggerValueChangeListener(key, oldValue, value);
  517. }
  518. /**
  519. * 获取值
  520. * @param key 键
  521. * @param defaultValue 默认值
  522. */
  523. get(key, defaultValue) {
  524. let localValue = this.getLocalValue();
  525. return Reflect.get(localValue, key) ?? defaultValue;
  526. }
  527. /**
  528. * 获取所有值
  529. */
  530. getAll() {
  531. let localValue = this.getLocalValue();
  532. return localValue;
  533. }
  534. /**
  535. * 删除值
  536. * @param key 键
  537. */
  538. delete(key) {
  539. let oldValue = this.get(key);
  540. let localValue = this.getLocalValue();
  541. Reflect.deleteProperty(localValue, key);
  542. this.setLocalValue(localValue);
  543. this.triggerValueChangeListener(key, oldValue, void 0);
  544. }
  545. /**
  546. * 判断是否存在该值
  547. */
  548. has(key) {
  549. let localValue = this.getLocalValue();
  550. return Reflect.has(localValue, key);
  551. }
  552. /**
  553. * 获取所有键
  554. */
  555. keys() {
  556. let localValue = this.getLocalValue();
  557. return Reflect.ownKeys(localValue);
  558. }
  559. /**
  560. * 获取所有值
  561. */
  562. values() {
  563. let localValue = this.getLocalValue();
  564. return Reflect.ownKeys(localValue).map(
  565. (key) => Reflect.get(localValue, key)
  566. );
  567. }
  568. /**
  569. * 清空所有值
  570. */
  571. clear() {
  572. _GM_deleteValue(this.storageKey);
  573. }
  574. /**
  575. * 监听值改变
  576. * + .set
  577. * + .delete
  578. * @param key 监听的键
  579. * @param callback 值改变的回调函数
  580. */
  581. addValueChangeListener(key, callback) {
  582. let listenerId = Math.random();
  583. let listenerData = this.listenerData.get(key) || [];
  584. listenerData.push({
  585. id: listenerId,
  586. key,
  587. callback
  588. });
  589. this.listenerData.set(key, listenerData);
  590. return listenerId;
  591. }
  592. /**
  593. * 移除监听
  594. * @param listenerId 监听的id或键名
  595. */
  596. removeValueChangeListener(listenerId) {
  597. let flag = false;
  598. for (const [key, listenerData] of this.listenerData.entries()) {
  599. for (let index = 0; index < listenerData.length; index++) {
  600. const value = listenerData[index];
  601. if (typeof listenerId === "string" && value.key === listenerId || typeof listenerId === "number" && value.id === listenerId) {
  602. listenerData.splice(index, 1);
  603. index--;
  604. flag = true;
  605. }
  606. }
  607. this.listenerData.set(key, listenerData);
  608. }
  609. return flag;
  610. }
  611. /**
  612. * 主动触发监听器
  613. * @param key 键
  614. * @param oldValue (可选)旧值
  615. * @param newValue (可选)新值
  616. */
  617. triggerValueChangeListener(key, oldValue, newValue) {
  618. if (!this.listenerData.has(key)) {
  619. return;
  620. }
  621. let listenerData = this.listenerData.get(key);
  622. for (let index = 0; index < listenerData.length; index++) {
  623. const data = listenerData[index];
  624. if (typeof data.callback === "function") {
  625. let value = this.get(key);
  626. let __newValue;
  627. let __oldValue;
  628. if (typeof oldValue !== "undefined" && arguments.length >= 2) {
  629. __oldValue = oldValue;
  630. } else {
  631. __oldValue = value;
  632. }
  633. if (typeof newValue !== "undefined" && arguments.length > 2) {
  634. __newValue = newValue;
  635. } else {
  636. __newValue = value;
  637. }
  638. data.callback(key, __oldValue, __newValue);
  639. }
  640. }
  641. }
  642. }
  643. const PopsPanelStorageApi = new StorageUtils(KEY);
  644. const PanelContent = {
  645. $data: {
  646. /**
  647. * @private
  648. */
  649. __contentConfig: null,
  650. get contentConfig() {
  651. if (this.__contentConfig == null) {
  652. this.__contentConfig = new utils.Dictionary();
  653. }
  654. return this.__contentConfig;
  655. }
  656. },
  657. /**
  658. * 设置所有配置项,用于初始化默认的值
  659. *
  660. * 如果是第一组添加的话,那么它默认就是设置菜单打开的配置
  661. * @param configList 配置项
  662. */
  663. addContentConfig(configList) {
  664. if (!Array.isArray(configList)) {
  665. configList = [configList];
  666. }
  667. let index = this.$data.contentConfig.keys().length;
  668. this.$data.contentConfig.set(index, configList);
  669. },
  670. /**
  671. * 获取所有的配置内容,用于初始化默认的值
  672. */
  673. getAllContentConfig() {
  674. return this.$data.contentConfig.values().flat();
  675. },
  676. /**
  677. * 获取配置内容
  678. * @param index 配置索引
  679. */
  680. getConfig(index = 0) {
  681. return this.$data.contentConfig.get(index) ?? [];
  682. }
  683. };
  684. const PanelMenu = {
  685. $data: {
  686. __menuOption: [
  687. {
  688. key: "show_pops_panel_setting",
  689. text: "⚙ 设置",
  690. autoReload: false,
  691. isStoreValue: false,
  692. showText(text) {
  693. return text;
  694. },
  695. callback: () => {
  696. Panel.showPanel(PanelContent.getConfig(0));
  697. }
  698. }
  699. ],
  700. get menuOption() {
  701. return this.__menuOption;
  702. }
  703. },
  704. init() {
  705. this.initExtensionsMenu();
  706. },
  707. /**
  708. * 初始化菜单项
  709. */
  710. initExtensionsMenu() {
  711. if (!Panel.isTopWindow()) {
  712. return;
  713. }
  714. GM_Menu.add(this.$data.menuOption);
  715. },
  716. /**
  717. * 添加菜单项
  718. * @param option 菜单配置
  719. */
  720. addMenuOption(option) {
  721. if (!Array.isArray(option)) {
  722. option = [option];
  723. }
  724. this.$data.menuOption.push(...option);
  725. },
  726. /**
  727. * 更新菜单项
  728. * @param option 菜单配置
  729. */
  730. updateMenuOption(option) {
  731. if (!Array.isArray(option)) {
  732. option = [option];
  733. }
  734. option.forEach((optionItem) => {
  735. let findIndex = this.$data.menuOption.findIndex((it) => {
  736. return it.key === optionItem.key;
  737. });
  738. if (findIndex !== -1) {
  739. this.$data.menuOption[findIndex] = optionItem;
  740. }
  741. });
  742. },
  743. /**
  744. * 获取菜单项
  745. * @param [index=0] 索引
  746. */
  747. getMenuOption(index = 0) {
  748. return this.$data.menuOption[index];
  749. },
  750. /**
  751. * 删除菜单项
  752. * @param [index=0] 索引
  753. */
  754. deleteMenuOption(index = 0) {
  755. this.$data.menuOption.splice(index, 1);
  756. }
  757. };
  758. const Panel = {
  759. /** 数据 */
  760. $data: {
  761. /**
  762. * @private
  763. */
  764. __configDefaultValueData: null,
  765. /**
  766. * @private
  767. */
  768. __onceExecMenuData: null,
  769. /**
  770. * @private
  771. */
  772. __onceExecData: null,
  773. /**
  774. * @private
  775. */
  776. __panelConfig: {},
  777. $panel: null,
  778. /**
  779. * 菜单项的默认值
  780. */
  781. get configDefaultValueData() {
  782. if (this.__configDefaultValueData == null) {
  783. this.__configDefaultValueData = new utils.Dictionary();
  784. }
  785. return this.__configDefaultValueData;
  786. },
  787. /**
  788. * 成功只执行了一次的项
  789. */
  790. get onceExecMenuData() {
  791. if (this.__onceExecMenuData == null) {
  792. this.__onceExecMenuData = new utils.Dictionary();
  793. }
  794. return this.__onceExecMenuData;
  795. },
  796. /**
  797. * 成功只执行了一次的项
  798. */
  799. get onceExecData() {
  800. if (this.__onceExecData == null) {
  801. this.__onceExecData = new utils.Dictionary();
  802. }
  803. return this.__onceExecData;
  804. },
  805. /** 脚本名,一般用在设置的标题上 */
  806. get scriptName() {
  807. return SCRIPT_NAME;
  808. },
  809. /**
  810. * pops.panel的默认配置
  811. */
  812. get panelConfig() {
  813. return this.__panelConfig;
  814. },
  815. set panelConfig(value) {
  816. this.__panelConfig = value;
  817. },
  818. /** 菜单项的总值在本地数据配置的键名 */
  819. key: KEY,
  820. /** 菜单项在attributes上配置的菜单键 */
  821. attributeKeyName: ATTRIBUTE_KEY,
  822. /** 菜单项在attributes上配置的菜单默认值 */
  823. attributeDefaultValueName: ATTRIBUTE_DEFAULT_VALUE
  824. },
  825. init() {
  826. this.initContentDefaultValue();
  827. PanelMenu.init();
  828. },
  829. /** 判断是否是顶层窗口 */
  830. isTopWindow() {
  831. return _unsafeWindow.top === _unsafeWindow.self;
  832. },
  833. /** 初始化菜单项的默认值保存到本地数据中 */
  834. initContentDefaultValue() {
  835. const initDefaultValue = (config) => {
  836. if (!config.attributes) {
  837. return;
  838. }
  839. if (config.type === "button" || config.type === "forms" || config.type === "deepMenu") {
  840. return;
  841. }
  842. let needInitConfig = {};
  843. let key = config.attributes[ATTRIBUTE_KEY];
  844. if (key != null) {
  845. needInitConfig[key] = config.attributes[ATTRIBUTE_DEFAULT_VALUE];
  846. }
  847. let __attr_init__ = config.attributes[ATTRIBUTE_INIT];
  848. if (typeof __attr_init__ === "function") {
  849. let __attr_result__ = __attr_init__();
  850. if (typeof __attr_result__ === "boolean" && !__attr_result__) {
  851. return;
  852. }
  853. }
  854. let initMoreValue = config.attributes[ATTRIBUTE_INIT_MORE_VALUE];
  855. if (initMoreValue && typeof initMoreValue === "object") {
  856. Object.assign(needInitConfig, initMoreValue);
  857. }
  858. let needInitConfigList = Object.keys(needInitConfig);
  859. if (!needInitConfigList.length) {
  860. log.warn(["请先配置键", config]);
  861. return;
  862. }
  863. needInitConfigList.forEach((__key) => {
  864. let __defaultValue = needInitConfig[__key];
  865. this.setDefaultValue(__key, __defaultValue);
  866. });
  867. };
  868. const loopInitDefaultValue = (configList) => {
  869. for (let index = 0; index < configList.length; index++) {
  870. let configItem = configList[index];
  871. initDefaultValue(configItem);
  872. let childForms = configItem.forms;
  873. if (childForms && Array.isArray(childForms)) {
  874. loopInitDefaultValue(childForms);
  875. }
  876. }
  877. };
  878. const contentConfigList = [...PanelContent.getAllContentConfig()];
  879. for (let index = 0; index < contentConfigList.length; index++) {
  880. let leftContentConfigItem = contentConfigList[index];
  881. if (!leftContentConfigItem.forms) {
  882. continue;
  883. }
  884. const rightContentConfigList = leftContentConfigItem.forms;
  885. if (rightContentConfigList && Array.isArray(rightContentConfigList)) {
  886. loopInitDefaultValue(rightContentConfigList);
  887. }
  888. }
  889. },
  890. /**
  891. * 设置初始化使用的默认值
  892. */
  893. setDefaultValue(key, defaultValue) {
  894. if (this.$data.configDefaultValueData.has(key)) {
  895. log.warn("请检查该key(已存在): " + key);
  896. }
  897. this.$data.configDefaultValueData.set(key, defaultValue);
  898. },
  899. /**
  900. * 设置值
  901. * @param key 键
  902. * @param value 值
  903. */
  904. setValue(key, value) {
  905. PopsPanelStorageApi.set(key, value);
  906. },
  907. /**
  908. * 获取值
  909. * @param key 键
  910. * @param defaultValue 默认值
  911. */
  912. getValue(key, defaultValue) {
  913. let localValue = PopsPanelStorageApi.get(key);
  914. if (localValue == null) {
  915. if (this.$data.configDefaultValueData.has(key)) {
  916. return this.$data.configDefaultValueData.get(key);
  917. }
  918. return defaultValue;
  919. }
  920. return localValue;
  921. },
  922. /**
  923. * 删除值
  924. * @param key 键
  925. */
  926. deleteValue(key) {
  927. PopsPanelStorageApi.delete(key);
  928. },
  929. /**
  930. * 判断该键是否存在
  931. * @param key 键
  932. */
  933. hasKey(key) {
  934. return PopsPanelStorageApi.has(key);
  935. },
  936. /**
  937. * 监听调用setValue、deleteValue
  938. * @param key 需要监听的键
  939. * @param callback
  940. */
  941. addValueChangeListener(key, callback) {
  942. let listenerId = PopsPanelStorageApi.addValueChangeListener(
  943. key,
  944. (__key, __newValue, __oldValue) => {
  945. callback(key, __oldValue, __newValue);
  946. }
  947. );
  948. return listenerId;
  949. },
  950. /**
  951. * 移除监听
  952. * @param listenerId 监听的id
  953. */
  954. removeValueChangeListener(listenerId) {
  955. PopsPanelStorageApi.removeValueChangeListener(listenerId);
  956. },
  957. /**
  958. * 主动触发菜单值改变的回调
  959. * @param key 菜单键
  960. * @param newValue 想要触发的新值,默认使用当前值
  961. * @param oldValue 想要触发的旧值,默认使用当前值
  962. */
  963. triggerMenuValueChange(key, newValue, oldValue) {
  964. PopsPanelStorageApi.triggerValueChangeListener(key, oldValue, newValue);
  965. },
  966. /**
  967. * 移除已执行的仅执行一次的菜单
  968. * @param key 键
  969. */
  970. deleteExecMenuOnce(key) {
  971. this.$data.onceExecMenuData.delete(key);
  972. let flag = PopsPanelStorageApi.removeValueChangeListener(key);
  973. return flag;
  974. },
  975. /**
  976. * 移除已执行的仅执行一次的菜单
  977. * @param key 键
  978. */
  979. deleteOnceExec(key) {
  980. this.$data.onceExecData.delete(key);
  981. },
  982. /**
  983. * 执行菜单
  984. *
  985. * @param queryKey 键|键数组
  986. * @param callback 执行的回调函数
  987. * @param checkExec 判断是否执行回调
  988. *
  989. * (默认)如果想要每个菜单是`与`关系,即每个菜单都判断为开启,那么就判断它们的值&就行
  990. *
  991. * 如果想要任意菜单存在true再执行,那么判断它们的值|就行
  992. *
  993. * + 返回值都为`true`,执行回调,如果回调返回了<style>元素,该元素会在监听到值改变时被移除掉
  994. * + 返回值有一个为`false`,则不执行回调,且移除之前回调函数返回的<style>元素
  995. * @param once 是否只执行一次,默认true
  996. *
  997. * + true (默认)只执行一次,且会监听键的值改变
  998. * + false 不会监听键的值改变
  999. */
  1000. exec(queryKey, callback, checkExec, once = true) {
  1001. const that = this;
  1002. let queryKeyFn;
  1003. if (typeof queryKey === "string" || Array.isArray(queryKey)) {
  1004. queryKeyFn = () => queryKey;
  1005. } else {
  1006. queryKeyFn = queryKey;
  1007. }
  1008. let isArrayKey = false;
  1009. let queryKeyResult = queryKeyFn();
  1010. let keyList = [];
  1011. if (Array.isArray(queryKeyResult)) {
  1012. isArrayKey = true;
  1013. keyList = queryKeyResult;
  1014. } else {
  1015. keyList.push(queryKeyResult);
  1016. }
  1017. let findNotInDataKey = keyList.find(
  1018. (it) => !this.$data.configDefaultValueData.has(it)
  1019. );
  1020. if (findNotInDataKey) {
  1021. log.warn(`${findNotInDataKey} 键不存在`);
  1022. return;
  1023. }
  1024. let storageKey = JSON.stringify(keyList);
  1025. if (once) {
  1026. if (this.$data.onceExecMenuData.has(storageKey)) {
  1027. return;
  1028. }
  1029. this.$data.onceExecMenuData.set(storageKey, 1);
  1030. }
  1031. let storeStyleElements = [];
  1032. let listenerIdList = [];
  1033. let dynamicPushStyleNode = (value, $style) => {
  1034. let dynamicResultList = [];
  1035. if ($style instanceof HTMLStyleElement) {
  1036. dynamicResultList = [$style];
  1037. } else if (Array.isArray($style)) {
  1038. dynamicResultList = [
  1039. ...$style.filter(
  1040. (item) => item != null && item instanceof HTMLStyleElement
  1041. )
  1042. ];
  1043. }
  1044. {
  1045. storeStyleElements = storeStyleElements.concat(dynamicResultList);
  1046. }
  1047. };
  1048. let getMenuValue = (key) => {
  1049. let value = this.getValue(key);
  1050. return value;
  1051. };
  1052. let clearStoreStyleElements = () => {
  1053. for (let index = 0; index < storeStyleElements.length; index++) {
  1054. let $css = storeStyleElements[index];
  1055. $css.remove();
  1056. storeStyleElements.splice(index, 1);
  1057. index--;
  1058. }
  1059. };
  1060. let __checkExec__ = () => {
  1061. let flag = false;
  1062. if (typeof checkExec === "function") {
  1063. flag = checkExec(keyList);
  1064. } else {
  1065. flag = keyList.every((key) => getMenuValue(key));
  1066. }
  1067. return flag;
  1068. };
  1069. let valueChange = (valueOption) => {
  1070. let execFlag = __checkExec__();
  1071. let resultList = [];
  1072. if (execFlag) {
  1073. let valueList = keyList.map((key) => this.getValue(key));
  1074. let $styles = callback({
  1075. addStyleElement: (...args) => {
  1076. return dynamicPushStyleNode(true, ...args);
  1077. },
  1078. value: isArrayKey ? valueList : valueList[0]
  1079. });
  1080. if ($styles instanceof HTMLStyleElement) {
  1081. resultList.push($styles);
  1082. } else if (Array.isArray($styles)) {
  1083. resultList.push(
  1084. ...$styles.filter(
  1085. (item) => item != null && item instanceof HTMLStyleElement
  1086. )
  1087. );
  1088. }
  1089. }
  1090. clearStoreStyleElements();
  1091. storeStyleElements = [...resultList];
  1092. };
  1093. once && keyList.forEach((key) => {
  1094. let listenerId = this.addValueChangeListener(
  1095. key,
  1096. (key2, newValue, oldValue) => {
  1097. valueChange();
  1098. }
  1099. );
  1100. listenerIdList.push(listenerId);
  1101. });
  1102. valueChange();
  1103. let result = {
  1104. /**
  1105. * 清空菜单执行情况
  1106. *
  1107. * + 清空存储的元素列表
  1108. * + 清空值改变的监听器
  1109. * + 清空存储的一次执行的键
  1110. */
  1111. clear() {
  1112. this.clearStoreStyleElements();
  1113. this.removeValueChangeListener();
  1114. once && that.$data.onceExecMenuData.delete(storageKey);
  1115. },
  1116. /**
  1117. * 清空存储的元素列表
  1118. */
  1119. clearStoreStyleElements: () => {
  1120. return clearStoreStyleElements();
  1121. },
  1122. /**
  1123. * 移除值改变的监听器
  1124. */
  1125. removeValueChangeListener: () => {
  1126. listenerIdList.forEach((listenerId) => {
  1127. this.removeValueChangeListener(listenerId);
  1128. });
  1129. }
  1130. };
  1131. return result;
  1132. },
  1133. /**
  1134. * 自动判断菜单是否启用,然后执行回调
  1135. * @param key
  1136. * @param callback 回调
  1137. * @param [isReverse=false] 逆反判断菜单启用
  1138. */
  1139. execMenu(key, callback, isReverse = false) {
  1140. return this.exec(
  1141. key,
  1142. (option) => {
  1143. return callback(option);
  1144. },
  1145. (keyList) => {
  1146. let execFlag = keyList.every((__key__) => {
  1147. let flag = !!this.getValue(__key__);
  1148. isReverse && (flag = !flag);
  1149. return flag;
  1150. });
  1151. return execFlag;
  1152. },
  1153. false
  1154. );
  1155. },
  1156. /**
  1157. * 自动判断菜单是否启用,然后执行回调,只会执行一次
  1158. *
  1159. * 它会自动监听值改变(设置中的修改),改变后如果未执行,则执行一次
  1160. * @param key
  1161. * @param callback 回调
  1162. * @param getValueFn 自定义处理获取当前值,值true是启用并执行回调,值false是不执行回调
  1163. * @param handleValueChangeFn 自定义处理值改变时的回调,值true是启用并执行回调,值false是不执行回调
  1164. */
  1165. execMenuOnce(key, callback) {
  1166. return this.exec(
  1167. key,
  1168. callback,
  1169. (keyList) => {
  1170. let execFlag = keyList.every((__key__) => {
  1171. let flag = !!this.getValue(__key__);
  1172. return flag;
  1173. });
  1174. return execFlag;
  1175. },
  1176. true
  1177. );
  1178. },
  1179. /**
  1180. * 根据key执行一次
  1181. * @param key 键
  1182. * @param callback 回调
  1183. */
  1184. onceExec(key, callback) {
  1185. if (typeof key !== "string") {
  1186. throw new TypeError("key 必须是字符串");
  1187. }
  1188. if (this.$data.onceExecData.has(key)) {
  1189. return;
  1190. }
  1191. callback();
  1192. this.$data.onceExecData.set(key, 1);
  1193. },
  1194. /**
  1195. * 显示设置面板
  1196. * @param content 显示的内容配置
  1197. * @param [title] 标题
  1198. */
  1199. showPanel(content, title = `${SCRIPT_NAME}-设置`) {
  1200. let $panel = __pops.panel({
  1201. ...{
  1202. title: {
  1203. text: `${SCRIPT_NAME}-设置`,
  1204. position: "center",
  1205. html: false,
  1206. style: ""
  1207. },
  1208. content,
  1209. btn: {
  1210. close: {
  1211. enable: true,
  1212. callback: (details, event) => {
  1213. details.close();
  1214. this.$data.$panel = null;
  1215. }
  1216. }
  1217. },
  1218. mask: {
  1219. enable: true,
  1220. clickEvent: {
  1221. toClose: true,
  1222. toHide: false
  1223. },
  1224. clickCallBack: (originalRun, config) => {
  1225. originalRun();
  1226. this.$data.$panel = null;
  1227. }
  1228. },
  1229. width: PanelUISize.setting.width,
  1230. height: PanelUISize.setting.height,
  1231. drag: true,
  1232. only: true
  1233. },
  1234. ...this.$data.panelConfig
  1235. });
  1236. this.$data.$panel = $panel;
  1237. }
  1238. };
  1239. const CSDNRouter = {
  1240. /**
  1241. * 判断是否是华为云联盟
  1242. * + huaweicloud.csdn.net
  1243. */
  1244. isHuaWeiCloudBlog() {
  1245. return Boolean(/huaweicloud.csdn.net/i.test(window.location.origin));
  1246. },
  1247. /**
  1248. * 判断是否是博客
  1249. * + blog.csdn.net
  1250. */
  1251. isBlog() {
  1252. return Boolean(/blog.csdn.net/i.test(window.location.origin));
  1253. },
  1254. /**
  1255. * 博客帖子
  1256. */
  1257. isBlogArticle() {
  1258. return this.isBlog() && window.location.pathname.includes("/article/details/");
  1259. },
  1260. /**
  1261. * 判断是否是文库
  1262. * + wenku.csdn.net
  1263. */
  1264. isWenKu() {
  1265. return Boolean(/wenku.csdn.net/i.test(window.location.origin));
  1266. },
  1267. /**
  1268. * 判断是否是链接
  1269. * + link.csdn.net
  1270. */
  1271. isLink() {
  1272. return window.location.hostname === "link.csdn.net";
  1273. },
  1274. /**
  1275. * 判断是否是搜索
  1276. * + so.csdn.net
  1277. */
  1278. isSo() {
  1279. return window.location.hostname === "so.csdn.net";
  1280. },
  1281. /**
  1282. * 判断是否是C知道
  1283. * + so.csdn.net/know
  1284. * + /chat
  1285. * + /so/ai
  1286. */
  1287. isSoCKnow() {
  1288. return this.isSo() && (window.location.pathname.startsWith("/chat") || window.location.pathname.startsWith("/so/ai"));
  1289. },
  1290. /**
  1291. * 判断是否是资源页面
  1292. * + download.csdn.net
  1293. */
  1294. isDownload() {
  1295. return window.location.hostname === "download.csdn.net";
  1296. }
  1297. };
  1298. 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";
  1299. const CSDNHuaWeiCloud = {
  1300. init() {
  1301. addStyle(ShieldCSS$4);
  1302. Panel.execMenuOnce(
  1303. "csdn-hua-wei-cloud-shieldCloudDeveloperTaskChallengeEvent",
  1304. () => {
  1305. return this.shieldCloudDeveloperTaskChallengeEvent();
  1306. }
  1307. );
  1308. Panel.execMenuOnce("csdn-hua-wei-cloud-autoExpandContent", () => {
  1309. return this.autoExpandContent();
  1310. });
  1311. Panel.execMenuOnce(
  1312. "csdn-hua-wei-cloud-shieldLeftFloatingButton",
  1313. () => {
  1314. return this.shieldLeftFloatingButton();
  1315. }
  1316. );
  1317. Panel.execMenuOnce("csdn-hua-wei-cloud-blockRightColumn", () => {
  1318. return this.blockRightColumn();
  1319. });
  1320. Panel.execMenuOnce(
  1321. "csdn-hua-wei-cloud-blockRecommendedContentAtTheBottom",
  1322. () => {
  1323. return this.blockRecommendedContentAtTheBottom();
  1324. }
  1325. );
  1326. Panel.execMenuOnce(
  1327. "csdn-hua-wei-cloud-shieldTheBottomForMoreRecommendations",
  1328. () => {
  1329. return this.shieldTheBottomForMoreRecommendations();
  1330. }
  1331. );
  1332. },
  1333. /**
  1334. * 自动展开内容
  1335. */
  1336. autoExpandContent() {
  1337. log.info("自动展开全文");
  1338. return [
  1339. CommonUtil.addBlockCSS("div.article-show-more"),
  1340. addStyle(`
  1341. /* 自动展开全文 */
  1342. .main-content .user-article{
  1343. height: auto !important;
  1344. overflow: auto !important;
  1345. }
  1346. `)
  1347. ];
  1348. },
  1349. /**
  1350. * 屏蔽云开发者任务挑战活动
  1351. */
  1352. shieldCloudDeveloperTaskChallengeEvent() {
  1353. log.info("屏蔽云开发者任务挑战活动");
  1354. return CommonUtil.addBlockCSS(".luck-draw-modal-warp");
  1355. },
  1356. /**
  1357. * 屏蔽左侧悬浮按钮
  1358. */
  1359. shieldLeftFloatingButton() {
  1360. log.info("屏蔽左侧悬浮按钮,包括当前阅读量、点赞按钮、评论按钮、分享按钮");
  1361. return CommonUtil.addBlockCSS("div.toolbar-wrapper.article-interact-bar");
  1362. },
  1363. /**
  1364. * 屏蔽右侧栏
  1365. */
  1366. blockRightColumn() {
  1367. log.info("屏蔽右侧栏,包括相关产品-活动日历-运营活动-热门标签");
  1368. return CommonUtil.addBlockCSS("div.page-home-right.dp-aside-right");
  1369. },
  1370. /**
  1371. * 屏蔽底部推荐内容
  1372. */
  1373. blockRecommendedContentAtTheBottom() {
  1374. log.info("屏蔽底部推荐内容");
  1375. return CommonUtil.addBlockCSS("div.recommend-card-box");
  1376. },
  1377. /**
  1378. * 屏蔽底部更多推荐
  1379. */
  1380. shieldTheBottomForMoreRecommendations() {
  1381. log.info("屏蔽底部更多推荐");
  1382. return CommonUtil.addBlockCSS("div.more-article");
  1383. }
  1384. };
  1385. 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';
  1386. const CSDNBlogArticleRightToolBar = {
  1387. init() {
  1388. Panel.exec(
  1389. "csdn-blog-rightToolbarEnable",
  1390. () => {
  1391. return this.shieldRightToolbar();
  1392. },
  1393. (keyList) => !Panel.getValue(keyList[0]),
  1394. true
  1395. );
  1396. Panel.execMenuOnce("csdn-blog-rightToolbarCreativeCenter", () => {
  1397. return this.shieldCreativeCenter();
  1398. });
  1399. Panel.execMenuOnce("csdn-blog-rightToolbarShowOrSidebar", () => {
  1400. return this.shieldShowOrSidebar();
  1401. });
  1402. Panel.execMenuOnce("csdn-blog-rightToolbarBeginnerGuidance", () => {
  1403. return this.shieldBeginnerGuidance();
  1404. });
  1405. Panel.execMenuOnce("csdn-blog-rightToolbarCustomerService", () => {
  1406. return this.shieldCustomerService();
  1407. });
  1408. Panel.execMenuOnce("csdn-blog-rightToolbarReport", () => {
  1409. return this.shieldReport();
  1410. });
  1411. Panel.execMenuOnce("csdn-blog-rightToolbarBackToTop", () => {
  1412. return this.shieldBackToTop();
  1413. });
  1414. this.initRightToolbarOffset();
  1415. domUtils.ready(() => {
  1416. Panel.execMenuOnce("csdn-blog-addGotoRecommandButton", () => {
  1417. this.addGotoRecommandButton();
  1418. });
  1419. });
  1420. },
  1421. /**
  1422. * 【添加】前往评论按钮,在返回顶部的下面
  1423. */
  1424. addGotoRecommandButton() {
  1425. log.info("【添加】前往评论按钮,在返回顶部的上面");
  1426. let gotoRecommandNode = document.createElement("a");
  1427. gotoRecommandNode.className = "option-box";
  1428. gotoRecommandNode.setAttribute("data-type", "gorecommand");
  1429. gotoRecommandNode.innerHTML = /*html*/
  1430. `
  1431. <img src="https://g.csdnimg.cn/side-toolbar/3.6/images/customer.png" alt="" srcset="">
  1432. <span class="show-txt" style="opacity:100;">前往<br>评论</span>
  1433. `;
  1434. gotoRecommandNode.addEventListener("click", function() {
  1435. let toolbarBoxElement = document.querySelector("#toolBarBox");
  1436. if (!toolbarBoxElement || !toolbarBoxElement.getClientRects().length) {
  1437. let $pcCommentBox = $("#pcCommentBox");
  1438. if ($pcCommentBox && $pcCommentBox.getClientRects().length) {
  1439. toolbarBoxElement = $pcCommentBox;
  1440. } else {
  1441. log.error("评论区处于隐藏状态");
  1442. return;
  1443. }
  1444. }
  1445. log.info("滚动到评论");
  1446. let toolbarBoxOffsetTop = toolbarBoxElement.getBoundingClientRect().top + window.scrollY;
  1447. let csdnToolBarElement = document.querySelector(
  1448. "#csdn-toolbar"
  1449. );
  1450. let csdnToolBarStyles = window.getComputedStyle(csdnToolBarElement);
  1451. let csdnToolBarHeight = csdnToolBarElement.clientHeight - parseFloat(csdnToolBarStyles.paddingTop) - parseFloat(csdnToolBarStyles.paddingBottom);
  1452. window.scrollTo({
  1453. top: toolbarBoxOffsetTop - csdnToolBarHeight - 8,
  1454. left: 0,
  1455. behavior: "smooth"
  1456. });
  1457. });
  1458. utils.waitNode(".csdn-side-toolbar").then(() => {
  1459. let targetElement = document.querySelector(
  1460. ".csdn-side-toolbar a:nth-last-child(2)"
  1461. );
  1462. targetElement.parentElement.insertBefore(
  1463. gotoRecommandNode,
  1464. targetElement.nextSibling
  1465. );
  1466. });
  1467. },
  1468. /**
  1469. * 初始化右侧工具栏的偏移(top、right)
  1470. */
  1471. initRightToolbarOffset() {
  1472. log.info("初始化右侧工具栏的偏移(top、right)");
  1473. addStyle(
  1474. /*css*/
  1475. `
  1476. .csdn-side-toolbar{
  1477. left: unset !important;
  1478. }
  1479. `
  1480. );
  1481. utils.waitNode(".csdn-side-toolbar").then(($sideToolbar) => {
  1482. domUtils.css($sideToolbar, {
  1483. top: parseInt(Panel.getValue("csdn-blog-rightToolbarTopOffset")) + "px",
  1484. right: parseInt(Panel.getValue("csdn-blog-rightToolbarRightOffset")) + "px"
  1485. });
  1486. });
  1487. },
  1488. /**
  1489. * 屏蔽右侧工具栏
  1490. */
  1491. shieldRightToolbar() {
  1492. log.info("屏蔽右侧工具栏");
  1493. return CommonUtil.addBlockCSS(`div.csdn-side-toolbar`);
  1494. },
  1495. /**
  1496. * 【屏蔽】创作中心
  1497. */
  1498. shieldCreativeCenter() {
  1499. log.info("【屏蔽】创作中心");
  1500. return CommonUtil.addBlockCSS(
  1501. ".csdn-side-toolbar .sidetool-writeguide-box"
  1502. );
  1503. },
  1504. /**
  1505. * 【屏蔽】显示/隐藏侧栏
  1506. */
  1507. shieldShowOrSidebar() {
  1508. log.info("【屏蔽】显示/隐藏侧栏");
  1509. return CommonUtil.addBlockCSS(".csdn-side-toolbar a.sidecolumn");
  1510. },
  1511. /**
  1512. * 【屏蔽】新手引导
  1513. */
  1514. shieldBeginnerGuidance() {
  1515. log.info("【屏蔽】新手引导");
  1516. return CommonUtil.addBlockCSS(
  1517. '.csdn-side-toolbar a.option-box[data-type="guide"]'
  1518. );
  1519. },
  1520. /**
  1521. * 【屏蔽】客服
  1522. */
  1523. shieldCustomerService() {
  1524. log.info("【屏蔽】客服");
  1525. return CommonUtil.addBlockCSS(
  1526. '.csdn-side-toolbar a.option-box[data-type="cs"]'
  1527. );
  1528. },
  1529. /**
  1530. * 【屏蔽】举报
  1531. */
  1532. shieldReport() {
  1533. log.info("【屏蔽】举报");
  1534. return CommonUtil.addBlockCSS(
  1535. '.csdn-side-toolbar a.option-box[data-type="report"]'
  1536. );
  1537. },
  1538. /**
  1539. * 【屏蔽】返回顶部
  1540. */
  1541. shieldBackToTop() {
  1542. log.info("【屏蔽】返回顶部");
  1543. return CommonUtil.addBlockCSS(
  1544. '.csdn-side-toolbar a.option-box[data-type="gotop"]'
  1545. );
  1546. }
  1547. };
  1548. const CSDNBlogArticle = {
  1549. init() {
  1550. CSDNBlogArticleRightToolBar.init();
  1551. Panel.execMenuOnce("csdn-blog-articleCenter", () => {
  1552. return this.articleCenter();
  1553. });
  1554. Panel.execMenuOnce("csdn-blog-shieldLoginDialog", () => {
  1555. return this.shieldLoginDialog();
  1556. });
  1557. Panel.execMenuOnce("csdn-blog-autoExpandContent", () => {
  1558. return this.autoExpandContent();
  1559. });
  1560. Panel.execMenuOnce("csdn-blog-autoExpandCodeContent", () => {
  1561. return this.autoExpandCodeContent();
  1562. });
  1563. Panel.exec(
  1564. "csdn-blog-blockComment",
  1565. () => {
  1566. return this.blockComment();
  1567. },
  1568. (keyList) => !Panel.getValue(keyList[0]),
  1569. true
  1570. );
  1571. Panel.exec(
  1572. "csdn-blog-bottomRecommendArticleEnable",
  1573. () => {
  1574. return this.shieldBottomRecommendArticle();
  1575. },
  1576. (keyList) => !Panel.getValue(keyList[0]),
  1577. true
  1578. );
  1579. Panel.execMenuOnce("csdn-blog-shieldBottomSkillTree", () => {
  1580. return this.shieldBottomSkillTree();
  1581. });
  1582. Panel.execMenuOnce("csdn-blog-shieldBottomFloatingToolbar", () => {
  1583. return this.shieldBottomFloatingToolbar();
  1584. });
  1585. Panel.execMenuOnce("csdn-blog-shieldLeftBlogContainerAside", () => {
  1586. return this.shieldLeftBlogContainerAside();
  1587. });
  1588. Panel.execMenuOnce("csdn-blog-shieldRightDirectoryInformation", () => {
  1589. return this.shieldRightDirectoryInformation();
  1590. });
  1591. Panel.execMenuOnce("csdn-blog-shieldArticleSearchTip", () => {
  1592. return this.shieldArticleSearchTip();
  1593. });
  1594. Panel.execMenuOnce("csdn-blog-allowSelectContent", () => {
  1595. return this.allowSelectContent();
  1596. });
  1597. domUtils.ready(() => {
  1598. Panel.execMenuOnce("csdn-blog-identityCSDNDownload", () => {
  1599. this.identityCSDNDownload();
  1600. });
  1601. Panel.execMenuOnce("csdn-blog-clickPreCodeAutomatically", () => {
  1602. this.clickPreCodeAutomatically();
  1603. });
  1604. Panel.execMenuOnce("csdn-blog-restoreComments", () => {
  1605. this.restoreComments();
  1606. });
  1607. });
  1608. },
  1609. /**
  1610. * 点击代码块自动展开
  1611. */
  1612. clickPreCodeAutomatically() {
  1613. log.info("点击代码块自动展开");
  1614. document.addEventListener("click", function(event) {
  1615. var _a2;
  1616. let $click = event.target;
  1617. if ($click.localName !== "pre") {
  1618. return;
  1619. }
  1620. $click.style.setProperty("height", "auto");
  1621. (_a2 = $click.querySelector(".hide-preCode-box")) == null ? void 0 : _a2.remove();
  1622. });
  1623. },
  1624. /**
  1625. * 恢复评论到正确位置
  1626. */
  1627. restoreComments() {
  1628. log.info("恢复评论到正确位置-第一条评论");
  1629. utils.waitNode(".first-recommend-box").then(($firstRecommendBox) => {
  1630. let recommendBoxElement = document.querySelector(
  1631. ".recommend-box.insert-baidu-box.recommend-box-style"
  1632. );
  1633. recommendBoxElement.insertBefore(
  1634. $firstRecommendBox,
  1635. recommendBoxElement.firstChild
  1636. );
  1637. });
  1638. log.info("恢复评论到正确位置-第二条评论");
  1639. utils.waitNode(".second-recommend-box").then(($secondRecommendBox) => {
  1640. let recommendBoxElement = document.querySelector(
  1641. ".recommend-box.insert-baidu-box.recommend-box-style"
  1642. );
  1643. recommendBoxElement.insertBefore(
  1644. $secondRecommendBox,
  1645. recommendBoxElement.firstChild
  1646. );
  1647. });
  1648. },
  1649. /**
  1650. * 标识CSDN下载的链接
  1651. */
  1652. identityCSDNDownload() {
  1653. log.info("标识CSDN下载的链接");
  1654. document.querySelectorAll(
  1655. ".recommend-item-box[data-url*='https://download.csdn.net/']"
  1656. ).forEach((item) => {
  1657. if (Panel.getValue("csdn-blog-removeResourceDownloadArticle")) {
  1658. item.remove();
  1659. } else {
  1660. item.querySelector(".content-box").style.setProperty("border", "2px solid red");
  1661. }
  1662. });
  1663. },
  1664. /**
  1665. * 全文居中
  1666. */
  1667. articleCenter() {
  1668. log.info("全文居中");
  1669. return addStyle(BlogArticleCenterCSS);
  1670. },
  1671. /**
  1672. * 屏蔽登录弹窗
  1673. */
  1674. shieldLoginDialog() {
  1675. log.info("屏蔽登录弹窗");
  1676. return CommonUtil.addBlockCSS(`.passport-login-container`);
  1677. },
  1678. /**
  1679. * 自动展开代码块
  1680. */
  1681. autoExpandCodeContent() {
  1682. log.info("自动展开代码块");
  1683. return [
  1684. CommonUtil.addBlockCSS("pre.set-code-hide .hide-preCode-box"),
  1685. addStyle(
  1686. /*css*/
  1687. `
  1688. pre.set-code-hide{
  1689. height: auto !important;
  1690. }
  1691. /* 自动展开代码块 */
  1692. .comment-list-box,
  1693. main div.blog-content-box pre {
  1694. max-height: none !important;
  1695. }
  1696. `
  1697. )
  1698. ];
  1699. },
  1700. /**
  1701. * 自动展开全文
  1702. */
  1703. autoExpandContent() {
  1704. log.info("自动展开全文");
  1705. return addStyle(
  1706. /*css*/
  1707. `
  1708. /* 自动展开全文 */
  1709. #article_content,
  1710. .user-article.user-article-hide {
  1711. height: auto !important;
  1712. overflow: auto !important;
  1713. }
  1714. `
  1715. );
  1716. },
  1717. /**
  1718. * 屏蔽评论区
  1719. */
  1720. blockComment() {
  1721. log.info("屏蔽评论区");
  1722. return CommonUtil.addBlockCSS(`#pcCommentBox`);
  1723. },
  1724. /**
  1725. * 屏蔽底部推荐文章
  1726. */
  1727. shieldBottomRecommendArticle() {
  1728. log.info("屏蔽底部推荐文章");
  1729. return CommonUtil.addBlockCSS(`main > div.recommend-box`);
  1730. },
  1731. /**
  1732. * 屏蔽底部xx技能树
  1733. */
  1734. shieldBottomSkillTree() {
  1735. log.info("屏蔽底部xx技能树");
  1736. return CommonUtil.addBlockCSS(`#treeSkill`);
  1737. },
  1738. /**
  1739. * 屏蔽底部悬浮工具栏
  1740. */
  1741. shieldBottomFloatingToolbar() {
  1742. log.info("屏蔽底部悬浮工具栏");
  1743. return CommonUtil.addBlockCSS(`#toolBarBox`);
  1744. },
  1745. /**
  1746. * 屏蔽左侧博客信息
  1747. */
  1748. shieldLeftBlogContainerAside() {
  1749. log.info("【屏蔽】左侧博客信息");
  1750. return CommonUtil.addBlockCSS(`aside.blog_container_aside`);
  1751. },
  1752. /**
  1753. * 【屏蔽】右侧目录信息
  1754. */
  1755. shieldRightDirectoryInformation() {
  1756. log.info("【屏蔽】右侧目录信息");
  1757. return CommonUtil.addBlockCSS("#rightAsideConcision", "#rightAside");
  1758. },
  1759. /**
  1760. * 屏蔽文章内的选中搜索悬浮提示
  1761. */
  1762. shieldArticleSearchTip() {
  1763. log.info("屏蔽文章内的选中搜索悬浮提示");
  1764. return CommonUtil.addBlockCSS(`#articleSearchTip`);
  1765. },
  1766. /**
  1767. * 允许选择内容
  1768. */
  1769. allowSelectContent() {
  1770. log.info("允许选择内容");
  1771. return addStyle(
  1772. /*css*/
  1773. `
  1774. #content_views,
  1775. #content_views pre,
  1776. #content_views pre code {
  1777. user-select: text !important;
  1778. }
  1779. `
  1780. );
  1781. }
  1782. };
  1783. 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";
  1784. 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}";
  1785. const CSDNWenKu = {
  1786. init() {
  1787. addStyle(WenkuCSS);
  1788. addStyle(ShieldCSS$3);
  1789. Panel.execMenuOnce("csdn-wenku-shieldResourceRecommend", () => {
  1790. return this.shieldResourceRecommend();
  1791. });
  1792. Panel.execMenuOnce("csdn-wenku-shieldRightUserInfo", () => {
  1793. return this.shieldRightUserInfo();
  1794. });
  1795. Panel.execMenuOnce("csdn-wenku-shieldRightToolBar", () => {
  1796. return this.shieldRightToolBar();
  1797. });
  1798. },
  1799. /**
  1800. * 【屏蔽】资源推荐
  1801. */
  1802. shieldResourceRecommend() {
  1803. log.info("【屏蔽】资源推荐");
  1804. return CommonUtil.addBlockCSS("#recommend");
  1805. },
  1806. /**
  1807. * 【屏蔽】右侧用户信息
  1808. */
  1809. shieldRightUserInfo() {
  1810. log.info("【屏蔽】右侧用户信息");
  1811. return CommonUtil.addBlockCSS(".layout-right");
  1812. },
  1813. /**
  1814. * 【屏蔽】右侧悬浮工具栏
  1815. */
  1816. shieldRightToolBar() {
  1817. log.info("【屏蔽】右侧悬浮工具栏");
  1818. return CommonUtil.addBlockCSS(".csdn-side-toolbar");
  1819. }
  1820. };
  1821. const CSDNLink = {
  1822. init() {
  1823. Panel.execMenuOnce("csdn-link-jumpRedirect", () => {
  1824. this.jumpRedirect();
  1825. });
  1826. },
  1827. /**
  1828. * 去除CSDN拦截其它网址的url并自动跳转
  1829. * @example
  1830. * https://link.csdn.net/?target=https%3A%2F%2Fjaist.dl.sourceforge.net%2Fproject%2Fportecle%2Fv1.11%2Fportecle-1.11.zip
  1831. */
  1832. jumpRedirect() {
  1833. try {
  1834. let urlSearchParams = new URLSearchParams(window.location.search);
  1835. const URL_KEY = "target";
  1836. if (urlSearchParams.has(URL_KEY)) {
  1837. let target = urlSearchParams.get(URL_KEY);
  1838. let jumpUrl = decodeURIComponent(target);
  1839. log.success(`跳转链接:${jumpUrl}`);
  1840. window.location.href = jumpUrl;
  1841. } else {
  1842. log.error("解析跳转的链接失败,原因:搜索参数中没有target参数");
  1843. }
  1844. } catch (error) {
  1845. Qmsg.error("跳转链接失败:" + error.message);
  1846. }
  1847. }
  1848. };
  1849. 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/* 全屏双十一红包 */\r\n.csdn-reapck-select,\r\n/* 侧栏的618会员开通 */\r\n.csdn-side-toolbar .sidecolumn-vip {\r\n display: none !important;\r\n}\r\n";
  1850. 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";
  1851. const CSDNBlog = {
  1852. init() {
  1853. this.addCSS();
  1854. Panel.execMenuOnce("csdn-blog-shieldTopToolbar", () => {
  1855. return this.shieldTopToolbar();
  1856. });
  1857. domUtils.ready(() => {
  1858. Panel.execMenuOnce("csdn-blog-removeClipboardHijacking", () => {
  1859. this.removeClipboardHijacking();
  1860. });
  1861. Panel.execMenuOnce("csdn-blog-unBlockCopy", () => {
  1862. this.unBlockCopy();
  1863. });
  1864. });
  1865. },
  1866. /**
  1867. * 添加屏蔽CSS和功能CSS
  1868. */
  1869. addCSS() {
  1870. log.info("添加屏蔽CSS和功能CSS");
  1871. return [addStyle(BlogShieldCSS), addStyle(BlogCSS)];
  1872. },
  1873. /**
  1874. * 去除剪贴板劫持
  1875. */
  1876. removeClipboardHijacking() {
  1877. log.info("去除剪贴板劫持");
  1878. let $article_copyright = document.querySelector(".article-copyright");
  1879. if ($article_copyright) {
  1880. $article_copyright.remove();
  1881. }
  1882. if (_unsafeWindow.articleType) {
  1883. _unsafeWindow.articleType = 0;
  1884. }
  1885. if (_unsafeWindow.csdn && _unsafeWindow.csdn.copyright && _unsafeWindow.csdn.copyright.textData) {
  1886. _unsafeWindow.csdn.copyright.textData = "";
  1887. }
  1888. if (_unsafeWindow.csdn && _unsafeWindow.csdn.copyright && _unsafeWindow.csdn.copyright.htmlData) {
  1889. _unsafeWindow.csdn.copyright.htmlData = "";
  1890. }
  1891. },
  1892. /**
  1893. * 取消禁止复制
  1894. */
  1895. unBlockCopy() {
  1896. log.info("取消禁止复制");
  1897. domUtils.on(
  1898. document,
  1899. "click",
  1900. function(event) {
  1901. let $click = event.target;
  1902. let $parent = $click.parentElement;
  1903. if (!$click.classList.contains("hljs-button")) {
  1904. return;
  1905. }
  1906. let $code = $parent.querySelector("code");
  1907. $code = $code || $parent;
  1908. utils.preventEvent(event);
  1909. let copyText = $code.innerText;
  1910. log.info(
  1911. "点击复制按钮复制内容:" + (copyText.length > 8 ? copyText.substring(0, 8) + "..." : copyText)
  1912. );
  1913. utils.setClip(copyText);
  1914. $click.setAttribute("data-title", "复制成功");
  1915. },
  1916. {
  1917. capture: true
  1918. }
  1919. );
  1920. let changeDataTitle = new utils.LockFunction(function(event) {
  1921. let $mouse = event.target;
  1922. if ($mouse.localName !== "pre") {
  1923. return;
  1924. }
  1925. let $hljsBtn = $mouse.querySelector(".hljs-button");
  1926. if ($hljsBtn) {
  1927. $hljsBtn.setAttribute("data-title", "复制");
  1928. }
  1929. });
  1930. domUtils.on(
  1931. document,
  1932. ["mouseenter", "mouseleave"],
  1933. function(event) {
  1934. changeDataTitle.run(event);
  1935. },
  1936. {
  1937. capture: true
  1938. }
  1939. );
  1940. utils.waitNode("#content_views").then(($content_views) => {
  1941. var _a2;
  1942. if (_unsafeWindow.$) {
  1943. (_a2 = _unsafeWindow.$("#content_views")) == null ? void 0 : _a2.unbind("copy");
  1944. }
  1945. domUtils.on(
  1946. $content_views,
  1947. "copy",
  1948. function(event) {
  1949. utils.preventEvent(event);
  1950. let selectText = _unsafeWindow.getSelection();
  1951. let copyText = selectText == null ? void 0 : selectText.toString();
  1952. log.info(
  1953. "Ctrl+C复制内容:" + (copyText.length > 8 ? copyText.substring(0, 8) + "..." : copyText)
  1954. );
  1955. utils.setClip(copyText);
  1956. return false;
  1957. },
  1958. {
  1959. capture: true
  1960. }
  1961. );
  1962. });
  1963. utils.waitNode(".hljs-button").then(() => {
  1964. setTimeout(() => {
  1965. $$(".hljs-button").forEach(($el) => {
  1966. $el.removeAttribute("onclick");
  1967. $el.removeAttribute("data-report-click");
  1968. $el.setAttribute("data-title", "复制");
  1969. });
  1970. }, 250);
  1971. });
  1972. },
  1973. /**
  1974. * 屏蔽顶部Toolbar
  1975. */
  1976. shieldTopToolbar() {
  1977. log.info("屏蔽顶部Toolbar");
  1978. return CommonUtil.addBlockCSS("#toolbarBox", "#csdn-toolbar");
  1979. }
  1980. };
  1981. const CSDN = {
  1982. init() {
  1983. if (CSDNRouter.isLink()) {
  1984. log.info("Router: 中转链接");
  1985. CSDNLink.init();
  1986. } else if (CSDNRouter.isHuaWeiCloudBlog()) {
  1987. log.info("Router: 华为云联盟");
  1988. CSDNHuaWeiCloud.init();
  1989. } else if (CSDNRouter.isBlog()) {
  1990. log.info("Router: 博客");
  1991. CSDNBlog.init();
  1992. if (CSDNRouter.isBlogArticle()) {
  1993. log.info("Router: 帖子");
  1994. CSDNBlogArticle.init();
  1995. }
  1996. } else if (CSDNRouter.isWenKu()) {
  1997. log.info("Router: 文库");
  1998. CSDNWenKu.init();
  1999. } else {
  2000. log.error("暂未适配,请反馈开发者:" + globalThis.location.href);
  2001. }
  2002. }
  2003. };
  2004. const M_CSDNLink = {
  2005. init() {
  2006. Panel.execMenuOnce("m-csdn-link-jumpRedirect", () => {
  2007. CSDNLink.jumpRedirect();
  2008. });
  2009. }
  2010. };
  2011. const ShieldCSS$2 = "/* 右下角的 免费赢华为平板xxxx */\r\n.org-main-content .siderbar-box {\r\n display: none !important;\r\n}\r\n";
  2012. const M_CSDNHuaWeiCloud = {
  2013. init() {
  2014. addStyle(ShieldCSS$2);
  2015. Panel.execMenuOnce("m-csdn-hua-wei-cloud-autoExpandContent", () => {
  2016. return CSDNHuaWeiCloud.autoExpandContent();
  2017. });
  2018. Panel.execMenuOnce(
  2019. "m-csdn-hua-wei-cloud-blockBottomJoinTheCommunity",
  2020. () => {
  2021. return this.blockBottomJoinTheCommunity();
  2022. }
  2023. );
  2024. },
  2025. /**
  2026. * 【屏蔽】底部加入社区
  2027. */
  2028. blockBottomJoinTheCommunity() {
  2029. log.info("【屏蔽】底部加入社区");
  2030. return CommonUtil.addBlockCSS(".user-desc");
  2031. }
  2032. };
  2033. const ApiResponseCheck = {
  2034. isSuccessResponse(data) {
  2035. if (data == null) {
  2036. return false;
  2037. }
  2038. if (typeof data === "string") {
  2039. data = utils.toJSON(data);
  2040. }
  2041. return (data == null ? void 0 : data.code) === 200;
  2042. }
  2043. };
  2044. const CSDNFavoriteApi = {
  2045. /**
  2046. * 获取收藏夹信息
  2047. * @param url 当前url
  2048. */
  2049. async folderListWithCheck(url) {
  2050. let response = await httpx.get(
  2051. `https://mp-action.csdn.net/interact/wrapper/pc/favorite/v1/api/folderListWithCheck`,
  2052. {
  2053. data: {
  2054. url
  2055. },
  2056. fetch: true,
  2057. allowInterceptConfig: false,
  2058. headers: {
  2059. "User-Agent": utils.getRandomPCUA()
  2060. }
  2061. }
  2062. );
  2063. log.info(response);
  2064. let data = utils.toJSON(response.data.responseText);
  2065. if (!response.status || !ApiResponseCheck.isSuccessResponse(response.data.responseText)) {
  2066. log.error("获取收藏夹信息失败,请求异常");
  2067. if (typeof data.msg === "string") {
  2068. Qmsg.error(data.msg);
  2069. } else {
  2070. Qmsg.error("获取收藏夹信息失败");
  2071. }
  2072. return;
  2073. }
  2074. return data.data.result;
  2075. },
  2076. /**
  2077. * 添加到某个收藏夹
  2078. */
  2079. async addFavoriteInFolds(requestData) {
  2080. let response = await httpx.post(
  2081. "https://mp-action.csdn.net/interact/wrapper/pc/favorite/v1/api/addFavoriteInFolds",
  2082. {
  2083. fetch: true,
  2084. data: requestData,
  2085. headers: {
  2086. "Content-Type": "application/json",
  2087. "User-Agent": utils.getRandomPCUA()
  2088. },
  2089. allowInterceptConfig: false
  2090. }
  2091. );
  2092. log.info(response);
  2093. if (!response.status || !ApiResponseCheck.isSuccessResponse(response.data.responseText)) {
  2094. log.error("添加收藏失败,请求异常", response);
  2095. Qmsg.error("添加收藏失败,请求异常");
  2096. return;
  2097. }
  2098. return true;
  2099. },
  2100. /**
  2101. * 检查收藏夹信息
  2102. * @param url
  2103. * @returns
  2104. * + true 已收藏
  2105. * + false 未收藏
  2106. */
  2107. async checkFavoriteByUrl(url) {
  2108. debugger;
  2109. let response = await httpx.get(
  2110. `https://mp-action.csdn.net/interact/wrapper/pc/favorite/v1/api/checkFavoriteByUrl`,
  2111. {
  2112. data: {
  2113. url
  2114. },
  2115. fetch: true,
  2116. allowInterceptConfig: false,
  2117. headers: {
  2118. "User-Agent": utils.getRandomPCUA()
  2119. }
  2120. }
  2121. );
  2122. log.info(response);
  2123. if (!response.status || !ApiResponseCheck.isSuccessResponse(response.data.responseText)) {
  2124. log.error("检查收藏夹状态失败,请求异常");
  2125. Qmsg.error("检查收藏夹状态失败,请求异常");
  2126. return;
  2127. }
  2128. let data = utils.toJSON(response.data.responseText);
  2129. return data.data;
  2130. },
  2131. /**
  2132. * 创建收藏夹
  2133. */
  2134. async createFolder(config) {
  2135. let response = await httpx.post(
  2136. `https://mp-action.csdn.net/interact/wrapper/pc/favorite/v1/api/createFolder`,
  2137. {
  2138. data: config,
  2139. fetch: true,
  2140. headers: {
  2141. Accept: "application/json, text/javascript, */*; q=0.01",
  2142. "Content-Type": "application/json",
  2143. "User-Agent": utils.getRandomPCUA()
  2144. },
  2145. allowInterceptConfig: false
  2146. }
  2147. );
  2148. log.info(response);
  2149. if (!response.status || !ApiResponseCheck.isSuccessResponse(response.data.responseText)) {
  2150. Qmsg.error("创建收藏夹失败");
  2151. return;
  2152. }
  2153. let data = utils.toJSON(response.data.responseText);
  2154. return data.data;
  2155. }
  2156. };
  2157. const M_CSDNBlogArticle = {
  2158. init() {
  2159. Panel.exec(
  2160. "m-csdn-blog-shieldTopToolbar",
  2161. () => {
  2162. return this.shieldTopToolbar();
  2163. },
  2164. (keyList) => {
  2165. return !Panel.getValue(keyList[0]);
  2166. },
  2167. true
  2168. );
  2169. Panel.execMenuOnce("m-csdn-blog-notLimitCodePreMaxHeight", () => {
  2170. return this.notLimitCodePreMaxHeight();
  2171. });
  2172. Panel.execMenuOnce("m-csdn-blog-notLimitCommentMaxHeight", () => {
  2173. return this.notLimitCommentMaxHeight();
  2174. });
  2175. Panel.execMenuOnce("m-csdn-blog-allowSelectText", () => {
  2176. return this.allowSelectText();
  2177. });
  2178. Panel.execMenuOnce("m-csdn-blog-autoExpandContent", () => {
  2179. return this.autoExpandContent();
  2180. });
  2181. Panel.exec(
  2182. "m-csdn-blog-bottomArticleEnable",
  2183. () => {
  2184. return this.blockBottomArticle();
  2185. },
  2186. (keyList) => {
  2187. return !Panel.getValue(keyList[0]);
  2188. },
  2189. true
  2190. );
  2191. Panel.exec(
  2192. "m-csdn-blog-comment-enable",
  2193. () => {
  2194. return this.blockComment();
  2195. },
  2196. (keyList) => {
  2197. return !Panel.getValue(keyList[0]);
  2198. },
  2199. true
  2200. );
  2201. Panel.exec(
  2202. "m-csdn-blog-bottom-toolbar-enable",
  2203. () => {
  2204. return this.blockBottomToolBar();
  2205. },
  2206. (keyList) => {
  2207. return !Panel.getValue(keyList[0]);
  2208. },
  2209. true
  2210. );
  2211. Panel.execMenuOnce("m-csdn-blog-bottom-toolbar-always-bottom", () => {
  2212. return this.bottomToolBarAlwaysShow();
  2213. });
  2214. domUtils.ready(() => {
  2215. Panel.execMenuOnce("m-csdn-blog-removeAds", () => {
  2216. return this.removeAds();
  2217. });
  2218. Panel.execMenuOnce("m-csdn-blog-refactoringRecommendation", () => {
  2219. this.refactoringRecommendation();
  2220. });
  2221. Panel.execMenuOnce("m-csdn-blog-unBlockCopy", () => {
  2222. CSDNBlog.unBlockCopy();
  2223. });
  2224. Panel.execMenuOnce(
  2225. "m-csdn-blog-bottom-toolbar-optimizationCollectButton",
  2226. () => {
  2227. this.optimizationCollectButton();
  2228. }
  2229. );
  2230. });
  2231. },
  2232. /**
  2233. * 屏蔽顶部Toolbar
  2234. */
  2235. shieldTopToolbar() {
  2236. log.info("屏蔽顶部Toolbar");
  2237. return [
  2238. CommonUtil.addBlockCSS("#csdn-toolbar"),
  2239. addStyle(
  2240. /*css*/
  2241. `
  2242. /* 内容顶部要归位 */
  2243. body #main,
  2244. .margin_sides{
  2245. margin-top: unset !important;
  2246. padding-top: unset !important;
  2247. }
  2248. #article .article_title{
  2249. margin-top: .32rem !important;
  2250. padding-top: unset !important;
  2251. }
  2252. `
  2253. )
  2254. ];
  2255. },
  2256. /**
  2257. * 重构底部推荐
  2258. */
  2259. refactoringRecommendation() {
  2260. function refactoring() {
  2261. document.querySelectorAll(".container-fluid").forEach((item) => {
  2262. var _a2, _b;
  2263. let url = "";
  2264. let title = "";
  2265. let content = "";
  2266. let img = "";
  2267. let isCSDNDownload = false;
  2268. let isCSDNEduDownload = false;
  2269. if (item.hasAttribute("data-url")) {
  2270. url = item.getAttribute("data-url");
  2271. title = (_a2 = item.querySelector(".recommend_title div.left")) == null ? void 0 : _a2.innerHTML;
  2272. if (!item.querySelector(".text")) {
  2273. return;
  2274. }
  2275. content = (_b = item.querySelector(".text")) == null ? void 0 : _b.innerHTML;
  2276. if (item.querySelectorAll(".recommend-img").length) {
  2277. item.querySelectorAll(".recommend-img").forEach((item2) => {
  2278. img += item2.innerHTML;
  2279. });
  2280. }
  2281. } else {
  2282. url = item.querySelector("a[data-type]").getAttribute("href");
  2283. title = item.querySelector(".recommend_title div.left").innerHTML;
  2284. content = item.querySelector(".text").innerHTML;
  2285. }
  2286. var _URL_ = new URL(url);
  2287. if (_URL_.host === "download.csdn.net" || _URL_.host === "www.iteye.com" && _URL_.pathname.match(/^\/resource/gi)) {
  2288. isCSDNDownload = true;
  2289. title = `<div class="component-box"><a class="praise" href="javascript:;">CSDN下载</a></div>` + title;
  2290. } else if (_URL_.origin.match(/edu.csdn.net/gi)) {
  2291. isCSDNEduDownload = true;
  2292. title = `<div class="component-box"><a class="csdn-edu-title" href="javascript:;">CSDN学院</a></div>` + title;
  2293. }
  2294. item.setAttribute("class", "GM-csdn-dl");
  2295. item.setAttribute("data-url", url);
  2296. 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>`;
  2297. item.addEventListener("click", function() {
  2298. if (Panel.getValue("m-csdn-blog-openNewTab")) {
  2299. window.open(url, "_blank");
  2300. } else {
  2301. window.location.href = url;
  2302. }
  2303. });
  2304. if ((isCSDNDownload || isCSDNEduDownload) && Panel.getValue("m-csdn-blog-removeResourceArticle")) {
  2305. item.remove();
  2306. }
  2307. });
  2308. }
  2309. let lockFunction = new utils.LockFunction(refactoring, 50);
  2310. utils.waitNode("#recommend").then(($recommend) => {
  2311. log.info("重构底部推荐");
  2312. lockFunction.run();
  2313. utils.mutationObserver($recommend, {
  2314. callback: () => {
  2315. lockFunction.run();
  2316. },
  2317. config: { childList: true, subtree: true, attributes: true }
  2318. });
  2319. });
  2320. },
  2321. /**
  2322. * 屏蔽底部文章
  2323. */
  2324. blockBottomArticle() {
  2325. log.info("屏蔽底部文章");
  2326. return CommonUtil.addBlockCSS("#recommend");
  2327. },
  2328. /**
  2329. * 屏蔽评论
  2330. */
  2331. blockComment() {
  2332. log.info("屏蔽评论");
  2333. return CommonUtil.addBlockCSS("#comment");
  2334. },
  2335. /**
  2336. * 去除广告
  2337. */
  2338. removeAds() {
  2339. log.info("去除广告");
  2340. return [
  2341. /* 登录窗口 */
  2342. CommonUtil.waitRemove(".passport-login-container"),
  2343. /* 打开APP */
  2344. CommonUtil.waitRemove(".btn_open_app_prompt_box.detail-open-removed"),
  2345. /* 广告 */
  2346. CommonUtil.waitRemove(".add-firstAd"),
  2347. /* 打开CSDN APP 小程序看全文 */
  2348. CommonUtil.waitRemove("div.feed-Sign-weixin"),
  2349. /* ios版本提示 */
  2350. CommonUtil.waitRemove("div.ios-shadowbox")
  2351. ];
  2352. },
  2353. /**
  2354. * 不限制代码块最大高度
  2355. */
  2356. notLimitCodePreMaxHeight() {
  2357. log.info("不限制代码块最大高度");
  2358. return addStyle(
  2359. /*css*/
  2360. `
  2361. pre{
  2362. max-height: unset !important;
  2363. }
  2364. `
  2365. );
  2366. },
  2367. /**
  2368. * 不限制评论区最大高度
  2369. */
  2370. notLimitCommentMaxHeight() {
  2371. log.info("不限制评论区最大高度");
  2372. return addStyle(
  2373. /*css*/
  2374. `
  2375. #comment{
  2376. max-height: none !important;
  2377. }
  2378. `
  2379. );
  2380. },
  2381. /**
  2382. * 允许选择文字
  2383. */
  2384. allowSelectText() {
  2385. log.info("允许选择文字");
  2386. return addStyle(
  2387. /*css*/
  2388. `
  2389. #content_views,
  2390. #content_views pre,
  2391. #content_views pre code{
  2392. webkit-touch-callout: text !important;
  2393. -webkit-user-select: text !important;
  2394. -khtml-user-select: text !important;
  2395. -moz-user-select: text !important;
  2396. -ms-user-select: text !important;
  2397. user-select: text !important;
  2398. }
  2399. `
  2400. );
  2401. },
  2402. /**
  2403. * 自动展开内容
  2404. */
  2405. autoExpandContent() {
  2406. log.info("自动展开内容");
  2407. return addStyle(
  2408. /*css*/
  2409. `
  2410. #content_views pre.set-code-hide,
  2411. .article_content{
  2412. height: 100% !important;
  2413. overflow: auto !important;
  2414. }
  2415. `
  2416. );
  2417. },
  2418. /**
  2419. * 屏蔽底部工具栏
  2420. */
  2421. blockBottomToolBar() {
  2422. log.info(`屏蔽底部工具栏`);
  2423. return CommonUtil.addBlockCSS("#operate");
  2424. },
  2425. /**
  2426. * 底部工具栏常驻
  2427. */
  2428. bottomToolBarAlwaysShow() {
  2429. log.info(`底部工具栏常驻`);
  2430. return addStyle(
  2431. /*css*/
  2432. `
  2433. /* 底部工具栏 */
  2434. #operate {
  2435. bottom: 0 !important;
  2436. }
  2437. `
  2438. );
  2439. },
  2440. /**
  2441. * 优化收藏按钮
  2442. */
  2443. optimizationCollectButton() {
  2444. log.info(`优化收藏按钮`);
  2445. utils.waitNode("#operate .collect-btn", 1e4).then(($collectBtn) => {
  2446. if (!$collectBtn) {
  2447. return;
  2448. }
  2449. domUtils.on(
  2450. $collectBtn,
  2451. "click",
  2452. async (event) => {
  2453. utils.preventEvent(event);
  2454. let $isCollect = $collectBtn.querySelector(".collect");
  2455. let $unCollect = $collectBtn.querySelector(".uncollect");
  2456. let folderInfo = await CSDNFavoriteApi.folderListWithCheck(
  2457. window.location.origin + window.location.pathname
  2458. );
  2459. if (!folderInfo) {
  2460. return;
  2461. }
  2462. let isFavoriteFolderIdList = [];
  2463. folderInfo.forEach((item) => {
  2464. if (item.IsFavorite) {
  2465. isFavoriteFolderIdList.push(item.ID);
  2466. }
  2467. });
  2468. let createCollectItem = (data) => {
  2469. let folderId = data.ID;
  2470. let $item = domUtils.createElement(
  2471. "li",
  2472. {
  2473. className: "csdn-collection-item",
  2474. innerHTML: (
  2475. /*html*/
  2476. `
  2477. <div class="csdn-collection-item_left">
  2478. <div class="csdn-collection-item_title">
  2479. <span class="title-m">${data.Name}</span>
  2480. </div>
  2481. <span class="csdn-collection-item_ext">
  2482. <span class="csdn-collection-item_length">${data.FavoriteNum}条内容</span>
  2483. <span class="dot">・</span>
  2484. <span class="csdn-collection-controls">${data.IsPrivate ? "私密" : "公开"}</span>
  2485. </span>
  2486. </div>
  2487. <span class="collect-btn">${data.IsFavorite ? "已收藏" : "收藏"}</span>
  2488. `
  2489. )
  2490. },
  2491. {
  2492. "data-is-collect": data.IsFavorite
  2493. }
  2494. );
  2495. $item.querySelector(".title-m");
  2496. let $contentLength = $item.querySelector(
  2497. ".csdn-collection-item_length"
  2498. );
  2499. $item.querySelector(
  2500. ".csdn-collection-controls"
  2501. );
  2502. let $collectBtn2 = $item.querySelector(".collect-btn");
  2503. domUtils.on($collectBtn2, "click", async (event2) => {
  2504. let articleDetailUrl = _unsafeWindow.articleDetailUrl;
  2505. if (articleDetailUrl == null) {
  2506. articleDetailUrl = window.location.origin + window.location.pathname;
  2507. }
  2508. let articleId = _unsafeWindow.articleId;
  2509. if (articleId == null) {
  2510. log.error("获取文章ID失败");
  2511. Qmsg.error("获取文章ID失败");
  2512. return;
  2513. }
  2514. let username = _unsafeWindow.username;
  2515. if (username == null) {
  2516. log.error("获取文章作者失败");
  2517. Qmsg.error("获取文章作者失败");
  2518. return;
  2519. }
  2520. let articleTitle = _unsafeWindow.articleTitle;
  2521. if (articleTitle == null) {
  2522. articleTitle = document.title.replace(/-CSDN博客$/, "");
  2523. }
  2524. if (articleTitle == null) {
  2525. log.error("获取文章标题失败");
  2526. Qmsg.error("获取文章标题失败");
  2527. return;
  2528. }
  2529. let articleDesc = _unsafeWindow.articleDesc;
  2530. if (articleDesc == null) {
  2531. let $meta = $("meta[name='description']");
  2532. if ($meta) {
  2533. articleDesc = $meta.getAttribute("content");
  2534. }
  2535. }
  2536. if (articleDesc == null) {
  2537. log.error("获取文章描述失败");
  2538. Qmsg.error("获取文章描述失败");
  2539. return;
  2540. }
  2541. let folderIdList = [...isFavoriteFolderIdList];
  2542. let $loading = Qmsg.loading("处理中...");
  2543. try {
  2544. let checkResponse = await CSDNFavoriteApi.checkFavoriteByUrl(
  2545. articleDetailUrl
  2546. );
  2547. if (checkResponse == null) {
  2548. return;
  2549. }
  2550. log.info(folderId, checkResponse);
  2551. let toCollect = !checkResponse[folderId];
  2552. if (toCollect) {
  2553. log.info(`添加收藏`);
  2554. folderIdList.push(folderId);
  2555. } else {
  2556. log.info(`取消收藏`);
  2557. folderIdList.splice(folderIdList.indexOf(folderId), 1);
  2558. }
  2559. let response = await CSDNFavoriteApi.addFavoriteInFolds({
  2560. author: username,
  2561. url: articleDetailUrl,
  2562. source: "blog",
  2563. sourceId: articleId,
  2564. title: articleTitle,
  2565. description: articleDesc,
  2566. fromType: "PC",
  2567. username: data.Username,
  2568. folderIdList
  2569. });
  2570. if (!response) {
  2571. return;
  2572. }
  2573. let check_isCollect = await CSDNFavoriteApi.checkFavoriteByUrl(articleDetailUrl);
  2574. if (check_isCollect == null) {
  2575. return;
  2576. }
  2577. log.info(folderId, check_isCollect);
  2578. $item.setAttribute(
  2579. "data-is-collect",
  2580. (!!check_isCollect[folderId]).toString()
  2581. );
  2582. if (toCollect) {
  2583. if (!check_isCollect[folderId]) {
  2584. log.error("收藏失败", check_isCollect, folderId);
  2585. Qmsg.error("收藏失败");
  2586. } else {
  2587. log.success("收藏成功");
  2588. Qmsg.success("收藏成功");
  2589. domUtils.text($collectBtn2, "已收藏");
  2590. if (!isFavoriteFolderIdList.includes(folderId)) {
  2591. isFavoriteFolderIdList.push(folderId);
  2592. }
  2593. data.FavoriteNum++;
  2594. }
  2595. } else {
  2596. if (!check_isCollect[folderId]) {
  2597. log.success("取消收藏成功");
  2598. Qmsg.success("取消收藏成功");
  2599. domUtils.text($collectBtn2, "收藏");
  2600. if (isFavoriteFolderIdList.includes(folderId)) {
  2601. isFavoriteFolderIdList.splice(
  2602. isFavoriteFolderIdList.indexOf(folderId),
  2603. 1
  2604. );
  2605. }
  2606. data.FavoriteNum--;
  2607. } else {
  2608. log.error("取消收藏失败", check_isCollect, folderId);
  2609. Qmsg.error("取消收藏失败");
  2610. }
  2611. }
  2612. domUtils.text($contentLength, `${data.FavoriteNum}条内容`);
  2613. let findValue = Object.values(check_isCollect).find(
  2614. (item) => item
  2615. );
  2616. if (findValue) {
  2617. domUtils.show($isCollect, false);
  2618. domUtils.hide($unCollect, false);
  2619. } else {
  2620. domUtils.show($unCollect, false);
  2621. domUtils.hide($isCollect, false);
  2622. }
  2623. $loading.close();
  2624. } catch (error) {
  2625. log.error(error);
  2626. } finally {
  2627. $loading.close();
  2628. }
  2629. });
  2630. return $item;
  2631. };
  2632. let $alert = __pops.alert({
  2633. title: {
  2634. text: "添加收藏夹",
  2635. position: "center"
  2636. },
  2637. content: {
  2638. text: (
  2639. /*html*/
  2640. `
  2641. <ul class="csdn-collection-items"></ul>
  2642. `
  2643. ),
  2644. html: true
  2645. },
  2646. btn: {
  2647. ok: {
  2648. enable: false
  2649. }
  2650. },
  2651. width: PanelUISize.setting.width,
  2652. height: PanelUISize.setting.height,
  2653. drag: true,
  2654. mask: {
  2655. enable: true
  2656. },
  2657. style: (
  2658. /*css*/
  2659. `
  2660. .csdn-collection-items{
  2661. --font-size: 16px;
  2662. }
  2663. .csdn-collection-items{
  2664. font-size: var(--font-size);
  2665. font-weight: 400;
  2666. padding: 0 20px 0;
  2667. margin: 24px 0;
  2668. overflow: auto;
  2669. -ms-scroll-chaining: none;
  2670. overscroll-behavior: contain;
  2671. }
  2672. .csdn-collection-item{
  2673. width: 100%;
  2674. height: 62px;
  2675. line-height: normal;
  2676. position: relative;
  2677. padding: 8px 12px;
  2678. cursor: pointer;
  2679. display: -webkit-box;
  2680. display: -ms-flexbox;
  2681. display: flex;
  2682. -webkit-box-align: center;
  2683. -ms-flex-align: center;
  2684. align-items: center;
  2685. -webkit-box-pack: justify;
  2686. -ms-flex-pack: justify;
  2687. justify-content: space-between;
  2688. border-bottom: 1px solid #f0f0f5;
  2689. }
  2690. .csdn-collection-item_left{
  2691. line-height: normal;
  2692. flex: 1;
  2693. overflow: hidden;
  2694. }
  2695. .csdn-collection-item_title{
  2696. overflow: hidden;
  2697. text-overflow: ellipsis;
  2698. white-space: nowrap;
  2699. width: 100%;
  2700. }
  2701. .csdn-collection-item_ext{
  2702. font-weight: 400;
  2703. color: #999aaa;
  2704. line-height: 17px;
  2705. margin-top: 8px;
  2706. font-size: .8em;
  2707. overflow: hidden;
  2708. text-overflow: ellipsis;
  2709. white-space: nowrap;
  2710. width: 100%;
  2711. display: inline-flex;
  2712. align-items: center;
  2713. }
  2714. .collect-btn{
  2715. color: #555666;
  2716. font-size: var(--font-size);
  2717. width: 64px;
  2718. height: 30px;
  2719. line-height: 30px;
  2720. border-radius: 20px;
  2721. text-align: center;
  2722. -webkit-transition: all .2s;
  2723. transition: all .2s;
  2724. border: 1px solid #ccccd8;
  2725. }
  2726. .csdn-collection-item[data-is-collect="true"] .collect-btn{
  2727. color: #999aaa;
  2728. background: rgba(232, 232, 237, .3);
  2729. border: 1px solid #e8e8ed;
  2730. }
  2731. /* .csdn-collection-item:hover{
  2732. background: #f5f6f7;
  2733. }
  2734. .csdn-collection-item:hover .collect-btn{
  2735. border: 1px solid #555666;
  2736. } */
  2737. `
  2738. )
  2739. });
  2740. let $collectionContainer = $alert.$shadowRoot.querySelector(
  2741. ".csdn-collection-items"
  2742. );
  2743. folderInfo.forEach((folderInfoItem) => {
  2744. let $item = createCollectItem(folderInfoItem);
  2745. $collectionContainer.appendChild($item);
  2746. });
  2747. },
  2748. { capture: true }
  2749. );
  2750. });
  2751. }
  2752. };
  2753. const ShieldCSS$1 = "/* 右下角的买一年送3个月的广告图标 */\r\n.blind_box {\r\n display: none !important;\r\n}\r\n";
  2754. const M_CSDNWenKu = {
  2755. init() {
  2756. addStyle(ShieldCSS$1);
  2757. Panel.execMenuOnce("m-csdn-wenku-shieldBottomToolbar", () => {
  2758. return this.shieldBottomToolbar();
  2759. });
  2760. },
  2761. /**
  2762. * 【屏蔽】底部工具栏
  2763. */
  2764. shieldBottomToolbar() {
  2765. log.info("【屏蔽】底部工具栏");
  2766. return CommonUtil.addBlockCSS(`.page-container > div.btn`);
  2767. }
  2768. };
  2769. 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";
  2770. const M_CSDNDownload = {
  2771. init() {
  2772. Panel.execMenuOnce("m-csdn-download-removeAds", () => {
  2773. return addStyle(CSDNBlockCSS);
  2774. });
  2775. Panel.execMenuOnce(
  2776. "m-csdn-download-automaticallyExpandResourceIntroduction",
  2777. () => {
  2778. return this.automaticallyExpandResourceIntroduction();
  2779. }
  2780. );
  2781. },
  2782. /**
  2783. * 自动展开资源介绍
  2784. */
  2785. automaticallyExpandResourceIntroduction() {
  2786. log.info("自动展开资源介绍");
  2787. return [
  2788. CommonUtil.addBlockCSS("label.unfold-font"),
  2789. addStyle(
  2790. /*css*/
  2791. `
  2792. .resource-desc{
  2793. max-height: unset !important;
  2794. overflow: unset !important;
  2795. }
  2796. `
  2797. )
  2798. ];
  2799. }
  2800. };
  2801. const ShieldCSS = ".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/* 底部评论工具栏的抢沙发图片 */\r\n.comment-sofa-flag {\r\n display: none !important;\r\n}\r\n";
  2802. 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";
  2803. const M_CSDNBlog = {
  2804. init() {
  2805. this.addCSS();
  2806. },
  2807. /**
  2808. * 添加屏蔽CSS
  2809. */
  2810. addCSS() {
  2811. return [addStyle(ShieldCSS), addStyle(MBlogCSS)];
  2812. }
  2813. };
  2814. const M_CSDN = {
  2815. init() {
  2816. if (CSDNRouter.isLink()) {
  2817. log.info("Router: 中转链接");
  2818. M_CSDNLink.init();
  2819. } else if (CSDNRouter.isHuaWeiCloudBlog()) {
  2820. log.info("Router: 华为云联盟");
  2821. M_CSDNHuaWeiCloud.init();
  2822. } else if (CSDNRouter.isBlog()) {
  2823. log.info("Router: 博客");
  2824. M_CSDNBlog.init();
  2825. if (CSDNRouter.isBlogArticle()) {
  2826. log.info("Router: 文章");
  2827. M_CSDNBlogArticle.init();
  2828. }
  2829. } else if (CSDNRouter.isWenKu()) {
  2830. log.info("Router: 文库");
  2831. M_CSDNWenKu.init();
  2832. } else if (CSDNRouter.isDownload()) {
  2833. log.info("Router: 资源下载");
  2834. M_CSDNDownload.init();
  2835. } else {
  2836. log.error("暂未适配,请反馈开发者:" + globalThis.location.href);
  2837. }
  2838. }
  2839. };
  2840. const PanelComponents = {
  2841. $data: {
  2842. __storeApiFn: null,
  2843. get storeApiValue() {
  2844. if (!this.__storeApiFn) {
  2845. this.__storeApiFn = new Utils.Dictionary();
  2846. }
  2847. return this.__storeApiFn;
  2848. }
  2849. },
  2850. /**
  2851. * 获取自定义的存储接口
  2852. * @param type 组件类型
  2853. */
  2854. getStorageApi(type) {
  2855. if (!this.hasStorageApi(type)) {
  2856. return;
  2857. }
  2858. return this.$data.storeApiValue.get(type);
  2859. },
  2860. /**
  2861. * 判断是否存在自定义的存储接口
  2862. * @param type 组件类型
  2863. */
  2864. hasStorageApi(type) {
  2865. return this.$data.storeApiValue.has(type);
  2866. },
  2867. /**
  2868. * 设置自定义的存储接口
  2869. * @param type 组件类型
  2870. * @param storageApiValue 存储接口
  2871. */
  2872. setStorageApi(type, storageApiValue) {
  2873. this.$data.storeApiValue.set(type, storageApiValue);
  2874. },
  2875. /**
  2876. * 初始化组件的存储接口属性
  2877. *
  2878. * @param type 组件类型
  2879. * @param config 组件配置,必须包含prop属性
  2880. * @param storageApiValue 存储接口
  2881. */
  2882. initComponentsStorageApi(type, config, storageApiValue) {
  2883. let propsStorageApi;
  2884. if (this.hasStorageApi(type)) {
  2885. propsStorageApi = this.getStorageApi(type);
  2886. } else {
  2887. propsStorageApi = storageApiValue;
  2888. }
  2889. this.setComponentsStorageApiProperty(config, propsStorageApi);
  2890. },
  2891. /**
  2892. * 设置组件的存储接口属性
  2893. * @param config 组件配置,必须包含prop属性
  2894. * @param storageApiValue 存储接口
  2895. */
  2896. setComponentsStorageApiProperty(config, storageApiValue) {
  2897. Reflect.set(config.props, PROPS_STORAGE_API, storageApiValue);
  2898. }
  2899. };
  2900. const UISwitch = function(text, key, defaultValue, clickCallback, description, afterAddToUListCallBack) {
  2901. let result = {
  2902. text,
  2903. type: "switch",
  2904. description,
  2905. attributes: {},
  2906. props: {},
  2907. getValue() {
  2908. let storageApiValue = this.props[PROPS_STORAGE_API];
  2909. return Boolean(storageApiValue.get(key, defaultValue));
  2910. },
  2911. callback(event, __value) {
  2912. let value = Boolean(__value);
  2913. log.success(`${value ? "开启" : "关闭"} ${text}`);
  2914. if (typeof clickCallback === "function") {
  2915. let result2 = clickCallback(event, value);
  2916. if (result2) {
  2917. return;
  2918. }
  2919. }
  2920. let storageApiValue = this.props[PROPS_STORAGE_API];
  2921. storageApiValue.set(key, value);
  2922. },
  2923. afterAddToUListCallBack
  2924. };
  2925. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  2926. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  2927. PanelComponents.initComponentsStorageApi(
  2928. "switch",
  2929. result,
  2930. {
  2931. get(key2, defaultValue2) {
  2932. return Panel.getValue(key2, defaultValue2);
  2933. },
  2934. set(key2, value) {
  2935. Panel.setValue(key2, value);
  2936. }
  2937. }
  2938. );
  2939. return result;
  2940. };
  2941. const UISelect = function(text, key, defaultValue, data, changeCallback, description) {
  2942. let selectData = [];
  2943. if (typeof data === "function") {
  2944. selectData = data();
  2945. } else {
  2946. selectData = data;
  2947. }
  2948. let result = {
  2949. text,
  2950. type: "select",
  2951. description,
  2952. attributes: {},
  2953. props: {},
  2954. getValue() {
  2955. let storageApiValue = this.props[PROPS_STORAGE_API];
  2956. return storageApiValue.get(key, defaultValue);
  2957. },
  2958. callback(event, isSelectedValue, isSelectedText) {
  2959. let value = isSelectedValue;
  2960. log.info(`选择:${isSelectedText}`);
  2961. if (typeof changeCallback === "function") {
  2962. let result2 = changeCallback(event, value, isSelectedText);
  2963. if (result2) {
  2964. return;
  2965. }
  2966. }
  2967. let storageApiValue = this.props[PROPS_STORAGE_API];
  2968. storageApiValue.set(key, value);
  2969. },
  2970. data: selectData
  2971. };
  2972. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  2973. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  2974. PanelComponents.initComponentsStorageApi(
  2975. "select",
  2976. result,
  2977. {
  2978. get(key2, defaultValue2) {
  2979. return Panel.getValue(key2, defaultValue2);
  2980. },
  2981. set(key2, value) {
  2982. Panel.setValue(key2, value);
  2983. }
  2984. }
  2985. );
  2986. return result;
  2987. };
  2988. const SettingUICommon = {
  2989. id: "component-common",
  2990. title: "通用",
  2991. forms: [
  2992. {
  2993. text: "Toast配置",
  2994. type: "forms",
  2995. forms: [
  2996. UISelect(
  2997. "Toast位置",
  2998. "qmsg-config-position",
  2999. "bottom",
  3000. [
  3001. {
  3002. value: "topleft",
  3003. text: "左上角"
  3004. },
  3005. {
  3006. value: "top",
  3007. text: "顶部"
  3008. },
  3009. {
  3010. value: "topright",
  3011. text: "右上角"
  3012. },
  3013. {
  3014. value: "left",
  3015. text: "左边"
  3016. },
  3017. {
  3018. value: "center",
  3019. text: "中间"
  3020. },
  3021. {
  3022. value: "right",
  3023. text: "右边"
  3024. },
  3025. {
  3026. value: "bottomleft",
  3027. text: "左下角"
  3028. },
  3029. {
  3030. value: "bottom",
  3031. text: "底部"
  3032. },
  3033. {
  3034. value: "bottomright",
  3035. text: "右下角"
  3036. }
  3037. ],
  3038. (event, isSelectValue, isSelectText) => {
  3039. log.info("设置当前Qmsg弹出位置" + isSelectText);
  3040. },
  3041. "Toast显示在页面九宫格的位置"
  3042. ),
  3043. UISelect(
  3044. "最多显示的数量",
  3045. "qmsg-config-maxnums",
  3046. 3,
  3047. [
  3048. {
  3049. value: 1,
  3050. text: "1"
  3051. },
  3052. {
  3053. value: 2,
  3054. text: "2"
  3055. },
  3056. {
  3057. value: 3,
  3058. text: "3"
  3059. },
  3060. {
  3061. value: 4,
  3062. text: "4"
  3063. },
  3064. {
  3065. value: 5,
  3066. text: "5"
  3067. }
  3068. ],
  3069. void 0,
  3070. "限制Toast显示的数量"
  3071. ),
  3072. UISwitch(
  3073. "逆序弹出",
  3074. "qmsg-config-showreverse",
  3075. false,
  3076. void 0,
  3077. "修改Toast弹出的顺序"
  3078. )
  3079. ]
  3080. }
  3081. // {
  3082. // text: "Cookie配置",
  3083. // type: "forms",
  3084. // forms: [
  3085. // UISwitch(
  3086. // "启用",
  3087. // "httpx-use-cookie-enable",
  3088. // false,
  3089. // void 0,
  3090. // "启用后,将根据下面的配置进行添加cookie"
  3091. // ),
  3092. // UISwitch(
  3093. // "使用document.cookie",
  3094. // "httpx-use-document-cookie",
  3095. // false,
  3096. // void 0,
  3097. // "自动根据请求的域名来设置对应的cookie"
  3098. // ),
  3099. // UITextArea(
  3100. // "tieba.baidu.com",
  3101. // "httpx-cookie-tieba.baidu.com",
  3102. // "",
  3103. // void 0,
  3104. // void 0,
  3105. // "Cookie格式:xxx=xxxx;xxx=xxxx"
  3106. // ),
  3107. // ],
  3108. // },
  3109. ]
  3110. };
  3111. const UISlider = function(text, key, defaultValue, min, max, changeCallback, getToolTipContent, description, step) {
  3112. let result = {
  3113. text,
  3114. type: "slider",
  3115. description,
  3116. attributes: {},
  3117. props: {},
  3118. getValue() {
  3119. let storageApiValue = this.props[PROPS_STORAGE_API];
  3120. return storageApiValue.get(key, defaultValue);
  3121. },
  3122. getToolTipContent(value) {
  3123. if (typeof getToolTipContent === "function") {
  3124. return getToolTipContent(value);
  3125. } else {
  3126. return `${value}`;
  3127. }
  3128. },
  3129. callback(event, value) {
  3130. if (typeof changeCallback === "function") {
  3131. let result2 = changeCallback(event, value);
  3132. if (result2) {
  3133. return;
  3134. }
  3135. }
  3136. let storageApiValue = this.props[PROPS_STORAGE_API];
  3137. storageApiValue.set(key, value);
  3138. },
  3139. min,
  3140. max,
  3141. step
  3142. };
  3143. Reflect.set(result.attributes, ATTRIBUTE_KEY, key);
  3144. Reflect.set(result.attributes, ATTRIBUTE_DEFAULT_VALUE, defaultValue);
  3145. PanelComponents.initComponentsStorageApi(
  3146. "slider",
  3147. result,
  3148. {
  3149. get(key2, defaultValue2) {
  3150. return Panel.getValue(key2, defaultValue2);
  3151. },
  3152. set(key2, value) {
  3153. Panel.setValue(key2, value);
  3154. }
  3155. }
  3156. );
  3157. return result;
  3158. };
  3159. const SettingUIBlog = {
  3160. id: "panel-blog",
  3161. title: "博客",
  3162. isDefault() {
  3163. return CSDNRouter.isBlog();
  3164. },
  3165. forms: [
  3166. {
  3167. type: "forms",
  3168. text: "",
  3169. forms: [
  3170. {
  3171. type: "deepMenu",
  3172. text: "文章",
  3173. forms: [
  3174. {
  3175. type: "forms",
  3176. text: "",
  3177. forms: [
  3178. {
  3179. text: "布局屏蔽",
  3180. type: "deepMenu",
  3181. forms: [
  3182. {
  3183. text: "",
  3184. type: "forms",
  3185. forms: [
  3186. UISwitch(
  3187. "【屏蔽】登录弹窗",
  3188. "csdn-blog-shieldLoginDialog",
  3189. true
  3190. ),
  3191. UISwitch(
  3192. "【屏蔽】左侧博客信息",
  3193. "csdn-blog-shieldLeftBlogContainerAside",
  3194. false
  3195. ),
  3196. UISwitch(
  3197. "【屏蔽】右侧目录信息",
  3198. "csdn-blog-shieldRightDirectoryInformation",
  3199. false
  3200. ),
  3201. UISwitch(
  3202. "【屏蔽】底部的悬浮工具栏",
  3203. "csdn-blog-shieldBottomFloatingToolbar",
  3204. false
  3205. )
  3206. ]
  3207. }
  3208. ]
  3209. },
  3210. {
  3211. text: "右侧悬浮工具栏",
  3212. type: "deepMenu",
  3213. forms: [
  3214. {
  3215. text: "功能",
  3216. type: "forms",
  3217. forms: [
  3218. UISwitch(
  3219. "启用",
  3220. "csdn-blog-rightToolbarEnable",
  3221. true,
  3222. void 0,
  3223. "创作中心,隐藏/显示侧栏,新手引导,客服、举报..."
  3224. ),
  3225. UISwitch(
  3226. "【添加按钮】前往评论",
  3227. "csdn-blog-addGotoRecommandButton",
  3228. true,
  3229. void 0,
  3230. "在悬浮工具栏最后面添加"
  3231. ),
  3232. UISlider(
  3233. "right偏移",
  3234. "csdn-blog-rightToolbarRightOffset",
  3235. 90,
  3236. 0,
  3237. document.documentElement.clientWidth,
  3238. (event, value) => {
  3239. let csdnSideToolbar = document.querySelector(
  3240. ".csdn-side-toolbar"
  3241. );
  3242. domUtils.css(csdnSideToolbar, {
  3243. right: value + "px"
  3244. });
  3245. },
  3246. (value) => {
  3247. return `当前:${value}px,默认:90px`;
  3248. }
  3249. ),
  3250. UISlider(
  3251. "top偏移",
  3252. "csdn-blog-rightToolbarTopOffset",
  3253. 140,
  3254. 0,
  3255. document.documentElement.clientHeight,
  3256. (event, value) => {
  3257. let csdnSideToolbar = document.querySelector(
  3258. ".csdn-side-toolbar"
  3259. );
  3260. domUtils.css(csdnSideToolbar, {
  3261. top: value + "px"
  3262. });
  3263. },
  3264. (value) => {
  3265. return `当前:${value}px,默认:90px`;
  3266. }
  3267. )
  3268. ]
  3269. },
  3270. {
  3271. text: "屏蔽",
  3272. type: "forms",
  3273. forms: [
  3274. UISwitch(
  3275. "【屏蔽】创作中心",
  3276. "csdn-blog-rightToolbarCreativeCenter",
  3277. false
  3278. ),
  3279. UISwitch(
  3280. "【屏蔽】显示/隐藏侧栏",
  3281. "csdn-blog-rightToolbarShowOrSidebar",
  3282. false
  3283. ),
  3284. UISwitch(
  3285. "【屏蔽】新手引导",
  3286. "csdn-blog-rightToolbarBeginnerGuidance",
  3287. false
  3288. ),
  3289. UISwitch(
  3290. "【屏蔽】客服",
  3291. "csdn-blog-rightToolbarCustomerService",
  3292. false
  3293. ),
  3294. UISwitch(
  3295. "【屏蔽】举报",
  3296. "csdn-blog-rightToolbarReport",
  3297. false
  3298. ),
  3299. UISwitch(
  3300. "【屏蔽】返回顶部",
  3301. "csdn-blog-rightToolbarBackToTop",
  3302. false
  3303. )
  3304. ]
  3305. }
  3306. ]
  3307. },
  3308. {
  3309. text: "内容",
  3310. type: "deepMenu",
  3311. forms: [
  3312. {
  3313. text: "功能",
  3314. type: "forms",
  3315. forms: [
  3316. UISwitch(
  3317. "点击代码块自动展开",
  3318. "csdn-blog-clickPreCodeAutomatically",
  3319. true,
  3320. void 0,
  3321. "当鼠标点击代码块区域时,将自动展开内容"
  3322. ),
  3323. UISwitch(
  3324. "自动展开代码块",
  3325. "csdn-blog-autoExpandCodeContent",
  3326. true,
  3327. void 0,
  3328. "懒人操作,免手动点击展开"
  3329. ),
  3330. UISwitch(
  3331. "自动展开内容",
  3332. "csdn-blog-autoExpandContent",
  3333. true,
  3334. void 0,
  3335. "懒人操作,免手动点击展开"
  3336. ),
  3337. UISwitch(
  3338. "全文居中",
  3339. "csdn-blog-articleCenter",
  3340. true,
  3341. function(event, enable) {
  3342. if (enable) {
  3343. alert(
  3344. "为了更好的呈现效果,请开启功能:【屏蔽】左侧博客信息、【屏蔽】右侧目录信息"
  3345. );
  3346. }
  3347. },
  3348. "自动屏蔽左侧和右侧的信息,且将文章居中"
  3349. ),
  3350. UISwitch(
  3351. "允许选择内容",
  3352. "csdn-blog-allowSelectContent",
  3353. true,
  3354. void 0
  3355. )
  3356. ]
  3357. },
  3358. {
  3359. text: "屏蔽",
  3360. type: "forms",
  3361. forms: [
  3362. UISwitch(
  3363. "【屏蔽】底部xx技能树",
  3364. "csdn-blog-shieldBottomSkillTree",
  3365. false
  3366. ),
  3367. UISwitch(
  3368. "【屏蔽】选中文字悬浮栏",
  3369. "csdn-blog-shieldArticleSearchTip",
  3370. false,
  3371. void 0,
  3372. "选中文字弹出的,例如:搜索、评论、笔记"
  3373. )
  3374. ]
  3375. }
  3376. ]
  3377. },
  3378. {
  3379. text: "评论区",
  3380. type: "deepMenu",
  3381. forms: [
  3382. {
  3383. text: "",
  3384. type: "forms",
  3385. forms: [
  3386. UISwitch(
  3387. "启用",
  3388. "csdn-blog-blockComment",
  3389. true,
  3390. void 0,
  3391. "关闭是屏蔽评论区"
  3392. ),
  3393. UISwitch(
  3394. "优化评论区的位置",
  3395. "csdn-blog-restoreComments",
  3396. true
  3397. )
  3398. ]
  3399. }
  3400. ]
  3401. },
  3402. {
  3403. text: "底部文章",
  3404. type: "deepMenu",
  3405. forms: [
  3406. {
  3407. text: "",
  3408. type: "forms",
  3409. forms: [
  3410. UISwitch(
  3411. "启用",
  3412. "csdn-blog-bottomRecommendArticleEnable",
  3413. true,
  3414. void 0,
  3415. "关闭是屏蔽底部文章"
  3416. ),
  3417. UISwitch(
  3418. "标识CSDN下载",
  3419. "csdn-blog-identityCSDNDownload",
  3420. true,
  3421. void 0,
  3422. "使用红框标识"
  3423. ),
  3424. UISwitch(
  3425. "移除资源下载的文章",
  3426. "csdn-blog-removeResourceDownloadArticle",
  3427. false,
  3428. void 0,
  3429. "download.csdn.net<br>www.iteye.com<br>edu.csdn.net"
  3430. )
  3431. ]
  3432. }
  3433. ]
  3434. }
  3435. ]
  3436. }
  3437. ]
  3438. }
  3439. ]
  3440. },
  3441. {
  3442. text: "",
  3443. type: "forms",
  3444. forms: [
  3445. {
  3446. text: "全局布局屏蔽",
  3447. type: "deepMenu",
  3448. forms: [
  3449. {
  3450. text: "",
  3451. type: "forms",
  3452. forms: [
  3453. UISwitch(
  3454. "【屏蔽】顶部工具栏",
  3455. "csdn-blog-shieldTopToolbar",
  3456. false
  3457. )
  3458. ]
  3459. }
  3460. ]
  3461. },
  3462. {
  3463. text: "劫持/拦截",
  3464. type: "deepMenu",
  3465. forms: [
  3466. {
  3467. text: "",
  3468. type: "forms",
  3469. forms: [
  3470. UISwitch(
  3471. "拦截-复制的小尾巴",
  3472. "csdn-blog-removeClipboardHijacking",
  3473. true
  3474. ),
  3475. UISwitch(
  3476. "劫持-禁止复制",
  3477. "csdn-blog-unBlockCopy",
  3478. true,
  3479. void 0,
  3480. "允许点击复制按钮进行复制"
  3481. )
  3482. ]
  3483. }
  3484. ]
  3485. }
  3486. ]
  3487. }
  3488. ]
  3489. };
  3490. const SettingUILink = {
  3491. id: "panel-link",
  3492. title: "链接",
  3493. isDefault() {
  3494. return CSDNRouter.isLink();
  3495. },
  3496. forms: [
  3497. {
  3498. text: "功能",
  3499. type: "forms",
  3500. forms: [
  3501. UISwitch(
  3502. "重定向链接",
  3503. "csdn-link-jumpRedirect",
  3504. true,
  3505. void 0,
  3506. "自动跳转至被拦截的Url链接"
  3507. )
  3508. ]
  3509. }
  3510. ]
  3511. };
  3512. const SettingUIHuaWeiCloud = {
  3513. id: "panel-hua-wei-cloud",
  3514. title: "华为云开发者联盟",
  3515. isDefault() {
  3516. return CSDNRouter.isHuaWeiCloudBlog();
  3517. },
  3518. forms: [
  3519. {
  3520. text: "功能",
  3521. type: "forms",
  3522. forms: [
  3523. UISwitch("自动展开全文", "csdn-hua-wei-cloud-autoExpandContent", true)
  3524. ]
  3525. },
  3526. {
  3527. text: "屏蔽",
  3528. type: "forms",
  3529. forms: [
  3530. UISwitch(
  3531. "【屏蔽】云开发者任务挑战活动",
  3532. "csdn-hua-wei-cloud-shieldCloudDeveloperTaskChallengeEvent",
  3533. true
  3534. ),
  3535. UISwitch(
  3536. "【屏蔽】左侧悬浮按钮",
  3537. "csdn-hua-wei-cloud-shieldLeftFloatingButton",
  3538. false,
  3539. function(event, enable) {
  3540. if (enable) {
  3541. alert(
  3542. "开启后将屏蔽【当前阅读量】、【点赞按钮】、【评论按钮】、【分享按钮】"
  3543. );
  3544. }
  3545. }
  3546. ),
  3547. UISwitch(
  3548. "【屏蔽】右侧栏",
  3549. "csdn-hua-wei-cloud-blockRightColumn",
  3550. false,
  3551. function(event, enable) {
  3552. if (enable) {
  3553. alert(
  3554. "开启后将屏蔽【相关产品】-【活动日历】-【运营活动】-【热门标签】"
  3555. );
  3556. }
  3557. }
  3558. ),
  3559. UISwitch(
  3560. "【屏蔽】底部推荐内容",
  3561. "csdn-hua-wei-cloud-blockRecommendedContentAtTheBottom",
  3562. false
  3563. ),
  3564. UISwitch(
  3565. "【屏蔽】底部更多推荐",
  3566. "csdn-hua-wei-cloud-shieldTheBottomForMoreRecommendations",
  3567. false
  3568. )
  3569. ]
  3570. }
  3571. ]
  3572. };
  3573. const SettingUIWenKu = {
  3574. id: "panel-wenku",
  3575. title: "资源",
  3576. isDefault() {
  3577. return CSDNRouter.isLink();
  3578. },
  3579. forms: [
  3580. {
  3581. text: "屏蔽",
  3582. type: "forms",
  3583. forms: [
  3584. UISwitch(
  3585. "【屏蔽】资源推荐",
  3586. "csdn-wenku-shieldResourceRecommend",
  3587. false
  3588. ),
  3589. UISwitch(
  3590. "【屏蔽】右侧用户信息",
  3591. "csdn-wenku-shieldRightUserInfo",
  3592. false
  3593. ),
  3594. UISwitch(
  3595. "【屏蔽】右侧悬浮工具栏",
  3596. "csdn-wenku-shieldRightToolBar",
  3597. false
  3598. )
  3599. ]
  3600. }
  3601. ]
  3602. };
  3603. const SettingUISo = {
  3604. id: "panel-so",
  3605. title: "搜索",
  3606. isDefault() {
  3607. return CSDNRouter.isSo();
  3608. },
  3609. forms: [
  3610. {
  3611. text: "C知道-功能",
  3612. type: "forms",
  3613. forms: [UISwitch("去除水印", "csdn-so-cknow-removeMaskCover", true)]
  3614. }
  3615. ]
  3616. };
  3617. const MSettingUICommon = {
  3618. id: "component-common",
  3619. title: "通用",
  3620. forms: [
  3621. {
  3622. text: "Toast配置",
  3623. type: "forms",
  3624. forms: [
  3625. UISelect(
  3626. "Toast位置",
  3627. "qmsg-config-position",
  3628. "bottom",
  3629. [
  3630. {
  3631. value: "topleft",
  3632. text: "左上角"
  3633. },
  3634. {
  3635. value: "top",
  3636. text: "顶部"
  3637. },
  3638. {
  3639. value: "topright",
  3640. text: "右上角"
  3641. },
  3642. {
  3643. value: "left",
  3644. text: "左边"
  3645. },
  3646. {
  3647. value: "center",
  3648. text: "中间"
  3649. },
  3650. {
  3651. value: "right",
  3652. text: "右边"
  3653. },
  3654. {
  3655. value: "bottomleft",
  3656. text: "左下角"
  3657. },
  3658. {
  3659. value: "bottom",
  3660. text: "底部"
  3661. },
  3662. {
  3663. value: "bottomright",
  3664. text: "右下角"
  3665. }
  3666. ],
  3667. (event, isSelectValue, isSelectText) => {
  3668. log.info("设置当前Qmsg弹出位置" + isSelectText);
  3669. },
  3670. "Toast显示在页面九宫格的位置"
  3671. ),
  3672. UISelect(
  3673. "最多显示的数量",
  3674. "qmsg-config-maxnums",
  3675. 3,
  3676. [
  3677. {
  3678. value: 1,
  3679. text: "1"
  3680. },
  3681. {
  3682. value: 2,
  3683. text: "2"
  3684. },
  3685. {
  3686. value: 3,
  3687. text: "3"
  3688. },
  3689. {
  3690. value: 4,
  3691. text: "4"
  3692. },
  3693. {
  3694. value: 5,
  3695. text: "5"
  3696. }
  3697. ],
  3698. void 0,
  3699. "限制Toast显示的数量"
  3700. ),
  3701. UISwitch(
  3702. "逆序弹出",
  3703. "qmsg-config-showreverse",
  3704. false,
  3705. void 0,
  3706. "修改Toast弹出的顺序"
  3707. )
  3708. ]
  3709. }
  3710. // {
  3711. // text: "Cookie配置",
  3712. // type: "forms",
  3713. // forms: [
  3714. // UISwitch(
  3715. // "启用",
  3716. // "httpx-use-cookie-enable",
  3717. // false,
  3718. // void 0,
  3719. // "启用后,将根据下面的配置进行添加cookie"
  3720. // ),
  3721. // UISwitch(
  3722. // "使用document.cookie",
  3723. // "httpx-use-document-cookie",
  3724. // false,
  3725. // void 0,
  3726. // "自动根据请求的域名来设置对应的cookie"
  3727. // ),
  3728. // UITextArea(
  3729. // "tieba.baidu.com",
  3730. // "httpx-cookie-tieba.baidu.com",
  3731. // "",
  3732. // void 0,
  3733. // void 0,
  3734. // "Cookie格式:xxx=xxxx;xxx=xxxx"
  3735. // ),
  3736. // ],
  3737. // },
  3738. ]
  3739. };
  3740. const MSettingUIBlog = {
  3741. id: "m-panel-blog",
  3742. title: "博客",
  3743. isDefault() {
  3744. return CSDNRouter.isBlog();
  3745. },
  3746. forms: [
  3747. {
  3748. type: "forms",
  3749. text: "",
  3750. forms: [
  3751. {
  3752. type: "deepMenu",
  3753. text: "文章",
  3754. forms: [
  3755. {
  3756. text: "",
  3757. type: "forms",
  3758. forms: [
  3759. {
  3760. type: "deepMenu",
  3761. text: "顶部工具栏",
  3762. forms: [
  3763. {
  3764. type: "forms",
  3765. text: "",
  3766. forms: [
  3767. UISwitch(
  3768. "启用",
  3769. "m-csdn-blog-shieldTopToolbar",
  3770. false,
  3771. void 0,
  3772. "关闭是屏蔽顶部工具栏"
  3773. )
  3774. ]
  3775. }
  3776. ]
  3777. },
  3778. {
  3779. text: "内容",
  3780. type: "deepMenu",
  3781. forms: [
  3782. {
  3783. text: "",
  3784. type: "forms",
  3785. forms: [
  3786. UISwitch(
  3787. "允许选中文字",
  3788. "m-csdn-blog-allowSelectText",
  3789. true,
  3790. void 0,
  3791. "设置user-select: text;"
  3792. ),
  3793. UISwitch(
  3794. "自动展开",
  3795. "m-csdn-blog-autoExpandContent",
  3796. true,
  3797. void 0,
  3798. "包括内容、代码块"
  3799. ),
  3800. UISwitch(
  3801. "不限制代码块的最大高度",
  3802. "m-csdn-blog-notLimitCodePreMaxHeight",
  3803. false,
  3804. void 0,
  3805. "让代码块的高度直接被撑开"
  3806. )
  3807. ]
  3808. }
  3809. ]
  3810. },
  3811. {
  3812. text: "评论",
  3813. type: "deepMenu",
  3814. forms: [
  3815. {
  3816. text: "",
  3817. type: "forms",
  3818. forms: [
  3819. UISwitch(
  3820. "启用",
  3821. "m-csdn-blog-comment-enable",
  3822. true,
  3823. void 0,
  3824. "关闭是屏蔽评论区"
  3825. ),
  3826. UISwitch(
  3827. "不限制评论区的最大高度",
  3828. "m-csdn-blog-notLimitCommentMaxHeight",
  3829. true,
  3830. void 0,
  3831. "让评论区高度直接被撑开"
  3832. )
  3833. ]
  3834. }
  3835. ]
  3836. },
  3837. {
  3838. text: "底部文章",
  3839. type: "deepMenu",
  3840. forms: [
  3841. {
  3842. text: "",
  3843. type: "forms",
  3844. forms: [
  3845. UISwitch(
  3846. "启用",
  3847. "m-csdn-blog-bottomArticleEnable",
  3848. true,
  3849. void 0,
  3850. "关闭是屏蔽底部文章"
  3851. ),
  3852. UISwitch(
  3853. "移除资源下载",
  3854. "m-csdn-blog-removeResourceArticle",
  3855. false,
  3856. void 0,
  3857. "download.csdn.net<br>www.iteye.com<br>edu.csdn.net"
  3858. ),
  3859. UISwitch(
  3860. "重构",
  3861. "m-csdn-blog-refactoringRecommendation",
  3862. true,
  3863. void 0,
  3864. "文章的样式统一"
  3865. ),
  3866. UISwitch(
  3867. "新标签页打开",
  3868. "m-csdn-blog-openNewTab",
  3869. true,
  3870. void 0,
  3871. "新标签页打开文章"
  3872. )
  3873. ]
  3874. }
  3875. ]
  3876. },
  3877. {
  3878. type: "deepMenu",
  3879. text: "底部工具栏",
  3880. forms: [
  3881. {
  3882. type: "forms",
  3883. text: "",
  3884. forms: [
  3885. UISwitch(
  3886. "启用",
  3887. "m-csdn-blog-bottom-toolbar-enable",
  3888. false,
  3889. void 0,
  3890. "关闭是屏蔽底部工具栏"
  3891. ),
  3892. UISwitch(
  3893. "常驻底部",
  3894. "m-csdn-blog-bottom-toolbar-always-bottom",
  3895. false,
  3896. void 0,
  3897. "开启后底部工具栏不随下滑滚动而隐藏"
  3898. ),
  3899. UISwitch(
  3900. "优化收藏按钮",
  3901. "m-csdn-blog-bottom-toolbar-optimizationCollectButton",
  3902. false,
  3903. void 0,
  3904. "可以自行选择收藏夹"
  3905. )
  3906. ]
  3907. }
  3908. ]
  3909. }
  3910. ]
  3911. }
  3912. ]
  3913. }
  3914. ]
  3915. },
  3916. {
  3917. type: "forms",
  3918. text: "",
  3919. forms: [
  3920. {
  3921. text: "功能",
  3922. type: "deepMenu",
  3923. forms: [
  3924. {
  3925. text: "",
  3926. type: "forms",
  3927. forms: [
  3928. UISwitch(
  3929. "【屏蔽】广告",
  3930. "m-csdn-blog-removeAds",
  3931. true,
  3932. void 0,
  3933. "包括:登录弹窗、打开APP、ios版本提示等"
  3934. ),
  3935. UISwitch(
  3936. "允许复制",
  3937. "m-csdn-blog-unBlockCopy",
  3938. true,
  3939. void 0,
  3940. "允许点击复制按钮进行复制"
  3941. )
  3942. ]
  3943. }
  3944. ]
  3945. }
  3946. ]
  3947. }
  3948. ]
  3949. };
  3950. const MSettingUILink = {
  3951. id: "m-panel-link",
  3952. title: "链接",
  3953. isDefault() {
  3954. return CSDNRouter.isLink();
  3955. },
  3956. forms: [
  3957. {
  3958. text: "功能",
  3959. type: "forms",
  3960. forms: [
  3961. UISwitch(
  3962. "重定向链接",
  3963. "m-csdn-link-jumpRedirect",
  3964. true,
  3965. void 0,
  3966. "自动跳转至被拦截的Url链接"
  3967. )
  3968. ]
  3969. }
  3970. ]
  3971. };
  3972. const MSettingUIHuaWeiCloud = {
  3973. id: "m-panel-hua-wei-cloud",
  3974. title: "华为云开发者联盟",
  3975. isDefault() {
  3976. return CSDNRouter.isHuaWeiCloudBlog();
  3977. },
  3978. forms: [
  3979. {
  3980. text: "功能",
  3981. type: "forms",
  3982. forms: [
  3983. UISwitch(
  3984. "自动展开全文",
  3985. "m-csdn-hua-wei-cloud-autoExpandContent",
  3986. true
  3987. )
  3988. ]
  3989. },
  3990. {
  3991. text: "屏蔽",
  3992. type: "forms",
  3993. forms: [
  3994. UISwitch(
  3995. "【屏蔽】底部加入社区",
  3996. "m-csdn-hua-wei-cloud-blockBottomJoinTheCommunity",
  3997. true
  3998. )
  3999. ]
  4000. }
  4001. ]
  4002. };
  4003. const MSettingUIWenKu = {
  4004. id: "m-panel-wenku",
  4005. title: "文库",
  4006. isDefault() {
  4007. return CSDNRouter.isWenKu();
  4008. },
  4009. forms: [
  4010. {
  4011. text: "屏蔽",
  4012. type: "forms",
  4013. forms: [
  4014. UISwitch(
  4015. "【屏蔽】底部工具栏",
  4016. "m-csdn-wenku-shieldBottomToolbar",
  4017. false
  4018. )
  4019. ]
  4020. }
  4021. ]
  4022. };
  4023. const MSettingUISo = {
  4024. id: "panel-so",
  4025. title: "搜索",
  4026. isDefault() {
  4027. return CSDNRouter.isSo();
  4028. },
  4029. forms: [
  4030. {
  4031. text: "C知道-功能",
  4032. type: "forms",
  4033. forms: [UISwitch("去除水印", "m-csdn-so-cknow-removeMaskCover", true)]
  4034. }
  4035. ]
  4036. };
  4037. const MSettingUIDownload = {
  4038. id: "m-panel-download",
  4039. title: "资源",
  4040. isDefault() {
  4041. return CSDNRouter.isDownload();
  4042. },
  4043. forms: [
  4044. {
  4045. text: "功能",
  4046. type: "forms",
  4047. forms: [
  4048. UISwitch(
  4049. "自动展开资源介绍",
  4050. "m-csdn-download-automaticallyExpandResourceIntroduction",
  4051. true,
  4052. void 0,
  4053. "屏蔽资源介绍【展开全部】按钮并展开资源介绍"
  4054. )
  4055. ]
  4056. },
  4057. {
  4058. text: "屏蔽",
  4059. type: "forms",
  4060. forms: [
  4061. UISwitch(
  4062. "【屏蔽】广告",
  4063. "m-csdn-download-removeAds",
  4064. true,
  4065. void 0,
  4066. "包括:登录弹窗、会员降价等"
  4067. )
  4068. ]
  4069. }
  4070. ]
  4071. };
  4072. PanelMenu.deleteMenuOption(0);
  4073. PanelMenu.addMenuOption([
  4074. {
  4075. key: "show_pops_panel_setting",
  4076. text: "⚙ PC端设置",
  4077. autoReload: false,
  4078. isStoreValue: false,
  4079. showText(text) {
  4080. return text;
  4081. },
  4082. callback: () => {
  4083. Panel.showPanel(PanelContent.getConfig(0));
  4084. }
  4085. },
  4086. {
  4087. key: "m_show_pops_panel_setting",
  4088. text: "⚙ 移动端端设置",
  4089. autoReload: false,
  4090. isStoreValue: false,
  4091. showText(text) {
  4092. return text;
  4093. },
  4094. callback: () => {
  4095. Panel.showPanel(PanelContent.getConfig(1));
  4096. }
  4097. },
  4098. {
  4099. key: "gotoCSDNCKnow",
  4100. text: "⚙ 前往C知道",
  4101. isStoreValue: false,
  4102. autoReload: false,
  4103. showText(text) {
  4104. return text;
  4105. },
  4106. callback() {
  4107. window.open("https://so.csdn.net/chat", "_blank");
  4108. }
  4109. }
  4110. ]);
  4111. PanelContent.addContentConfig([
  4112. SettingUICommon,
  4113. SettingUIBlog,
  4114. SettingUILink,
  4115. SettingUIHuaWeiCloud,
  4116. SettingUIWenKu,
  4117. SettingUISo
  4118. ]);
  4119. PanelContent.addContentConfig([
  4120. MSettingUICommon,
  4121. MSettingUIBlog,
  4122. MSettingUILink,
  4123. MSettingUIHuaWeiCloud,
  4124. MSettingUIWenKu,
  4125. MSettingUISo,
  4126. MSettingUIDownload
  4127. ]);
  4128. Panel.init();
  4129. let isMobile = utils.isPhone();
  4130. let CHANGE_ENV_SET_KEY = "change_env_set";
  4131. let chooseMode = _GM_getValue(CHANGE_ENV_SET_KEY);
  4132. GM_Menu.add({
  4133. key: CHANGE_ENV_SET_KEY,
  4134. text: `⚙ 自动: ${isMobile ? "移动端" : "PC端"}`,
  4135. autoReload: false,
  4136. isStoreValue: false,
  4137. showText(text) {
  4138. if (chooseMode == null) {
  4139. return text;
  4140. }
  4141. return text + ` 手动: ${chooseMode == 1 ? "移动端" : chooseMode == 2 ? "PC端" : "未知"}`;
  4142. },
  4143. callback: () => {
  4144. let allowValue = [0, 1, 2];
  4145. let chooseText = window.prompt(
  4146. "请输入当前脚本环境判定\n\n自动判断: 0\n移动端: 1\nPC端: 2",
  4147. "0"
  4148. );
  4149. if (!chooseText) {
  4150. return;
  4151. }
  4152. let chooseMode2 = parseInt(chooseText);
  4153. if (isNaN(chooseMode2)) {
  4154. Qmsg.error("输入的不是规范的数字");
  4155. return;
  4156. }
  4157. if (!allowValue.includes(chooseMode2)) {
  4158. Qmsg.error("输入的值必须是0或1或2");
  4159. return;
  4160. }
  4161. if (chooseMode2 == 0) {
  4162. _GM_deleteValue(CHANGE_ENV_SET_KEY);
  4163. } else {
  4164. _GM_setValue(CHANGE_ENV_SET_KEY, chooseMode2);
  4165. }
  4166. }
  4167. });
  4168. if (chooseMode != null) {
  4169. log.info(`手动判定为${chooseMode === 1 ? "移动端" : "PC端"}`);
  4170. if (chooseMode == 1) {
  4171. M_CSDN.init();
  4172. } else if (chooseMode == 2) {
  4173. CSDN.init();
  4174. } else {
  4175. Qmsg.error("意外,手动判定的值不在范围内");
  4176. _GM_deleteValue(CHANGE_ENV_SET_KEY);
  4177. }
  4178. } else {
  4179. if (isMobile) {
  4180. log.info("自动判定为移动端");
  4181. M_CSDN.init();
  4182. } else {
  4183. log.info("自动判定为PC端");
  4184. CSDN.init();
  4185. }
  4186. }
  4187.  
  4188. })(Qmsg, DOMUtils, Utils, pops);