PEACE AND LOVE,跟恶臭言论说拜拜。
// ==UserScript==
// @name 净化评论区
// @namespace http://tampermonkey.net/
// @version 0.3
// @description PEACE AND LOVE,跟恶臭言论说拜拜。
// @author Young2fun
// @match *://*/*
// @grant none
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAppJREFUaEPVmdFxwjAMhhU6QbmukDkK45QOARmidBxgjqzQoxMU95REnBG2JTsxODxCsPVJ+iXZqWDmnyqn/W/f7ernoz7m3CMLABp+MXC4Gm6gOX/WuxwgWQBe9+2hAljNFmC5bw339nlTZ3FWlkWLBFh+tbvFAo4aURYFkCLIogDQ81DB1s5pKZ+LBwChLBYFcJdCGIo5AaC9Lo+GIIqKQAfg0MH8AQDAJ+biIhCbRhJATE+R5id1J3amkScKIQA+J0klOTuASws+gJSKNhmAL40MwPF3U6/tjcYAxJ4h1CmEBt6NyWQ16wspACkjC24fBeDTAU+jFIDUM0QUgDOHhyjYYkwBkCqXTwtRAN5yysaLsgFcXXlwDwr65ihpuQ0jFKpCj4tAACBU8ooBCKaRRdBFw8AJv6KTXBER4OXUZWgoEnepMpTgh6UQGic1m87Tl/5axVTwjrqgKsUNXVSwxnP2QwHIwy5Dfd73GeoDw3U0c1J8GU0UMQEg9J+BLerDvuXgTdI1oricowYINTFp4CJjXKmHhuO1IwcgYGnt/ACDSMkBCNPNMAZOpA97FJH0xYHUAN5BzuEiqkx0oeudoVjZfamgQUGTtjQXwmoA58GeG2+gCeW1lA7890lFLEaA6jmKvJ9zby7DYo2fvApJaYCiw01v3gukWG3NVfygNKoKSQAkRFWqKcCeUkYxZ0VQhfFdB3ccVUdFQDXEBeYapd3XxybvAx2ApgsbaKYQ8PMAYl3t6SMaAffFLvKjikLkmvxxrfeTAFRaGAMQ+Uo2OgJo25jBLsSmrTz2GkkAWSAiPU8QyQC0gDhiaNIp0fhkDXCbrocU++28YDifWDWcoxuZZhOEoefoXGz/T/uuWbPXZBHQbpbjuX/rEk9PZCmOXwAAAABJRU5ErkJggg==
// @license GPL-3.0 License
// ==/UserScript==
(function () {
'use strict';
// 规则:domain 可以是正则,selectors 为数组(一个站点可能多个选择器)
const RULES = [
{ domain: /baijiahao\.baidu\.com/, selectors: ['#commentModule', '.comment-module'] },
{ domain: /baidu\.com\/s/, selectors: ['#danmuWrapper'] },
{ domain: /qq\.com/, selectors: ['#qqcom-comment', '.comment'] },
{ domain: /haokan\.baidu\.com/, selectors: ['#commentnum'] },
{ domain: /mbd\.baidu\.com\/newspage\//, selectors: ['#commentModule'] },
{ domain: /mbd\.baidu\.com/, selectors: ['#page-comment'] },
// 你可以在这里继续添加规则:{ domain: /example\.com/, selectors: ['#c1', '.c2'] }
];
const rule = RULES.find(r => r.domain.test(location.href));
if (!rule) {
// 没匹配到站点规则则退出(若想在所有站点尝试,可注释掉此 return)
// return;
console.log('[隐藏评论区] 本页面未匹配到规则,仍将尝试泛匹配常见选择器。');
} else {
console.log('[隐藏评论区] 匹配站点规则:', rule.domain, 'selectors:', rule.selectors);
}
// 如果没有匹配规则,使用一组常见的选择器作泛匹配
const fallbackSelectors = [
'#comments', '#comment', '.comments', '.comment-list', '.comment-area',
'.reply-area', '.comment-module', '#commentModule', '#page-comment', '#commentnum',
'#qqcom-comment', '#danmuWrapper'
];
const selectors = (rule && rule.selectors && rule.selectors.length) ? rule.selectors.concat(fallbackSelectors) : fallbackSelectors;
// 注入全局 CSS(尽可能立即生效)
function injectGlobalStyle(selArr) {
try {
const sheet = document.createElement('style');
sheet.setAttribute('data-name', 'hide-comments-style');
const rulesText = selArr.map(s => `${s} { display: none !important; visibility: hidden !important; height: 0 !important; margin: 0 !important; padding: 0 !important; overflow: hidden !important; }`).join('\n');
sheet.textContent = rulesText;
(document.head || document.documentElement).appendChild(sheet);
console.log('[隐藏评论区] 已注入全局 CSS(主文档)');
} catch (e) {
console.warn('[隐藏评论区] 注入全局 CSS 失败:', e);
}
}
// 在给定根节点(document 或 shadow/root)中查找并隐藏选择器
function hideInRoot(root, selArr) {
try {
selArr.forEach(sel => {
const list = (root || document).querySelectorAll(sel);
list.forEach(el => {
if (el) {
if (el.style) {
el.style.setProperty('display', 'none', 'important');
el.style.setProperty('visibility', 'hidden', 'important');
} else {
// 对于一些非元素节点(保险)
el.setAttribute && el.setAttribute('hidden', 'true');
}
console.log('[隐藏评论区] 隐藏元素:', sel, el);
}
});
});
} catch (e) {
console.warn('[隐藏评论区] hideInRoot 错误: ', e);
}
}
// 递归遍历 open shadow roots,尝试在 shadowRoot 中 hide
function traverseShadowAndHide(rootNode, selArr) {
if (!rootNode) return;
const treeWalker = document.createTreeWalker(rootNode, NodeFilter.SHOW_ELEMENT, null, false);
let node;
const visited = new Set();
while ((node = treeWalker.nextNode())) {
// 防止死循环
if (visited.has(node)) break;
visited.add(node);
// 如果节点有 shadowRoot(open),在其中执行 hide
try {
const sr = node.shadowRoot;
if (sr) {
hideInRoot(sr, selArr);
// 继续递归遍历 shadow root 的子节点
traverseShadowAndHide(sr, selArr);
}
} catch (e) {
// 有些 shadowRoot 可能不可访问或 closed
}
}
}
// 处理同源 iframe:注入 CSS 并隐藏其中匹配元素;对跨域 iframe:若 iframe.src 匹配规则域则直接隐藏 iframe 元素
function handleIframes(selArr, domainPatterns) {
const iframes = document.querySelectorAll('iframe');
iframes.forEach(iframe => {
try {
const doc = iframe.contentDocument;
if (doc && doc.head) {
// 在 iframe 中注入样式
const style = doc.createElement('style');
style.textContent = selArr.map(s => `${s} { display: none !important; visibility: hidden !important; height: 0 !important; overflow: hidden !important; }`).join('\n');
doc.head.appendChild(style);
// 直接尝试隐藏
selArr.forEach(s => {
doc.querySelectorAll(s).forEach(el => {
el.style && el.style.setProperty('display', 'none', 'important');
console.log('[隐藏评论区] 在同源 iframe 中隐藏:', s, el, iframe.src);
});
});
} else {
// contentDocument 不可访问 -> 跨域 iframe
const src = iframe.getAttribute('src') || '';
if (domainPatterns && domainPatterns.some(p => p.test(src) || p.test(location.href))) {
// 如果 iframe 的 src 含有目标域名,直接隐藏 iframe 元素本身
iframe.style.setProperty('display', 'none', 'important');
console.log('[隐藏评论区] 隐藏跨域 iframe 元素(通过 src 匹配):', src);
} else {
// 若没有明确匹配,也可以选择隐藏 iframe(注释掉以避免误伤)
// iframe.style.display = 'none';
}
}
} catch (e) {
// 访问跨域 iframe 会抛错
const src = iframe.getAttribute('src') || '';
if (domainPatterns && domainPatterns.some(p => p.test(src) || p.test(location.href))) {
iframe.style.setProperty('display', 'none', 'important');
console.log('[隐藏评论区] 跨域 iframe,已根据 src 隐藏:', src);
} else {
// 无法访问也未匹配,跳过
}
}
});
}
// 主运行逻辑:注入样式 -> 首次隐藏 -> 观察 DOM -> 处理 shadow & iframe -> 周期重试(小次数)
function start() {
injectGlobalStyle(selectors);
hideInRoot(document, selectors);
traverseShadowAndHide(document, selectors);
handleIframes(selectors, RULES.map(r => r.domain));
// MutationObserver 监听后续插入
const observer = new MutationObserver(mutations => {
// 当 DOM 变化时再次尝试隐藏
hideInRoot(document, selectors);
traverseShadowAndHide(document, selectors);
handleIframes(selectors, RULES.map(r => r.domain));
});
if (document.body) {
observer.observe(document.body, { childList: true, subtree: true });
console.log('[隐藏评论区] 已启动 MutationObserver');
} else {
console.warn('[隐藏评论区] document.body 尚未就绪,稍后建立 observer');
window.addEventListener('load', () => {
observer.observe(document.body, { childList: true, subtree: true });
});
}
// 周期性尝试(兼容某些站点在页面运行后很久才加载评论)
let attempts = 0;
const maxAttempts = 12; // 总共尝试约 12 次(每 2s -> 24s)
const intervalId = setInterval(() => {
attempts++;
hideInRoot(document, selectors);
traverseShadowAndHide(document, selectors);
handleIframes(selectors, RULES.map(r => r.domain));
if (attempts >= maxAttempts) {
clearInterval(intervalId);
console.log('[隐藏评论区] 周期重试结束,共尝试次数:', attempts);
}
}, 2000);
}
// 等待页面 load 更稳妥
if (document.readyState === 'complete' || document.readyState === 'interactive') {
start();
} else {
window.addEventListener('DOMContentLoaded', start);
// 以及保险的 load
window.addEventListener('load', start);
}
})();