您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
只要推文主体、标签、用户名等任一区块命中关键字,整则推文一起隐藏。支援关键字新增、清单、单独删除。
当前为
// ==UserScript== // @name Keyword-based Tweet Filtering for Threads // @name:zh-TW Threads 關鍵字過濾推文 // @name:zh-CN Threads 关键字过滤推文 // @namespace http://tampermonkey.net/ // @version 3.3 // @description As long as any section of a tweet—such as the main content, hashtags, or username—matches a keyword, the entire tweet will be hidden. Supports adding keywords, viewing the list, and deleting them individually. // @description:zh-TW 只要推文主體、標籤、用戶名等任一區塊命中關鍵字,整則推文一起隱藏。支援關鍵字新增、清單、單獨刪除。 // @description:zh-CN 只要推文主体、标签、用户名等任一区块命中关键字,整则推文一起隐藏。支援关键字新增、清单、单独删除。 // @author chatgpt // @match https://www.threads.net/* // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @license MIT // ==/UserScript== (function() { 'use strict'; function getKeywords() { return GM_getValue('keywords', []); } function setKeywords(keywords) { GM_setValue('keywords', keywords); } // 取得所有推文主容器 function getAllPostContainers() { return document.querySelectorAll('div[data-pressable-container][class*=" "]'); } // 在推文主容器下,找所有可能含有文字的區塊 function getAllTextBlocks(container) { return container.querySelectorAll('span[dir="auto"]:not([translate="no"]), a[role="link"], span, div'); } function filterPosts() { let keywords = getKeywords(); let containers = getAllPostContainers(); containers.forEach(container => { let blocks = getAllTextBlocks(container); let matched = false; blocks.forEach(block => { let text = (block.innerText || block.textContent || "").trim(); if (text && keywords.some(keyword => keyword && text.includes(keyword))) { matched = true; } }); if (matched) { container.style.display = 'none'; } }); } // observer 只監控新節點 const observer = new MutationObserver(mutations => { let needFilter = false; for (const m of mutations) { if (m.addedNodes && m.addedNodes.length > 0) { needFilter = true; break; } } if (needFilter) filterPosts(); }); observer.observe(document.body, { childList: true, subtree: true }); // 初始執行一次 filterPosts(); // 新增關鍵字 GM_registerMenuCommand('新增關鍵字', () => { let input = prompt('請輸入要新增的關鍵字(可用半形或全形逗號分隔,一次可多個):'); if (input !== null) { let arr = input.split(/,|,/).map(s => s.trim()).filter(Boolean); let keywords = getKeywords(); let newKeywords = [...keywords]; arr.forEach(k => { if (!newKeywords.includes(k)) newKeywords.push(k); }); setKeywords(newKeywords); alert('已新增關鍵字!'); location.reload(); } }); // 關鍵字清單與單獨刪除 GM_registerMenuCommand('關鍵字清單/刪除', () => { let keywords = getKeywords(); if (keywords.length === 0) { alert('目前沒有設定任何關鍵字。'); return; } let msg = '目前關鍵字如下:\n'; keywords.forEach((k, i) => { msg += `${i+1}. ${k}\n`; }); msg += '\n請輸入要刪除的關鍵字編號(可多個,用逗號分隔),或留空取消:'; let input = prompt(msg, ''); if (input !== null && input.trim() !== '') { let idxArr = input.split(/,|,/).map(s => parseInt(s.trim(), 10) - 1).filter(i => !isNaN(i) && i >= 0 && i < keywords.length); if (idxArr.length > 0) { let newKeywords = keywords.filter((k, i) => !idxArr.includes(i)); setKeywords(newKeywords); alert('已刪除指定關鍵字!'); location.reload(); } } }); // 清除所有關鍵字 GM_registerMenuCommand('清除所有關鍵字', () => { setKeywords([]); alert('已清除所有關鍵字!'); location.reload(); }); })();