您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
屏蔽关键词并彻底移除屏蔽后的帖子和空行,清理空的tbody标签,支持连续翻页,自动监听动态加载的内容,最大限度提升屏蔽后的阅读体验。
// ==UserScript== // @name NGA屏蔽关键词脚本清净版 // @namespace http://tampermonkey.net/ // @version 1.1 // @description 屏蔽关键词并彻底移除屏蔽后的帖子和空行,清理空的tbody标签,支持连续翻页,自动监听动态加载的内容,最大限度提升屏蔽后的阅读体验。 // @author cloud_rider // @match *://bbs.nga.cn/thread.php?fid=* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; // 屏蔽关键词列表 const blockKeywords = ["关键词1", "关键词2", "关键词3"]; // 请自行修改并增加要屏蔽的关键词 const minVisibleThreads = 20; // 希望页面上保留的最少帖子数 let totalVisibleThreads = 0; // 当前经过屏蔽的总帖子数 const loadedPages = new Set(); // 已加载页面记录,避免重复点击加载 // 屏蔽帖子并清理空行和空的tbody的逻辑 const filterThreads = () => { const threads = document.querySelectorAll('tbody tr'); // 假设帖子以<tbody>和<tr>标签呈现 let visibleCount = 0; threads.forEach(thread => { if (thread.dataset.filtered === "true") { // 如果已经处理过,跳过 if (thread.style.display !== "none") visibleCount++; return; } const titleElement = thread.querySelector('.topic'); // 假设标题位于 .topic 类名下 if (titleElement) { const title = titleElement.textContent || titleElement.innerText; if (blockKeywords.some(keyword => title.includes(keyword))) { // 彻底删除包含关键词的帖子行 thread.remove(); } else { thread.style.display = ""; // 确保未屏蔽的帖子正常显示 visibleCount++; } } else { // 删除没有实际内容的行(即没有标题的行) const isEmpty = thread.textContent.trim() === "" || thread.innerHTML.trim() === ""; if (isEmpty) { thread.remove(); } } thread.dataset.filtered = "true"; // 标记为已处理 }); // 隐藏 PAGE XX 黑条 const blackBars = document.querySelectorAll('th[id^="continuepage"]'); blackBars.forEach(bar => { bar.style.display = "none"; // 隐藏黑条 }); // 清理空的tbody const tbodys = document.querySelectorAll('tbody'); tbodys.forEach(tbody => { if (tbody.children.length === 0) { tbody.remove(); // 如果tbody为空,移除它 } }); return visibleCount; }; // 自动点击“加载下一页” const loadNextPage = async () => { const nextPageLink = document.querySelector('a[title="加载下一页"]'); if (nextPageLink) { const nextPageHref = nextPageLink.getAttribute('href'); if (nextPageHref && !loadedPages.has(nextPageHref)) { loadedPages.add(nextPageHref); // 记录已加载的页面 console.log(`正在加载下一页:${nextPageHref}`); // 模拟点击“加载下一页” nextPageLink.click(); return new Promise((resolve) => { // 等待页面内容加载完成,设置一个延迟 setTimeout(() => { resolve(true); }, 1500); // 假设加载下一页需要1.5秒,可以调整这个时间 }); } } else { console.log("未找到下一页链接,可能已经是最后一页。"); } return false; // 没有下一页 }; // 核心逻辑:递归加载直到满足数量 const ensureSufficientThreads = async () => { totalVisibleThreads = filterThreads(); // 更新当前可见帖子数 console.log(`当前总可见帖子数:${totalVisibleThreads}`); while (totalVisibleThreads < minVisibleThreads) { const success = await loadNextPage(); if (!success) { console.log("无法加载更多页面,可能已经是最后一页。"); break; } totalVisibleThreads = filterThreads(); // 重新计算可见帖子数 } console.log(`最终总可见帖子数:${totalVisibleThreads}`); }; // 监听动态变化的功能 const setupObserver = () => { const observer = new MutationObserver(() => { console.log("检测到页面内容发生变化,重新执行屏蔽逻辑..."); ensureSufficientThreads(); }); // 监听整个帖子列表所在的 DOM 节点 const targetNode = document.body; // 假设整个页面的 body 是动态变化的区域 const config = { childList: true, subtree: true }; observer.observe(targetNode, config); console.log("MutationObserver 已启动,正在监听动态内容变化..."); }; // 初始运行 ensureSufficientThreads(); setupObserver(); console.log("NGA屏蔽关键词+彻底移除被屏蔽行、空行及空tbody脚本已启动!"); })();