Greasy Fork

Greasy Fork is available in English.

Twitter/X Bot and Flag Post Hider

Hides posts from suspected bot accounts or users with specific flags/emojis (e.g., 🇮🇱, 🎗️, 🇺🇦) in their name by checking text and image URLs.

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

您需要先安装一款用户脚本管理器扩展,例如 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.7
// @description  Hides posts from suspected bot accounts or users with specific flags/emojis (e.g., 🇮🇱, 🎗️, 🇺🇦) in their name by checking text and image URLs.
// @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,}$/;

    // Hides if user's display name INCLUDES these characters (e.g., for standard text emojis).
    const HIDE_IF_NAME_INCLUDES = ['🇮🇱', '🎗️', '🇺🇦'];

    // Hides if user's name contains an IMAGE with a SRC attribute containing these strings. This is more reliable for flags.
    const HIDE_IF_IMG_SRC_INCLUDES = [
        '1f1ee-1f1f1', // Israel Flag 🇮🇱
        '1f1fa-1f1e6', // Ukraine Flag 🇺🇦
        '1f397'        // Reminder Ribbon 🎗️
    ];

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

    function createCounterElement() {
        const counterDiv = document.createElement('div');
        counterDiv.id = 'bot-hider-counter';
        Object.assign(counterDiv.style, {
            position: 'fixed',
            top: '15px',
            left: '15px',
            backgroundColor: 'rgba(29, 155, 240, 0.9)',
            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();

    // Check based on simple text content (includes alt text of images)
    function nameContainsHiddenString(displayName) {
        return HIDE_IF_NAME_INCLUDES.some(str => displayName.includes(str));
    }

    // New, more reliable check based on the image's SRC attribute
    function nameContainsHiddenImage(displayNameElement) {
        if (!displayNameElement) return false;
        const images = displayNameElement.querySelectorAll('img');
        for (const img of images) {
            const src = img.getAttribute('src');
            if (src && HIDE_IF_IMG_SRC_INCLUDES.some(str => src.includes(str))) {
                return true; // Found a matching image src
            }
        }
        return false;
    }

    function hidePosts() {
        const articles = document.querySelectorAll('article[data-testid="tweet"]');

        articles.forEach(article => {
            const articleId = article.getAttribute('aria-labelledby');
            if (!articleId || processedPosts.has(articleId)) {
                return;
            }
            processedPosts.add(articleId);

            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);
                const displayName = userDisplayNameElement.textContent || '';

                // The hiding condition now includes the new, more reliable image check
                const shouldHide = BOT_USERNAME_PATTERN.test(username) ||
                                   nameContainsHiddenString(displayName) ||
                                   nameContainsHiddenImage(userDisplayNameElement) || // <-- Added new check
                                   href.toLowerCase().includes('jew');

                if (shouldHide) {
                    const postContainer = article.closest('[data-testid="cellInnerDiv"]');
                    if (postContainer) {
                        postContainer.style.display = 'none';
                        hiddenPostCount++;
                    }
                }
            }
        });

        counterElement.textContent = `Hiding ${hiddenPostCount} posts`;
    }

    console.log('Twitter/X Bot & Flag Hider script is now active.');
    setInterval(hidePosts, CHECK_INTERVAL);
})();