简书优化

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

目前为 2024-03-24 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 简书优化
  3. // @icon https://www.jianshu.com/favicon.ico
  4. // @namespace https://gf.qytechs.cn/zh-CN/scripts/485483
  5. // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues
  6. // @version 2024.3.24.19
  7. // @license MIT
  8. // @description 支持手机端和PC端,屏蔽广告,优化浏览体验,自动跳转拦截的URL
  9. // @author WhiteSevs
  10. // @match *://*.jianshu.com/*
  11. // @match *://*.jianshu.io/*
  12. // @grant GM_registerMenuCommand
  13. // @grant GM_unregisterMenuCommand
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // @grant GM_deleteValue
  17. // @grant GM_info
  18. // @grant unsafeWindow
  19. // @run-at document-start
  20. // @require https://update.gf.qytechs.cn/scripts/456485/1348320/pops.js
  21. // @require https://update.gf.qytechs.cn/scripts/455186/1348379/WhiteSevsUtils.js
  22. // @require https://update.gf.qytechs.cn/scripts/465772/1344519/DOMUtils.js
  23. // ==/UserScript==
  24.  
  25. (function () {
  26. if(typeof unsafeWindow === "undefined"){
  27. unsafeWindow = globalThis;
  28. }
  29. /**
  30. * @type {import("../库/pops")}
  31. */
  32. const pops = window.pops;
  33. /**
  34. * @type {import("../库/Utils")}
  35. */
  36. const utils = window.Utils.noConflict();
  37. /**
  38. * @type {import("../库/DOMUtils")}
  39. */
  40. const DOMUtils = window.DOMUtils.noConflict();
  41. const log = new utils.Log(GM_info, unsafeWindow.console || console);
  42. log.config({
  43. autoClearConsole: false,
  44. });
  45. const GM_addStyle = utils.addStyle;
  46. /**
  47. * 菜单
  48. */
  49. const GM_Menu = new utils.GM_Menu({
  50. GM_getValue,
  51. GM_setValue,
  52. GM_registerMenuCommand,
  53. GM_unregisterMenuCommand,
  54. });
  55. /**
  56. * 移除元素(未出现也可以等待出现)
  57. * @param {string} selectorText 元素选择器
  58. */
  59. const waitForElementToRemove = function (selectorText = "") {
  60. utils.waitNodeList(selectorText).then((nodeList) => {
  61. nodeList.forEach((item) => {
  62. item.remove();
  63. });
  64. });
  65. };
  66.  
  67. const Optimization = {
  68. jianshu: {
  69. /**
  70. * 函数入口
  71. */
  72. init() {
  73. if (utils.isPhone()) {
  74. log.success("简书-移动端");
  75. this.Mobile.run();
  76. } else {
  77. log.success("简书-桌面端");
  78. this.PC.run();
  79. }
  80. },
  81. PC: {
  82. /**
  83. * 添加屏蔽CSS
  84. */
  85. addCSS() {
  86. GM_addStyle(`
  87. .download-app-guidance,
  88. .call-app-btn,
  89. .collapse-tips,
  90. .note-graceful-button,
  91. .app-open,
  92. .header-wrap,
  93. .recommend-wrap.recommend-ad,
  94. .call-app-Ad-bottom,
  95. #recommended-notes p.top-title span.more,
  96. #homepage .modal,
  97. button.index_call-app-btn,
  98. span.note__flow__download,
  99. .download-guide,
  100. #footer,
  101. .comment-open-app-btn-wrap,
  102. .nav.navbar-nav + div,
  103. .self-flow-ad,
  104. #free-reward-panel,
  105. div[id*='AdFive'],
  106. #index-aside-download-qrbox,
  107. .baidu-app-download-2eIkf_1,
  108. /* 底部的"小礼物走一走,来简书关注我"、赞赏支持和更多精彩内容,就在简书APP */
  109. div[role="main"] > div > section:first-child > div:nth-last-child(2),
  110. /* 它的内部是script标签,可能影响部分评论之间的高度问题 */
  111. div.adad_container{
  112. display:none !important;
  113. }
  114. body.reader-day-mode.normal-size {
  115. overflow: auto !important;
  116. }
  117. .collapse-free-content{
  118. height:auto !important;
  119. }
  120. .copyright{
  121. color:#000 !important;
  122. }
  123. #note-show .content .show-content-free .collapse-free-content:after{
  124. background-image:none !important;
  125. }
  126. footer > div > div{
  127. justify-content: center;
  128. }
  129. /* 修复底部最后编辑于:。。。在某些套壳浏览器上的错位问题 */
  130. #note-show .content .show-content-free .note-meta-time{
  131. margin-top: 0px !important;
  132. }
  133. `);
  134. },
  135. /**
  136. * 全文居中
  137. */
  138. articleCenter() {
  139. log.success("全文居中");
  140. GM_addStyle(`
  141. div[role=main] aside,
  142. div._3Pnjry{
  143. display: none !important;
  144. }
  145. div._gp-ck{
  146. width: 100% !important;
  147. }`);
  148. waitForElementToRemove("div[role=main] aside");
  149. waitForElementToRemove("div._3Pnjry");
  150. utils.waitNodeList("div._gp-ck").then((nodeList) => {
  151. nodeList.forEach((item) => {
  152. item.style["width"] = "100%";
  153. });
  154. });
  155. },
  156. /**
  157. * 去除剪贴板劫持
  158. */
  159. removeClipboardHijacking() {
  160. log.success("去除剪贴板劫持");
  161. const stopNativePropagation = (event) => {
  162. event.stopPropagation();
  163. };
  164. window.addEventListener("copy", stopNativePropagation, true);
  165. document.addEventListener("copy", stopNativePropagation, true);
  166. },
  167. /**
  168. * 自动展开全文
  169. */
  170. autoExpandFullText() {
  171. utils
  172. .waitNode(`div#homepage div[class*="dialog-"]`)
  173. .then((element) => {
  174. element.style["visibility"] = "hidden";
  175. utils.mutationObserver(element, {
  176. callback: (mutations) => {
  177. if (mutations.length == 0) {
  178. return;
  179. }
  180. if (mutations.target.style["display"] != "none") {
  181. log.success("自动展开全文");
  182. document
  183. .querySelector(
  184. 'div#homepage div[class*="dialog-"] .cancel'
  185. )
  186. ?.click();
  187. }
  188. },
  189. config: {
  190. /* 子节点的变动(新增、删除或者更改) */
  191. childList: false,
  192. /* 属性的变动 */
  193. attributes: true,
  194. /* 节点内容或节点文本的变动 */
  195. characterData: true,
  196. /* 是否将观察器应用于该节点的所有后代节点 */
  197. subtree: true,
  198. },
  199. });
  200. });
  201. },
  202. /**
  203. * 去除简书拦截其它网址的url并自动跳转
  204. */
  205. jumpRedirect() {
  206. if (window.location.pathname === "/go-wild") {
  207. /* 禁止简书拦截跳转 */
  208. window.stop();
  209. let search = window.location.href.replace(
  210. window.location.origin + "/",
  211. ""
  212. );
  213. search = decodeURIComponent(search);
  214. let newURL = search
  215. .replace(/^go-wild\?ac=2&url=/gi, "")
  216. .replace(/^https:\/\/link.zhihu.com\/\?target\=/gi, "");
  217. window.location.href = newURL;
  218. }
  219. },
  220. /**
  221. * 屏蔽相关文章
  222. */
  223. shieldRelatedArticles() {
  224. log.success("屏蔽相关文章");
  225. GM_addStyle(`
  226. div[role="main"] > div > section:nth-child(2){
  227. display: none !important;
  228. }
  229. `);
  230. },
  231. /**
  232. * 屏蔽评论区
  233. */
  234. shieldUserComments() {
  235. log.success("屏蔽评论区");
  236. GM_addStyle(`
  237. div#note-page-comment{
  238. display: none !important;
  239. }
  240. `);
  241. },
  242. /**
  243. * 屏蔽底部推荐阅读
  244. */
  245. shieldRecommendedReading() {
  246. log.success("屏蔽底部推荐阅读");
  247. GM_addStyle(`
  248. div[role="main"] > div > section:last-child{
  249. display: none !important;
  250. }
  251. `);
  252. },
  253. run() {
  254. this.addCSS();
  255. if (PopsPanel.getValue("JianShuAutoJumpRedirect_PC")) {
  256. Optimization.jianshu.PC.jumpRedirect();
  257. }
  258. if (PopsPanel.getValue("JianShuRemoveClipboardHijacking")) {
  259. this.removeClipboardHijacking();
  260. }
  261. if (PopsPanel.getValue("JianShuAutoExpandFullText")) {
  262. this.autoExpandFullText();
  263. }
  264. if (PopsPanel.getValue("JianShuArticleCenter")) {
  265. this.articleCenter();
  266. }
  267. if (PopsPanel.getValue("JianShuShieldRelatedArticles")) {
  268. this.shieldRelatedArticles();
  269. }
  270. if (PopsPanel.getValue("JianShuShieldUserComments")) {
  271. this.shieldUserComments();
  272. }
  273. if (PopsPanel.getValue("JianShuShieldRecommendedReading")) {
  274. this.shieldRecommendedReading();
  275. }
  276. },
  277. },
  278. Mobile: {
  279. addCSS() {
  280. Optimization.jianshu.PC.addCSS();
  281. },
  282. /**
  283. * 手机-屏蔽底部推荐阅读
  284. */
  285. removeFooterRecommendRead() {
  286. log.success("屏蔽底部推荐阅读");
  287. GM_addStyle(`
  288. #recommended-notes{
  289. display: none !important;
  290. }`);
  291. },
  292. /**
  293. * 处理原型
  294. */
  295. handlePrototype() {
  296. log.success("处理原型添加script标签");
  297. let originalAppendChild = Node.prototype.appendChild;
  298. Node.prototype.appendChild = function (element) {
  299. /* 允许添加的元素localName */
  300. let allowElementLocalNameList = ["img"];
  301. /* 不允许script标签加载包括jianshu.io的js资源,会让简书跳到广告页面 */
  302. if (
  303. element.src &&
  304. !element.src.includes("jianshu.io") &&
  305. !allowElementLocalNameList.includes(element.localName)
  306. ) {
  307. log.success(["禁止添加的元素", element]);
  308. return null;
  309. } else {
  310. return originalAppendChild.call(this, element);
  311. }
  312. };
  313. },
  314. /**
  315. * 屏蔽评论区
  316. */
  317. shieldUserComments() {
  318. log.success("屏蔽评论区");
  319. GM_addStyle(`
  320. #comment-main{
  321. display: none !important;
  322. }
  323. `);
  324. },
  325. run() {
  326. this.addCSS();
  327. if (PopsPanel.getValue("JianShuAutoJumpRedirect_Mobile")) {
  328. Optimization.jianshu.PC.jumpRedirect();
  329. }
  330. if (PopsPanel.getValue("JianShuHijackSchemeScriptLabel_Mobile")) {
  331. this.handlePrototype();
  332. }
  333. if (PopsPanel.getValue("JianShuRemoveClipboardHijacking_Mobile")) {
  334. Optimization.jianshu.PC.removeClipboardHijacking();
  335. }
  336.  
  337. if (PopsPanel.getValue("JianShuAutoExpandFullText_Mobile")) {
  338. Optimization.jianshu.PC.autoExpandFullText();
  339. }
  340. if (PopsPanel.getValue("JianShuremoveFooterRecommendRead")) {
  341. this.removeFooterRecommendRead();
  342. }
  343. if (PopsPanel.getValue("JianShuShieldUserCommentsMobile")) {
  344. this.shieldUserComments();
  345. }
  346. },
  347. },
  348. },
  349. };
  350.  
  351. /**
  352. * 配置面板
  353. */
  354. const PopsPanel = {
  355. /**
  356. * 本地存储的总键名
  357. */
  358. key: "GM_Panel",
  359. /**
  360. * 属性attributes的data-key
  361. */
  362. attributeDataKey_Name: "data-key",
  363. /**
  364. * 属性attributes的data-default-value
  365. */
  366. attributeDataDefaultValue_Name: "data-default-value",
  367. /**
  368. * 初始化菜单
  369. */
  370. initMenu() {
  371. this.initLocalDefaultValue();
  372. if (unsafeWindow.top !== unsafeWindow.self) {
  373. return;
  374. }
  375. GM_Menu.add([
  376. {
  377. key: "show_pops_panel_setting",
  378. text: "⚙ 设置",
  379. autoReload: false,
  380. isStoreValue: false,
  381. showText(text) {
  382. return text;
  383. },
  384. callback: () => {
  385. this.showPanel();
  386. },
  387. },
  388. ]);
  389. },
  390. /**
  391. * 初始化本地设置默认的值
  392. */
  393. initLocalDefaultValue() {
  394. let content = this.getContent();
  395. content.forEach((item) => {
  396. if (!item["forms"]) {
  397. return;
  398. }
  399. item.forms.forEach((__item__) => {
  400. if (__item__.forms) {
  401. __item__.forms.forEach((containerItem) => {
  402. if (!containerItem.attributes) {
  403. return;
  404. }
  405. let key = containerItem.attributes[this.attributeDataKey_Name];
  406. let defaultValue =
  407. containerItem.attributes[this.attributeDataDefaultValue_Name];
  408. if (this.getValue(key) == null) {
  409. this.setValue(key, defaultValue);
  410. }
  411. });
  412. } else {
  413. }
  414. });
  415. });
  416. },
  417. /**
  418. * 设置值
  419. * @param {string} key 键
  420. * @param {any} value 值
  421. */
  422. setValue(key, value) {
  423. let localValue = GM_getValue(this.key, {});
  424. localValue[key] = value;
  425. GM_setValue(this.key, localValue);
  426. },
  427. /**
  428. * 获取值
  429. * @param {string} key 键
  430. * @param {any} defaultValue 默认值
  431. * @returns {any}
  432. */
  433. getValue(key, defaultValue) {
  434. let localValue = GM_getValue(this.key, {});
  435. return localValue[key] ?? defaultValue;
  436. },
  437. /**
  438. * 删除值
  439. * @param {string} key 键
  440. */
  441. deleteValue(key) {
  442. let localValue = GM_getValue(this.key, {});
  443. delete localValue[key];
  444. GM_setValue(this.key, localValue);
  445. },
  446. /**
  447. * 显示设置面板
  448. */
  449. showPanel() {
  450. pops.panel({
  451. title: {
  452. text: `${GM_info?.script?.name || "简书优化"}-设置`,
  453. position: "center",
  454. },
  455. content: this.getContent(),
  456. mask: {
  457. enable: true,
  458. clickEvent: {
  459. toClose: true,
  460. },
  461. },
  462. width: pops.isPhone() ? "92vw" : "800px",
  463. height: pops.isPhone() ? "80vh" : "600px",
  464. only: true,
  465. drag: true,
  466. });
  467. },
  468. /**
  469. * 获取按钮配置
  470. * @param {string} text 文字
  471. * @param {string} key 键
  472. * @param {boolean} defaultValue 默认值
  473. * @param {?(event:Event,value: boolean)=>boolean} _callback_ 点击回调
  474. * @param {string|undefined} description 描述
  475. */
  476. getSwtichDetail(text, key, defaultValue, _callback_, description) {
  477. /**
  478. * @type {PopsPanelSwitchDetails}
  479. */
  480. let result = {
  481. text: text,
  482. type: "switch",
  483. description: description,
  484. attributes: {},
  485. getValue() {
  486. return Boolean(PopsPanel.getValue(key, defaultValue));
  487. },
  488. callback(event, value) {
  489. log.success(`${value ? "开启" : "关闭"} ${text}`);
  490. if (typeof _callback_ === "function") {
  491. if (_callback_(event, value)) {
  492. return;
  493. }
  494. }
  495. PopsPanel.setValue(key, value);
  496. },
  497. };
  498. result.attributes[this.attributeDataKey_Name] = key;
  499. result.attributes[this.attributeDataDefaultValue_Name] =
  500. Boolean(defaultValue);
  501. return result;
  502. },
  503. /**
  504. * 获取配置内容
  505. */
  506. getContent() {
  507. return [
  508. {
  509. id: "jianshu-panel-config-pc",
  510. title: "桌面端",
  511. forms: [
  512. {
  513. text: "屏蔽",
  514. type: "forms",
  515. forms: [
  516. PopsPanel.getSwtichDetail(
  517. "【屏蔽】底部推荐阅读",
  518. "JianShuShieldRecommendedReading",
  519. false
  520. ),
  521. PopsPanel.getSwtichDetail(
  522. "【屏蔽】评论区",
  523. "JianShuShieldUserComments",
  524. false
  525. ),
  526. PopsPanel.getSwtichDetail(
  527. "【屏蔽】相关文章",
  528. "JianShuShieldRelatedArticles",
  529. false
  530. ),
  531. ],
  532. },
  533. {
  534. text: "功能",
  535. type: "forms",
  536. forms: [
  537. PopsPanel.getSwtichDetail(
  538. "全文居中",
  539. "JianShuArticleCenter",
  540. true
  541. ),
  542. PopsPanel.getSwtichDetail(
  543. "自动展开全文",
  544. "JianShuAutoExpandFullText",
  545. true
  546. ),
  547. PopsPanel.getSwtichDetail(
  548. "重定向链接",
  549. "JianShuAutoJumpRedirect_PC",
  550. true,
  551. undefined,
  552. "自动跳转简书拦截的Url链接"
  553. ),
  554. ],
  555. },
  556. {
  557. text: "劫持/拦截",
  558. type: "forms",
  559. forms: [
  560. PopsPanel.getSwtichDetail(
  561. "拦截-剪贴板",
  562. "JianShuRemoveClipboardHijacking",
  563. true,
  564. undefined,
  565. "去除禁止复制"
  566. ),
  567. ],
  568. },
  569. ],
  570. },
  571. {
  572. id: "jianshu-panel-config-mobile",
  573. title: "移动端",
  574. forms: [
  575. {
  576. text: "屏蔽",
  577. type: "forms",
  578. forms: [
  579. PopsPanel.getSwtichDetail(
  580. "【屏蔽】底部推荐阅读",
  581. "JianShuremoveFooterRecommendRead",
  582. false
  583. ),
  584. PopsPanel.getSwtichDetail(
  585. "【屏蔽】评论区",
  586. "JianShuShieldUserCommentsMobile",
  587. false
  588. ),
  589. ],
  590. },
  591. {
  592. text: "功能",
  593. type: "forms",
  594. forms: [
  595. PopsPanel.getSwtichDetail(
  596. "自动展开全文",
  597. "JianShuAutoExpandFullText_Mobile",
  598. true
  599. ),
  600. PopsPanel.getSwtichDetail(
  601. "重定向链接",
  602. "JianShuAutoJumpRedirect_Mobile",
  603. true,
  604. undefined,
  605. "自动跳转简书拦截的Url链接"
  606. ),
  607. ],
  608. },
  609. {
  610. text: "劫持/拦截",
  611. type: "forms",
  612. forms: [
  613. PopsPanel.getSwtichDetail(
  614. "拦截-剪贴板",
  615. "JianShuRemoveClipboardHijacking_Mobile",
  616. true,
  617. undefined,
  618. "去除禁止复制"
  619. ),
  620. PopsPanel.getSwtichDetail(
  621. "劫持-唤醒/跳转App",
  622. "JianShuHijackSchemeScriptLabel_Mobile",
  623. true,
  624. undefined,
  625. "去除简书唤醒调用App"
  626. ),
  627. ],
  628. },
  629. ],
  630. },
  631. ];
  632. },
  633. };
  634.  
  635. PopsPanel.initMenu();
  636.  
  637. Optimization.jianshu.init();
  638. })();

QingJ © 2025

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