Keyword-based Tweet Filtering for Threads

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.

Versión del día 24/4/2025. Echa un vistazo a la versión más reciente.

// ==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();
    });

})();