// ==UserScript== // @name 小黑盒全能净化引擎 (终极版 V4.0) // @namespace https://heybox.com/ // @version 4.0.0 // @description 全栈式小黑盒论坛内容过滤:支持帖子过滤(关键词/0赞0评)、评论区净化(插眼/关键词/纯表情/楼中楼),完美适配单页应用。 // @author 架构师AI & kun // @match https://www.xiaoheihe.cn/app/bbs/* // @icon https://www.xiaoheihe.cn/favicon.ico // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/554075/%E5%B0%8F%E9%BB%91%E7%9B%92%E5%85%A8%E8%83%BD%E5%87%80%E5%8C%96%E5%BC%95%E6%93%8E%20%28%E7%BB%88%E6%9E%81%E7%89%88%20V40%29.user.js // @updateURL https://update.greasyfork.icu/scripts/554075/%E5%B0%8F%E9%BB%91%E7%9B%92%E5%85%A8%E8%83%BD%E5%87%80%E5%8C%96%E5%BC%95%E6%93%8E%20%28%E7%BB%88%E6%9E%81%E7%89%88%20V40%29.meta.js // ==/UserScript== (function () { 'use strict'; // ========================================== // 1. 配置中心 (自动持久化) // ========================================== const Config = { data: { postKeywords: [], // 帖子屏蔽词 commentKeywords: ["副屏", "插眼", "cy", "攻略"], // 评论屏蔽词 blockZeroComment: false, blockZeroLike: false, blockPureEmoji: false, // 新增:屏蔽纯表情/空评论 hideMode: 'remove', // 'remove' 完全隐藏, 'dim' 虚化半透明 stats: { postsBlocked: 0, commentsBlocked: 0 } }, load() { const saved = GM_getValue('hb_ultimate_config_v4'); if (saved) { this.data = { ...this.data, ...JSON.parse(saved) }; } }, save() { GM_setValue('hb_ultimate_config_v4', JSON.stringify(this.data)); UI.updateStats(); } }; // ========================================== // 2. 核心引擎 (双擎驱动 + SPA适配) // ========================================== const Engine = { debounceTimer: null, run() { this.filterPosts(); this.filterComments(); }, // 模块A:帖子列表净化 filterPosts() { const posts = document.querySelectorAll('a.hb-cpt__bbs-content'); let newlyBlocked = 0; posts.forEach(post => { if (post.dataset.hbProcessed === Config.data.hideMode) return; const title = post.querySelector('.bbs-content__title')?.innerText || ''; const content = post.querySelector('.bbs-content__content')?.innerText || ''; const text = (title + content).toLowerCase(); const commentEl = post.querySelector('.content-list__comment-cnt'); const likeEl = post.querySelector('.content-list__like-cnt'); const comments = commentEl ? parseInt(commentEl.textContent.replace(/[^0-9]/g, '') || '0', 10) : -1; const likes = likeEl ? parseInt(likeEl.textContent.replace(/[^0-9]/g, '') || '0', 10) : -1; let shouldBlock = false; if (Config.data.postKeywords.length > 0) { shouldBlock = Config.data.postKeywords.some(k => text.includes(k.toLowerCase())); } if (!shouldBlock && Config.data.blockZeroComment && comments === 0) shouldBlock = true; if (!shouldBlock && Config.data.blockZeroLike && likes === 0) shouldBlock = true; if (shouldBlock) { if (!post.dataset.hbBlocked) newlyBlocked++; post.dataset.hbBlocked = 'true'; post.dataset.hbProcessed = Config.data.hideMode; if (Config.data.hideMode === 'remove') { post.style.display = 'none'; } else { post.style.display = ''; post.style.opacity = '0.1'; post.style.pointerEvents = 'none'; } } else { post.dataset.hbBlocked = 'false'; post.dataset.hbProcessed = ''; post.style.display = ''; post.style.opacity = '1'; post.style.pointerEvents = 'auto'; } }); if (newlyBlocked > 0) { Config.data.stats.postsBlocked += newlyBlocked; Config.save(); } }, // 模块B:评论区净化 (主评论 + 楼中楼 + 纯表情) filterComments() { let newlyBlocked = 0; const selectors = '.comment-item__content, .children-item__comment-content'; document.querySelectorAll(selectors).forEach(content => { // 向上寻找该评论的最外层容器(兼容顶层评论和楼中楼) const commentWrapper = content.closest('.link-comment__comment-item') || content.closest('.comment-children-item'); if (!commentWrapper || commentWrapper.dataset.hbProcessed === 'true') return; const text = (content.innerText || "").trim(); const hasText = text.length > 0; let shouldBlock = false; // 规则1:官方插眼类 (.cy) if (content.classList.contains('cy')) { shouldBlock = true; } // 规则2:自定义关键词匹配 if (!shouldBlock && Config.data.commentKeywords.length > 0) { shouldBlock = Config.data.commentKeywords.some(k => text.toLowerCase().includes(k.toLowerCase())); } // 规则3:纯表情/空评论 (没有文字的评论,通常只包含表情或完全为空) if (!shouldBlock && Config.data.blockPureEmoji && !hasText) { shouldBlock = true; } if (shouldBlock) { commentWrapper.style.display = 'none'; commentWrapper.dataset.hbProcessed = 'true'; newlyBlocked++; } }); if (newlyBlocked > 0) { Config.data.stats.commentsBlocked += newlyBlocked; Config.save(); } }, observe() { const observer = new MutationObserver(() => { clearTimeout(this.debounceTimer); this.debounceTimer = setTimeout(() => this.run(), 300); }); // 监听整个 body 应对单页应用(SPA)的无刷新路由跳转 observer.observe(document.body, { childList: true, subtree: true }); }, refreshAll() { // 清除帖子状态并恢复显示 document.querySelectorAll('a.hb-cpt__bbs-content').forEach(p => { p.dataset.hbProcessed = ''; p.style.display = ''; p.style.opacity = '1'; p.style.pointerEvents = 'auto'; }); // 清除评论状态并恢复显示 document.querySelectorAll('.link-comment__comment-item, .comment-children-item').forEach(c => { c.dataset.hbProcessed = ''; c.style.display = ''; }); // 重新扫描 this.run(); } }; // ========================================== // 3. UI控制器 (Shadow DOM 隔离) // ========================================== const UI = { shadowRoot: null, init() { const host = document.createElement('div'); host.id = 'hb-ultimate-host'; document.body.appendChild(host); this.shadowRoot = host.attachShadow({ mode: 'open' }); this.render(); this.bindEvents(); this.makeDraggable(); GM_registerMenuCommand("⚙️ 净化设置", () => { const panel = this.shadowRoot.querySelector('#panel'); panel.style.display = panel.style.display === 'none' ? 'flex' : 'none'; }); }, render() { const style = ` `; const getTagsHTML = (arr, type) => arr.map(k => `
${k} ×
`).join(''); const html = ` ${style}

终极净化引擎 V4.0

列表帖子过滤
${getTagsHTML(Config.data.postKeywords, 'post')}
屏蔽 0 评论帖子
屏蔽 0 点赞帖子
列表处理模式
评论区过滤 (含楼中楼)
${getTagsHTML(Config.data.commentKeywords, 'comment')}
屏蔽纯表情/空评论
已净化:帖子 ${Config.data.stats.postsBlocked} | 评论 ${Config.data.stats.commentsBlocked}
`; this.shadowRoot.innerHTML = html; }, bindEvents() { const root = this.shadowRoot; root.getElementById('hide-panel').onclick = () => { root.getElementById('panel').style.display = 'none'; root.getElementById('trigger').style.display = 'flex'; }; root.getElementById('trigger').onclick = () => { root.getElementById('panel').style.display = 'flex'; root.getElementById('trigger').style.display = 'none'; }; // 关键词输入处理 const handleInput = (inputId, targetArray) => { const input = root.getElementById(inputId); input.addEventListener('keypress', (e) => { if (e.key === 'Enter' && input.value.trim()) { const word = input.value.trim(); if (!Config.data[targetArray].includes(word)) { Config.data[targetArray].push(word); Config.save(); this.refreshTags(); Engine.refreshAll(); } input.value = ''; } }); }; handleInput('kw-post-input', 'postKeywords'); handleInput('kw-comment-input', 'commentKeywords'); // 关键词删除 const handleTagRemove = (e) => { if (e.target.tagName === 'SPAN') { const word = e.target.dataset.word; const type = e.target.dataset.type; const targetArray = type === 'post' ? 'postKeywords' : 'commentKeywords'; Config.data[targetArray] = Config.data[targetArray].filter(k => k !== word); Config.save(); this.refreshTags(); Engine.refreshAll(); } }; root.getElementById('kw-post-list').addEventListener('click', handleTagRemove); root.getElementById('kw-comment-list').addEventListener('click', handleTagRemove); // 开关状态绑定 const bindSwitch = (id, key) => { root.getElementById(id).onchange = (e) => { Config.data[key] = e.target.checked; Config.save(); Engine.refreshAll(); }; }; bindSwitch('chk-0-comment', 'blockZeroComment'); bindSwitch('chk-0-like', 'blockZeroLike'); bindSwitch('chk-pure-emoji', 'blockPureEmoji'); // 模式选择 root.getElementById('sel-mode').onchange = (e) => { Config.data.hideMode = e.target.value; Config.save(); Engine.refreshAll(); }; }, refreshTags() { const getTagsHTML = (arr, type) => arr.map(k => `
${k} ×
`).join(''); this.shadowRoot.getElementById('kw-post-list').innerHTML = getTagsHTML(Config.data.postKeywords, 'post'); this.shadowRoot.getElementById('kw-comment-list').innerHTML = getTagsHTML(Config.data.commentKeywords, 'comment'); }, updateStats() { if (!this.shadowRoot) return; const pStat = this.shadowRoot.getElementById('stat-posts'); const cStat = this.shadowRoot.getElementById('stat-comments'); if (pStat) pStat.innerText = Config.data.stats.postsBlocked; if (cStat) cStat.innerText = Config.data.stats.commentsBlocked; }, makeDraggable() { const panel = this.shadowRoot.getElementById('panel'); const header = this.shadowRoot.querySelector('.header'); let isDragging = false, currentX, currentY, initialX, initialY, xOffset = 0, yOffset = 0; header.addEventListener('mousedown', (e) => { initialX = e.clientX - xOffset; initialY = e.clientY - yOffset; if (e.target === header || e.target.tagName === 'H3') isDragging = true; }); window.addEventListener('mouseup', () => { initialX = currentX; initialY = currentY; isDragging = false; }); window.addEventListener('mousemove', (e) => { if (isDragging) { e.preventDefault(); currentX = e.clientX - initialX; currentY = e.clientY - initialY; xOffset = currentX; yOffset = currentY; panel.style.transform = `translate3d(${currentX}px, ${currentY}px, 0)`; } }); } }; // ========================================== // 4. 启动引导 // ========================================== const Boot = () => { Config.load(); UI.init(); Engine.run(); Engine.observe(); }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', Boot); } else { Boot(); } })();