Greasy Fork is available in English.
Hides posts from suspected bot accounts or users with specific flags/emojis (e.g., 🇮🇱, 🎗️, 🇺🇦) in their name by checking text and image URLs.
当前为
// ==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);
})();