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