// ==UserScript== // @name 简书优化 // @icon https://www.jianshu.com/favicon.ico // @namespace https://greasyfork.org/zh-CN/scripts/485483 // @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues // @version 2024.4.24 // @license MIT // @description 支持手机端和PC端,屏蔽广告,优化浏览体验,自动跳转拦截的URL // @author WhiteSevs // @match *://*.jianshu.com/* // @match *://*.jianshu.io/* // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_info // @grant unsafeWindow // @run-at document-start // @require https://update.greasyfork.icu/scripts/456485/1360571/pops.js // @require https://update.greasyfork.icu/scripts/455186/1365298/WhiteSevsUtils.js // @require https://update.greasyfork.icu/scripts/465772/1360574/DOMUtils.js // @downloadURL none // ==/UserScript== (function () { if (typeof unsafeWindow === "undefined") { unsafeWindow = globalThis; } /** * @type {import("../库/pops")} */ const pops = window.pops; /** * @type {import("../库/Utils")} */ const utils = window.Utils.noConflict(); /** * @type {import("../库/DOMUtils")} */ const DOMUtils = window.DOMUtils.noConflict(); const log = new utils.Log(GM_info, unsafeWindow.console || console); log.config({ autoClearConsole: false, }); const GM_addStyle = utils.addStyle; /** * 菜单 */ const GM_Menu = new utils.GM_Menu({ GM_getValue, GM_setValue, GM_registerMenuCommand, GM_unregisterMenuCommand, }); /** * 移除元素(未出现也可以等待出现) * @param {string} selectorText 元素选择器 */ const waitForElementToRemove = function (selectorText = "") { utils.waitNodeList(selectorText).then((nodeList) => { nodeList.forEach((item) => { item.remove(); }); }); }; const Optimization = { jianshu: { /** * 函数入口 */ init() { if (utils.isPhone()) { log.success("简书-移动端"); this.Mobile.run(); } else { log.success("简书-桌面端"); this.PC.run(); } }, PC: { /** * 添加屏蔽CSS */ addCSS() { GM_addStyle(` .download-app-guidance, .call-app-btn, .collapse-tips, .note-graceful-button, .app-open, .header-wrap, .recommend-wrap.recommend-ad, .call-app-Ad-bottom, #recommended-notes p.top-title span.more, #homepage .modal, button.index_call-app-btn, span.note__flow__download, .download-guide, #footer, .comment-open-app-btn-wrap, .nav.navbar-nav + div, .self-flow-ad, #free-reward-panel, div[id*='AdFive'], #index-aside-download-qrbox, .baidu-app-download-2eIkf_1, /* 底部的"小礼物走一走,来简书关注我"、赞赏支持和更多精彩内容,就在简书APP */ div[role="main"] > div > section:first-child > div:nth-last-child(2), /* 它的内部是script标签,可能影响部分评论之间的高度问题 */ div.adad_container{ display:none !important; } body.reader-day-mode.normal-size { overflow: auto !important; } .collapse-free-content{ height:auto !important; } .copyright{ color:#000 !important; } #note-show .content .show-content-free .collapse-free-content:after{ background-image:none !important; } footer > div > div{ justify-content: center; } /* 修复底部最后编辑于:。。。在某些套壳浏览器上的错位问题 */ #note-show .content .show-content-free .note-meta-time{ margin-top: 0px !important; } `); }, /** * 全文居中 */ articleCenter() { log.success("全文居中"); GM_addStyle(` div[role=main] aside, div._3Pnjry{ display: none !important; } div._gp-ck{ width: 100% !important; }`); waitForElementToRemove("div[role=main] aside"); waitForElementToRemove("div._3Pnjry"); utils.waitNodeList("div._gp-ck").then((nodeList) => { nodeList.forEach((item) => { item.style["width"] = "100%"; }); }); }, /** * 去除剪贴板劫持 */ removeClipboardHijacking() { log.success("去除剪贴板劫持"); const stopNativePropagation = (event) => { event.stopPropagation(); }; window.addEventListener("copy", stopNativePropagation, true); document.addEventListener("copy", stopNativePropagation, true); }, /** * 自动展开全文 */ autoExpandFullText() { utils .waitNode(`div#homepage div[class*="dialog-"]`) .then((element) => { element.style["visibility"] = "hidden"; utils.mutationObserver(element, { callback: (mutations) => { if (mutations.length == 0) { return; } if (mutations.target.style["display"] != "none") { log.success("自动展开全文"); document .querySelector( 'div#homepage div[class*="dialog-"] .cancel' ) ?.click(); } }, config: { /* 子节点的变动(新增、删除或者更改) */ childList: false, /* 属性的变动 */ attributes: true, /* 节点内容或节点文本的变动 */ characterData: true, /* 是否将观察器应用于该节点的所有后代节点 */ subtree: true, }, }); }); }, /** * 去除简书拦截其它网址的url并自动跳转 */ jumpRedirect() { if (window.location.pathname === "/go-wild") { /* 禁止简书拦截跳转 */ window.stop(); let search = window.location.href.replace( window.location.origin + "/", "" ); search = decodeURIComponent(search); let newURL = search .replace(/^go-wild\?ac=2&url=/gi, "") .replace(/^https:\/\/link.zhihu.com\/\?target\=/gi, ""); window.location.href = newURL; } }, /** * 屏蔽相关文章 */ shieldRelatedArticles() { log.success("屏蔽相关文章"); GM_addStyle(` div[role="main"] > div > section:nth-child(2){ display: none !important; } `); }, /** * 【屏蔽】客户端弹窗 */ shieldClientDialog() { GM_addStyle(` div:has(>div[class*="-mask"]:not([class*="-mask-hidden"]) + div[tabindex="-1"][role="dialog"]){ display: none !important; } `); utils .waitNode( `div[class*="-mask"]:not([class*="-mask-hidden"]) + div[tabindex="-1"][role="dialog"]` ) .then((element) => { log.info("弹窗出现"); utils .waitPropertyByInterval( element, () => { let react = utils.getReactObj(element); return react?.reactInternalInstance?.return?.return ?.memoizedProps?.onClose; }, 250, 10000 ) .then(() => { let react = utils.getReactObj(element); react.reactInternalInstance.return.return.memoizedProps.onClose( new Event("click") ); log.success("调用函数关闭弹窗"); }); }); }, /** * 屏蔽评论区 */ shieldUserComments() { log.success("屏蔽评论区"); GM_addStyle(` div#note-page-comment{ display: none !important; } `); }, /** * 屏蔽底部推荐阅读 */ shieldRecommendedReading() { log.success("屏蔽底部推荐阅读"); GM_addStyle(` div[role="main"] > div > section:last-child{ display: none !important; } `); }, run() { this.addCSS(); if (PopsPanel.getValue("JianShuAutoJumpRedirect_PC")) { Optimization.jianshu.PC.jumpRedirect(); } if (PopsPanel.getValue("JianShuRemoveClipboardHijacking")) { this.removeClipboardHijacking(); } if (PopsPanel.getValue("JianShuAutoExpandFullText")) { this.autoExpandFullText(); } if (PopsPanel.getValue("JianShuArticleCenter")) { this.articleCenter(); } if (PopsPanel.getValue("JianShuShieldRelatedArticles")) { this.shieldRelatedArticles(); } if (PopsPanel.getValue("jianshu-shieldClientDialog")) { this.shieldClientDialog(); } if (PopsPanel.getValue("JianShuShieldUserComments")) { this.shieldUserComments(); } if (PopsPanel.getValue("JianShuShieldRecommendedReading")) { this.shieldRecommendedReading(); } }, }, Mobile: { addCSS() { Optimization.jianshu.PC.addCSS(); }, /** * 手机-屏蔽底部推荐阅读 */ removeFooterRecommendRead() { log.success("屏蔽底部推荐阅读"); GM_addStyle(` #recommended-notes{ display: none !important; }`); }, /** * 处理原型 */ handlePrototype() { log.success("处理原型添加script标签"); let originalAppendChild = Node.prototype.appendChild; Node.prototype.appendChild = function (element) { /* 允许添加的元素localName */ let allowElementLocalNameList = ["img"]; /* 不允许script标签加载包括jianshu.io的js资源,会让简书跳到广告页面 */ if ( element.src && !element.src.includes("jianshu.io") && !allowElementLocalNameList.includes(element.localName) ) { log.success(["禁止添加的元素", element]); return null; } else { return originalAppendChild.call(this, element); } }; }, /** * 屏蔽评论区 */ shieldUserComments() { log.success("屏蔽评论区"); GM_addStyle(` #comment-main{ display: none !important; } `); }, run() { this.addCSS(); if (PopsPanel.getValue("JianShuAutoJumpRedirect_Mobile")) { Optimization.jianshu.PC.jumpRedirect(); } if (PopsPanel.getValue("JianShuHijackSchemeScriptLabel_Mobile")) { this.handlePrototype(); } if (PopsPanel.getValue("JianShuRemoveClipboardHijacking_Mobile")) { Optimization.jianshu.PC.removeClipboardHijacking(); } if (PopsPanel.getValue("JianShuAutoExpandFullText_Mobile")) { Optimization.jianshu.PC.autoExpandFullText(); } if (PopsPanel.getValue("JianShuremoveFooterRecommendRead")) { this.removeFooterRecommendRead(); } if (PopsPanel.getValue("JianShuShieldUserCommentsMobile")) { this.shieldUserComments(); } }, }, }, }; /** * 配置面板 */ const PopsPanel = { /** * 本地存储的总键名 */ key: "GM_Panel", /** * 属性attributes的data-key */ attributeDataKey_Name: "data-key", /** * 属性attributes的data-default-value */ attributeDataDefaultValue_Name: "data-default-value", /** * 初始化菜单 */ initMenu() { this.initLocalDefaultValue(); if (unsafeWindow.top !== unsafeWindow.self) { return; } GM_Menu.add([ { key: "show_pops_panel_setting", text: "⚙ 设置", autoReload: false, isStoreValue: false, showText(text) { return text; }, callback: () => { this.showPanel(); }, }, ]); }, /** * 初始化本地设置默认的值 */ initLocalDefaultValue() { let content = this.getContent(); content.forEach((item) => { if (!item["forms"]) { return; } item.forms.forEach((__item__) => { if (__item__.forms) { __item__.forms.forEach((containerItem) => { if (!containerItem.attributes) { return; } let key = containerItem.attributes[this.attributeDataKey_Name]; let defaultValue = containerItem.attributes[this.attributeDataDefaultValue_Name]; if (this.getValue(key) == null) { this.setValue(key, defaultValue); } }); } else { } }); }); }, /** * 设置值 * @param {string} key 键 * @param {any} value 值 */ setValue(key, value) { let localValue = GM_getValue(this.key, {}); localValue[key] = value; GM_setValue(this.key, localValue); }, /** * 获取值 * @param {string} key 键 * @param {any} defaultValue 默认值 * @returns {any} */ getValue(key, defaultValue) { let localValue = GM_getValue(this.key, {}); return localValue[key] ?? defaultValue; }, /** * 删除值 * @param {string} key 键 */ deleteValue(key) { let localValue = GM_getValue(this.key, {}); delete localValue[key]; GM_setValue(this.key, localValue); }, /** * 显示设置面板 */ showPanel() { pops.panel({ title: { text: `${GM_info?.script?.name || "简书优化"}-设置`, position: "center", }, content: this.getContent(), mask: { enable: true, clickEvent: { toClose: true, }, }, width: pops.isPhone() ? "92vw" : "800px", height: pops.isPhone() ? "80vh" : "600px", only: true, drag: true, }); }, /** * 获取按钮配置 * @param {string} text 文字 * @param {string} key 键 * @param {boolean} defaultValue 默认值 * @param {?(event:Event,value: boolean)=>boolean} _callback_ 点击回调 * @param {string|undefined} description 描述 */ getSwtichDetail(text, key, defaultValue, _callback_, description) { /** * @type {PopsPanelSwitchDetails} */ let result = { text: text, type: "switch", description: description, attributes: {}, getValue() { return Boolean(PopsPanel.getValue(key, defaultValue)); }, callback(event, value) { log.success(`${value ? "开启" : "关闭"} ${text}`); if (typeof _callback_ === "function") { if (_callback_(event, value)) { return; } } PopsPanel.setValue(key, value); }, }; result.attributes[this.attributeDataKey_Name] = key; result.attributes[this.attributeDataDefaultValue_Name] = Boolean(defaultValue); return result; }, /** * 获取配置内容 */ getContent() { return [ { id: "jianshu-panel-config-pc", title: "桌面端", forms: [ { text: "屏蔽", type: "forms", forms: [ PopsPanel.getSwtichDetail( "【屏蔽】底部推荐阅读", "JianShuShieldRecommendedReading", false ), PopsPanel.getSwtichDetail( "【屏蔽】评论区", "JianShuShieldUserComments", false ), PopsPanel.getSwtichDetail( "【屏蔽】相关文章", "JianShuShieldRelatedArticles", false ), PopsPanel.getSwtichDetail( "【屏蔽】客户端弹窗", "jianshu-shieldClientDialog", false, void 0, "弹出的【扫码安装简书客户端 畅享全文阅读体验】" ), ], }, { text: "功能", type: "forms", forms: [ PopsPanel.getSwtichDetail( "全文居中", "JianShuArticleCenter", true ), PopsPanel.getSwtichDetail( "自动展开全文", "JianShuAutoExpandFullText", true ), PopsPanel.getSwtichDetail( "重定向链接", "JianShuAutoJumpRedirect_PC", true, undefined, "自动跳转简书拦截的Url链接" ), ], }, { text: "劫持/拦截", type: "forms", forms: [ PopsPanel.getSwtichDetail( "拦截-剪贴板", "JianShuRemoveClipboardHijacking", true, undefined, "去除禁止复制" ), ], }, ], }, { id: "jianshu-panel-config-mobile", title: "移动端", forms: [ { text: "屏蔽", type: "forms", forms: [ PopsPanel.getSwtichDetail( "【屏蔽】底部推荐阅读", "JianShuremoveFooterRecommendRead", false ), PopsPanel.getSwtichDetail( "【屏蔽】评论区", "JianShuShieldUserCommentsMobile", false ), ], }, { text: "功能", type: "forms", forms: [ PopsPanel.getSwtichDetail( "自动展开全文", "JianShuAutoExpandFullText_Mobile", true ), PopsPanel.getSwtichDetail( "重定向链接", "JianShuAutoJumpRedirect_Mobile", true, undefined, "自动跳转简书拦截的Url链接" ), ], }, { text: "劫持/拦截", type: "forms", forms: [ PopsPanel.getSwtichDetail( "拦截-剪贴板", "JianShuRemoveClipboardHijacking_Mobile", true, undefined, "去除禁止复制" ), PopsPanel.getSwtichDetail( "劫持-唤醒/跳转App", "JianShuHijackSchemeScriptLabel_Mobile", true, undefined, "去除简书唤醒调用App" ), ], }, ], }, ]; }, }; PopsPanel.initMenu(); Optimization.jianshu.init(); })();