Greasy Fork

Greasy Fork is available in English.

Twitter/X Bot and Flag Post Hider

Hides posts from suspected bot accounts (e.g., Name12345) or users with specific flags (e.g., 🇮🇱) in their name.

当前为 2025-07-03 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Twitter/X Bot and Flag Post Hider
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Hides posts from suspected bot accounts (e.g., Name12345) or users with specific flags (e.g., 🇮🇱) in their name.
// @author       CL
// @match        *://x.com/*
// @match        *://twitter.com/*
// @grant        none
// @run-at       document-idle
// @license MIT 
// ==/UserScript==

(function() {
    'use strict';

    // --- Configuration ---
    // This regex pattern identifies usernames that have letters followed by two or more numbers at the end.
    const BOT_USERNAME_PATTERN = /[a-zA-Z].*\d{2,}$/;
    // This array contains strings or emojis to look for in the user's display name. Add more items to this list to hide more users.
    const HIDE_IF_NAME_INCLUDES = ['🇮🇱'];

    // How often the script checks for new posts on the page (in milliseconds).
    const CHECK_INTERVAL = 1000;
    // --- End Configuration ---

    let hiddenPostCount = 0;
    const processedPosts = new Set();

    /**
     * Creates and injects a counter element onto the page to display the number of hidden posts.
     * @returns {HTMLElement} The created counter element.
     */
    function createCounterElement() {
        const counterDiv = document.createElement('div');
        counterDiv.id = 'bot-hider-counter';
        // Apply styles to make the counter visible but not intrusive.
        Object.assign(counterDiv.style, {
            position: 'fixed',
            top: '15px',
            left: '15px',
            backgroundColor: 'rgba(29, 155, 240, 0.9)', // A semi-transparent Twitter blue
            color: 'white',
            padding: '5px 12px',
            borderRadius: '15px',
            zIndex: '10000',
            fontSize: '14px',
            fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif',
            boxShadow: '0 2px 8px rgba(0,0,0,0.2)',
            userSelect: 'none',
            transition: 'opacity 0.3s ease-in-out'
        });
        document.body.appendChild(counterDiv);
        return counterDiv;
    }

    const counterElement = createCounterElement();

    /**
     * Checks if a user's display name contains any of the strings specified in the configuration.
     * @param {string} displayName - The user's display name.
     * @returns {boolean} - True if the name contains a forbidden string, false otherwise.
     */
    function nameContainsHiddenString(displayName) {
        return HIDE_IF_NAME_INCLUDES.some(str => displayName.includes(str));
    }

    /**
     * The main function that finds and hides posts based on configured rules.
     * It iterates through all tweet articles, checks the author's username and display name,
     * and hides the post if it matches any rule.
     */
    function hidePosts() {
        // Select all tweet articles on the page. `data-testid` is a more stable selector than CSS classes.
        const articles = document.querySelectorAll('article[data-testid="tweet"]');

        articles.forEach(article => {
            // A unique identifier for the tweet, often found in 'aria-labelledby', is used to track processed posts.
            // This prevents the script from re-evaluating the same post repeatedly.
            const articleId = article.getAttribute('aria-labelledby');
            if (!articleId || processedPosts.has(articleId)) {
                return; // Skip if it has no ID or has already been processed.
            }
            processedPosts.add(articleId);

            // Find the user's profile link and display name element.
            const userLink = article.querySelector('a[href^="/"]:not([href*="/status/"])');
            const userDisplayNameElement = article.querySelector('[data-testid="User-Name"]');

            if (userLink && userDisplayNameElement) {
                const href = userLink.getAttribute('href');
                const username = href.substring(1); // Remove the leading '/' to get the username.
                const displayName = userDisplayNameElement.textContent || '';

                // Check if the post should be hidden based on either the username pattern or the display name content.
                const shouldHide = BOT_USERNAME_PATTERN.test(username) || nameContainsHiddenString(displayName);

                if (shouldHide) {
                    // Traverse up the DOM to find the main container of the post.
                    // Hiding this container removes the entire post from view.
                    const postContainer = article.closest('[data-testid="cellInnerDiv"]');
                    if (postContainer) {
                        postContainer.style.display = 'none';
                        hiddenPostCount++;
                    }
                }
            }
        });

        // Update the counter display with the latest count.
        counterElement.textContent = `Hiding ${hiddenPostCount} posts`;
    }

    // --- Script Execution ---
    console.log('Twitter/X Bot & Flag Hider script is now active.');

    // Because Twitter is a single-page application that loads content dynamically,
    // we need to run our function periodically to catch new tweets as they appear.
    setInterval(hidePosts, CHECK_INTERVAL);
})();