您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
针对微信公众号文章的增强脚本
// ==UserScript== // @name WeChat Plus // @namespace http://tampermonkey.net/ // @version 0.1.0 // @description 针对微信公众号文章的增强脚本 // @author PRO-2684 // @match https://mp.weixin.qq.com/s/* // @run-at document-start // @icon https://res.wx.qq.com/a/wx_fed/assets/res/MjliNWVm.svg // @license gpl-3.0 // @grant unsafeWindow // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_addValueChangeListener // @require https://github.com/PRO-2684/GM_config/releases/download/v1.2.1/config.min.js#md5=525526b8f0b6b8606cedf08c651163c2 // ==/UserScript== (function () { 'use strict'; const { name, version } = GM_info.script; const idPrefix = "wechat-plus-"; const $ = document.querySelector.bind(document); const debug = console.debug.bind(console, `[${name}@${version}]`); const error = console.error.bind(console, `[${name}@${version}]`); const configDesc = { $default: { autoClose: false, }, viewCover: { name: "🖼️ 查看封面", title: "在新标签页中打开封面", type: "action", }, showSummary: { name: "📄 显示摘要", type: "bool", }, allowCopy: { name: "📋 允许复制", title: "允许复制所有内容", type: "bool", }, hideBottomBar: { name: "⬇️ 隐藏底栏", title: "隐藏毫无作用的底栏", type: "bool", }, blockReport: { name: "🚫 屏蔽上报*", title: "屏蔽信息上报,避免隐私泄露,需要刷新页面生效", type: "bool", }, }; const config = new GM_config(configDesc); // Helper functions /** * Resolves when the document is ready. */ async function onReady() { return new Promise((resolve) => { if (document.readyState === "complete") { resolve(); } else { document.addEventListener("DOMContentLoaded", () => { resolve(); }, { once: true }); } }); } /** * Toggles the given style on or off. */ function toggleStyle(id, toggle) { const existing = document.getElementById(idPrefix + id); if (existing && !toggle) { existing.remove(); } else if (!existing && toggle) { const styleElement = document.createElement("style"); styleElement.id = idPrefix + id; styleElement.textContent = styles[id]; document.head.appendChild(styleElement); } } // Main functions function viewCover() { const meta = $("meta[property='og:image']"); const url = meta?.content; if (url) { window.open(url, "_blank"); } else { alert("Cannot find cover image URL."); } } function showSummary(show) { const block = $("#meta_content"); if (!block) { error("Cannot find meta content block."); return; } const summary = block.querySelector("#summary"); if (summary && !show) { summary.remove(); } else if (!summary && show) { const meta = $("meta[name='description']"); const description = meta?.content; if (!description) { error("Cannot find summary description."); return; } const summary = document.createElement("span"); summary.id = "summary"; summary.style.display = "block"; summary.style.borderLeft = "0.2em solid"; summary.style.paddingLeft = "0.5em"; summary.classList.add("rich_media_meta", "rich_media_meta_text"); summary.textContent = description; block.appendChild(summary); } } function allowCopy(allow) { const body = document.body; body.classList.toggle("use-femenu", !allow); } const hideBottomBar = "#unlogin_bottom_bar { display: none !important; }" + "body#activity-detail { padding-bottom: 0 !important; }"; function blockReport() { function shouldBlock(url) { const blockList = new Set([ // Additional info, like albums, etc. // "mp.weixin.qq.com/mp/getappmsgext", // CSP report, can't be blocked by UserScript - Use [uBlock Origin](https://github.com/gorhill/uBlock) to block it // "mp.weixin.qq.com/mp/fereport", // Will return error anyway (errmsg: "no session") "mp.weixin.qq.com/mp/appmsg_comment", "mp.weixin.qq.com/mp/relatedsearchword", "mp.weixin.qq.com/mp/getbizbanner", // Information collection "mp.weixin.qq.com/mp/getappmsgad", "mp.weixin.qq.com/mp/jsmonitor", "mp.weixin.qq.com/mp/wapcommreport", "mp.weixin.qq.com/mp/appmsgreport", "badjs.weixinbridge.com/badjs", "badjs.weixinbridge.com/report", "open.weixin.qq.com/pcopensdk/report", ]); url = new URL(url, location.href); const identifier = url.hostname + url.pathname; return blockList.has(identifier); } // Overwrite `XMLHttpRequest` const originalOpen = unsafeWindow.XMLHttpRequest.prototype.open; unsafeWindow.XMLHttpRequest.prototype.open = function (...args) { const url = args[1]; if (shouldBlock(url)) { debug("Blocked opening:", url); this._url = url; } else { return originalOpen.apply(this, args); } } const originalSet = unsafeWindow.XMLHttpRequest.prototype.setRequestHeader; unsafeWindow.XMLHttpRequest.prototype.setRequestHeader = function (...args) { if (this._url) { debug("Blocked setting header:", this._url, ...args); } else { return originalSet.apply(this, args); } } const originalSend = unsafeWindow.XMLHttpRequest.prototype.send; unsafeWindow.XMLHttpRequest.prototype.send = function (...args) { if (this._url) { debug("Blocked sending:", this._url, ...args); } else { return originalSend.apply(this, args); } } // Filter setting `src` of images const { get, set } = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, "src"); Object.defineProperty(HTMLImageElement.prototype, "src", { get() { return get.call(this); }, set(url) { if (shouldBlock(url)) { debug("Blocked image url:", url); return url; } else { return set.call(this, url); } }, }); } // Once: Functions that are called once when the script is loaded. if (config.get("blockReport")) { blockReport(); } // Actions: Functions that are called when the user clicks on it. const actions = { viewCover, }; config.addEventListener("get", (e) => { const action = actions[e.detail.prop]; if (action) { action(); } }); // Callbacks: Functions that are called when the config is changed. const callbacks = { showSummary, allowCopy, }; onReady().then(() => { for (const [prop, callback] of Object.entries(callbacks)) { callback(config.get(prop)); } }); // Styles: CSS styles that can be toggled on and off. const styles = { hideBottomBar, }; for (const prop of Object.keys(styles)) { toggleStyle(prop, config.get(prop)); } config.addEventListener("set", (e) => { const callback = callbacks[e.detail.prop]; if (callback) { onReady().then(() => { callback(e.detail.after); }); } if (e.detail.prop in styles) { toggleStyle(e.detail.prop, e.detail.after); } }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址