您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
屏蔽C站和NGA论坛中的指定用户,同时删除签名区块,支持一键屏蔽用户
// ==UserScript== // @name 屏蔽C站和NGA的傻逼-调试 // @namespace http://tampermonkey.net/ // @version 0.4 // @description 屏蔽C站和NGA论坛中的指定用户,同时删除签名区块,支持一键屏蔽用户 // @author forthejiong // @match *://*.chiphell.com/* // @match *://chiphell.com/* // @match *://ngabbs.com/* // @match *://*.nga.cn/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; // 屏蔽用户配置 // 将用户列表作为变量直接定义,GM_getValue的键名使用字符串 const CHIPHELL_BLOCK_KEY = 'chiphellBlockUsers'; const NGA_BLOCK_UIDS_KEY = 'ngaBlockUids'; const NGA_BLOCK_USERNAMES_KEY = 'ngaBlockUsernames'; // 在这里直接添加/删除用户。修改这里保存,可生效。 const defaultChiphellBlockUsers = [ "destroypeter", "kthlon", "normanlu", "YsHaNg", "raoshine", // 在这里添加/删除 Chiphell 用户名,一行一个 "new_user_1", "new_user_2" ]; const defaultNgaBlockUids = [ 64542480, // 在这里添加/删除 NGA 的 UID,一行一个 //建议使用UID避免用户修改名字之类的逃逸,建议手动添加或者把存储器的复制过来 6680916, 10086 ]; const defaultNgaBlockUsernames = [ "张三", // 在这里添加/删除 NGA 的用户名,一行一个。“修改请注意引号和逗号格式” "李四", "王五" ]; // 初始化屏蔽列表:从 Tampermonkey 存储中获取,如果没有则使用默认值 let chiphellBlockUsers = GM_getValue(CHIPHELL_BLOCK_KEY, defaultChiphellBlockUsers); let ngaBlockUids = GM_getValue(NGA_BLOCK_UIDS_KEY, defaultNgaBlockUids).map(uid => Number(uid)); let ngaBlockUsernames = GM_getValue(NGA_BLOCK_USERNAMES_KEY, defaultNgaBlockUsernames); // 从URL中提取UID(兼容相对/绝对URL) function getUidFromUrl(url) { try { const fullUrl = new URL(url, window.location.origin); const uid = fullUrl.searchParams.get('uid'); return uid ? Number(uid) : null; } catch (e) { console.error(`解析UID失败: ${url}`, e); return null; } } // 检查用户是否应被屏蔽(增加类型校验) function shouldHideUser(site, identifier) { if (site === 'chiphell') { return typeof identifier === 'string' && chiphellBlockUsers.includes(identifier); } else if (site === 'nga' && typeof identifier === 'object') { const { uid, username } = identifier; return typeof uid === 'number' && ngaBlockUids.includes(uid) || typeof username === 'string' && ngaBlockUsernames.includes(username); } return false; } // 移除指定的DOM元素(增加安全校验,避免误删核心结构) function removeElement(element, reason) { // 安全校验:排除页面核心容器(根据NGA/Chiphell结构调整) const safeTagNames = ['TR', 'TBODY', 'DIV', 'TABLE']; const forbiddenIds = ['mainContent', 'postList', 'topicList']; const forbiddenClasses = ['forum-main', 'topic-container']; if (!element || !element.parentNode || !safeTagNames.includes(element.tagName) || forbiddenIds.includes(element.id) || Array.from(element.classList).some(cls => forbiddenClasses.includes(cls))) { console.warn(`[元素安全校验] 跳过删除非目标元素: ${element?.id || element?.tagName}`, reason); return false; } element.parentNode.removeChild(element); console.log(`[元素清理] 已移除: ${reason} (元素: ${element.id || element.tagName})`); return true; } // 删除id以postsign开头的div元素(增加选择器精确性) function removePostsignDivs() { // 精确匹配:仅删除class含"postsign"且id以"postsign"开头的div(避免误删其他元素) const postsignDivs = document.querySelectorAll('div[id^="postsign"][class*="postsign"]'); postsignDivs.forEach(div => { removeElement(div, `签名区块 (ID: ${div.id})`); }); } // 屏蔽指定用户的发言(优化选择器,避免重复操作) function hideTargetPosts() { const currentHost = window.location.hostname; // 处理Chiphell论坛(优化选择器,匹配首页和帖子页) if (currentHost.includes('chiphell.com')) { // 1. 处理首页/列表页的帖子(匹配tbody中的帖子行) const threadRows = document.querySelectorAll('tbody[id^="normalthread_"] tr:has(td.by cite a):not([data-processed])'); threadRows.forEach(row => { row.setAttribute('data-processed', 'true'); const userLink = row.querySelector('td.by cite a'); if (!userLink) return; const username = userLink.textContent.trim(); if (shouldHideUser('chiphell', username)) { // 移除整个帖子行(包含标题、作者等信息的整行) removeElement(row, `Chiphell帖子列表 (用户: ${username})`); } }); // 2. 处理帖子详情页的回复(匹配帖子内容容器) const postContainers = document.querySelectorAll('div[id^="post_"]:has(a.xw1[href^="space-uid-"]):not([data-processed])'); postContainers.forEach(container => { container.setAttribute('data-processed', 'true'); const userLink = container.querySelector('a.xw1[href^="space-uid-"]'); if (!userLink) return; const username = userLink.textContent.trim(); if (shouldHideUser('chiphell', username)) { removeElement(container, `Chiphell帖子详情 (用户: ${username}, 容器ID: ${container.id})`); } }); } // 处理NGA论坛(分场景精确匹配,避免误删) else if (currentHost.includes('nga.cn')) { // 1. 处理回复帖(仅匹配.postrow行,标记已处理) const replyUserLinks = document.querySelectorAll('tr.postrow a.author[href*="uid="]:not([data-processed])'); replyUserLinks.forEach(link => { link.setAttribute('data-processed', 'true'); const uid = getUidFromUrl(link.href); const username = link.textContent.trim(); if (uid && shouldHideUser('nga', { uid, username })) { const postContainer = link.closest('tr.postrow'); if (postContainer) { removeElement(postContainer, `NGA回复 (用户: ${username}, UID: ${uid})`); } } }); // 2. 处理主题帖(仅匹配含.c3列的tbody,标记已处理) const topicUserLinks = document.querySelectorAll('tbody td.c3 a.author[href*="uid="]:not([data-processed])'); topicUserLinks.forEach(link => { link.setAttribute('data-processed', 'true'); const uid = getUidFromUrl(link.href); const username = link.textContent.trim(); if (uid && shouldHideUser('nga', { uid, username })) { const topicContainer = link.closest('tbody'); if (topicContainer) { removeElement(topicContainer, `NGA主题帖 (用户: ${username}, UID: ${uid})`); } } }); } } // 添加一键屏蔽按钮(避免重复添加,优化样式) function addBlockButtons() { const currentHost = window.location.hostname; if (!currentHost.includes('nga.cn')) return; // 仅匹配未添加按钮的用户链接 const userLinks = document.querySelectorAll('a.author[href*="uid="]:not([data-has-block-btn])'); userLinks.forEach(link => { link.setAttribute('data-has-block-btn', 'true'); const uid = getUidFromUrl(link.href); if (!uid) return; // 创建屏蔽按钮(避免inline样式冲突,用GM_addStyle) const blockBtn = document.createElement('a'); blockBtn.href = 'javascript:void(0)'; blockBtn.textContent = '屏蔽'; blockBtn.className = 'nga-block-button'; blockBtn.dataset.uid = uid; // 按钮点击事件(优化逻辑,避免重复添加) blockBtn.addEventListener('click', () => { const targetUid = Number(blockBtn.dataset.uid); if (ngaBlockUids.includes(targetUid)) { alert(`该用户(UID: ${targetUid})已在屏蔽列表中`); return; } if (confirm(`确定要屏蔽 UID: ${targetUid} 吗?`)) { ngaBlockUids.push(targetUid); GM_setValue(NGA_BLOCK_UIDS_KEY, ngaBlockUids); console.log(`[一键屏蔽] 已添加 UID: ${targetUid} 到屏蔽列表`); window.location.reload(); } }); link.after(blockBtn); }); // 用GM_addStyle添加样式,避免inline样式冲突 GM_addStyle(` .nga-block-button { font-size: 10px; color: #ff5722; margin-left: 5px; cursor: pointer; text-decoration: underline; padding: 0 2px; border: none; background: transparent; } .nga-block-button:hover { color: #e64a19; } `); } // 核心执行函数(增加防抖,避免重复执行) let runScriptDebounce; function runScript() { // 防抖:50ms内只执行一次,避免频繁触发 clearTimeout(runScriptDebounce); runScriptDebounce = setTimeout(() => { removePostsignDivs(); hideTargetPosts(); addBlockButtons(); }, 50); } // 初始执行:等待DOM完全加载后再执行(关键修复) if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', runScript); } else { runScript(); } // 优化MutationObserver:缩小监听范围,减少触发频率 const observer = new MutationObserver((mutations) => { // 仅当新增节点是元素节点时才执行(过滤文本/注释节点) const hasUsefulNodes = mutations.some(mut => Array.from(mut.addedNodes).some(node => node.nodeType === 1)); if (hasUsefulNodes) { runScript(); } }); // 监听范围优化:仅监听帖子列表容器(根据NGA/Chiphell结构调整) const targetContainer = document.querySelector('#postList, #topicList, .forum-main, #threadlist') || document.body; observer.observe(targetContainer, { childList: true, subtree: true, attributes: false, characterData: false }); // 页面卸载时断开监听,避免内存泄漏 window.addEventListener('beforeunload', () => { observer.disconnect(); }); })();