Greasy Fork

Greasy Fork is available in English.

X 黄推+币圈机器人终极隐藏器

宁杀错不放过:强力屏蔽引流/币圈/擦边/博彩等机器人内容,支持选中文本后alt+B一键加入屏蔽词。

当前为 2026-03-23 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         X 黄推+币圈机器人终极隐藏器
// @namespace    https://grok.x.ai
// @version      1.1
// @description  宁杀错不放过:强力屏蔽引流/币圈/擦边/博彩等机器人内容,支持选中文本后alt+B一键加入屏蔽词。
// @author       Grok、codex
// @match        https://x.com/*
// @match        https://twitter.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// @icon         http://greasyfork.icu/images/blacklogo16.png
// @homepageURL  http://greasyfork.icu/zh-CN/scripts/570683
// ==/UserScript==

(function () {
    'use strict';

    const STORAGE_KEY = 'x_block_words_v1';
    const HIDDEN_ATTR = 'data-x-ultra-hidden';

    const BUILTIN_PATTERNS = [
        /男大/i,
        /足控/i,
        /蜜桃臀/i,
        /主人|舔狗|小狗|真人|线下|上门|男搭讪|急找|在线|蹲一个|有线下吗/i,
        /谁来当我主人|小狗想跟你玩|小狗在线找主人|小狗在线等你|主人快来领我/i,
        /找个长期搭子|有没有单男|有没有游戏搭子|有没有单女/i,
        /急需一位|找个哥哥|调教|附近的有没有|满足我|看做爱|不如做爱/i,
        /小母狗|母狗|欲望少女|纯欲|反差/i,
        /我是真人 有线下吗|➡️小狗在线等你|➡️(急需|找个|蹲一个|谁来当我)/i,
        /那亲亲吧|你的娱乐群|小狗在线等你/i,
        /找个同城哥哥|找个温柔主人|dd个线下|找个线下哥哥|小狗求主人抱抱/i,
        /空投|USDT.*(奖池|交易|转账|推广)|拉盘|打新项目|上币路线|Pre-IPO|合约.*(喊单|爆仓)/i,
        /引流|私信|DM|加V|VX|微信|电报|TG|群号|群聊|福利群|进群|进组/i,
        /开户|理财|搬砖|量化|带单|套利|返利|高收益|稳赚|保本|日赚/i,
        /博彩|赌场|下注|百家乐|时时彩|快三|网投|棋牌游戏/i,
        /约炮|一夜情|同城|上门服务|包夜|全套|外围|小姐|嫩模|学生妹/i,
        /裸聊|视频聊天|视频交友|语音交友|聊骚|骚扰|撩骚/i,
        /兼职|日结|招募|代理|推广员|刷单|返现|冲量/i,
        /空降|互关|互粉|互赞|点赞关注|关注我|回关|求关/i,
        /[\u2196\u2197\u2198\u2199\u2190\u2191\u2192\u2193\u2B05\u2B06\u2B07\u27A1]/,
        /蹲|搭子|固炮|反差/i,
        /同城(哥哥|弟弟|姐姐|妹妹)|陪聊|陪玩|陪睡|宠物系|恋爱搭子|陪伴搭子/i,
        /小狗找主人|小狗求主人|找(个|位)?主人|找(个|位)?哥哥|找(个|位)?弟弟/i,
        /主(人|子)快来领我|求主人抱抱|在线等(你|哥哥|弟弟)/i,
        /淫/i,
        /温柔主(人)?|同城|万达广场附近/i,
        /(^|[^A-Za-z0-9])[sSmM]([^A-Za-z0-9]|$)/,
        /萌猫|小烧货|千万次心跳|护士姐姐|学妹|学姐|反差婊/i,
        /(萌|甜|软|奶|乖|小|可爱).*(猫|狗|兔|鹿|狐|虎|猫咪)/i,
        /(护士|学妹|学姐|老师|姐姐|妹妹).*(小烧货|反差|纯欲|欲望)/i,
        /\b[A-Z][a-z]+[A-Z][a-z]+\d{3,}\b/,
        /蹲一个男搭子|有没有离得近的|被.*(小烧货|骚货|sao货)|扣1白给|温柔s|爹系男友/i,
        /射射|色色|涩涩|瑟瑟|视频|瓦学弟|破处/i
    ];

    const NAME_PATTERNS = [
        /反差|母狗|臀|破处|处男|处女|找主人|温柔主/i,
        /(^|[^A-Za-z0-9])[sSmM]([^A-Za-z0-9]|$)/,
        /男大|足控|蜜桃臀/i
    ];

    function escapeRegExp(text) {
        return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    function normalize(text) {
        return (text || '')
            .toLowerCase()
            .replace(/[\s\.\,\!\?\-_/\\()\[\]{}"'`~@#$%^&*+=<>|:;、,。!?【】()《》“”‘’·]+/g, '');
    }

    function isMostlyEmoji(text) {
        const stripped = (text || '').replace(/[\p{Extended_Pictographic}\s\.,!?;:、,。!?【】()《》“”‘’·~`'"-]/gu, '');
        return stripped.length <= 1 && /[\p{Extended_Pictographic}]/u.test(text || '');
    }

    function emojiOnlyWithHearts(text) {
        const t = text || '';
        const nonEmoji = t.replace(/[\p{Extended_Pictographic}\s\.,!?;:、,。!?【】()《》“”‘’·~`'"-]/gu, '');
        if (nonEmoji.length > 0) return false;
        const emojis = (t.match(/[\p{Extended_Pictographic}]/gu) || []).length;
        if (emojis < 3) return false;
        return /[\u2764\uFE0F\u1F49B\u1F49A\u1F499\u1F49C\u1F90E\u1F90D\u1F5A4]/u.test(t);
    }

    function loadUserWords() {
        try {
            const raw = localStorage.getItem(STORAGE_KEY);
            const list = raw ? JSON.parse(raw) : [];
            return Array.isArray(list) ? list : [];
        } catch {
            return [];
        }
    }

    let userWords = loadUserWords();
    let userRegexes = buildUserRegexes(userWords);

    function buildUserRegexes(words) {
        return words
            .map(w => String(w || '').trim())
            .filter(Boolean)
            .map(w => new RegExp(`.*${escapeRegExp(w)}.*`, 'i')); // 贪婪匹配
    }

    function saveUserWords() {
        localStorage.setItem(STORAGE_KEY, JSON.stringify(userWords));
        userRegexes = buildUserRegexes(userWords);
    }

    function addUserWord(word) {
        const w = String(word || '').trim();
        if (!w) return;
        if (userWords.includes(w)) return;
        userWords.push(w);
        saveUserWords();
        toast(`已加入屏蔽词:${w}`);
        scheduleScan();
    }

    function shouldHide(text, nameText) {
        const original = text || '';
        const compact = normalize(original);
        const name = nameText || '';
        const nameCompact = normalize(name);
        return emojiOnlyWithHearts(original) ||
            isMostlyEmoji(original) ||
            NAME_PATTERNS.some(r => r.test(name) || r.test(nameCompact)) ||
            BUILTIN_PATTERNS.some(r => r.test(original) || r.test(compact)) ||
            userRegexes.some(r => r.test(original) || r.test(compact) || r.test(name) || r.test(nameCompact));
    }

    function collectArticleText(article) {
        const parts = [];
        const text = article.textContent || '';
        if (text) parts.push(text);
        article.querySelectorAll('[alt],[title],[aria-label]').forEach(el => {
            const alt = el.getAttribute('alt');
            const title = el.getAttribute('title');
            const aria = el.getAttribute('aria-label');
            if (alt) parts.push(alt);
            if (title) parts.push(title);
            if (aria) parts.push(aria);
        });
        return parts.join(' ');
    }

    function collectNameText(article) {
        const nameNode = article.querySelector('[data-testid="User-Name"]');
        return nameNode ? (nameNode.textContent || '') : '';
    }

    function hideArticle(article) {
        if (article.getAttribute(HIDDEN_ATTR)) return;
        const text = collectArticleText(article).trim();
        const nameText = collectNameText(article).trim();
        if (!shouldHide(text, nameText)) return;
        article.setAttribute(HIDDEN_ATTR, '1');
        article.style.setProperty('display', 'none', 'important');
        article.style.setProperty('visibility', 'hidden', 'important');
        const container = article.closest('div[data-testid="cellInnerDiv"]');
        if (container) container.style.setProperty('display', 'none', 'important');
    }

    function scanAll() {
        document.querySelectorAll('article[data-testid="tweet"]').forEach(hideArticle);
    }

    let scanInProgress = false;
    function scheduleScan() {
        if (scanInProgress) return;
        scanInProgress = true;
        scanAll();
        scanInProgress = false;
    }

    function handleMutations(mutations) {
        for (const mutation of mutations) {
            for (const node of mutation.addedNodes) {
                if (node.nodeType !== 1) continue;
                if (node.matches && node.matches('article[data-testid="tweet"]')) {
                    hideArticle(node);
                } else if (node.querySelectorAll) {
                    node.querySelectorAll('article[data-testid="tweet"]').forEach(hideArticle);
                }
            }
        }
    }

    function getSelectionText() {
        return String(window.getSelection && window.getSelection().toString() || '').trim();
    }

    function createManagePanel() {
        const panel = document.createElement('div');
        panel.id = 'x-ultra-block-panel';
        panel.style.cssText = [
            'position:fixed',
            'right:16px',
            'bottom:64px',
            'width:280px',
            'max-height:360px',
            'overflow:auto',
            'background:#111',
            'color:#fff',
            'border:1px solid #444',
            'border-radius:10px',
            'padding:10px',
            'font-size:12px',
            'z-index:2147483647',
            'display:none'
        ].join(';');

        const header = document.createElement('div');
        header.textContent = '屏蔽词管理';
        header.style.cssText = 'font-weight:600; margin-bottom:8px;';

        const list = document.createElement('div');

        const inputRow = document.createElement('div');
        inputRow.style.cssText = 'display:flex; gap:6px; margin-bottom:8px;';
        const input = document.createElement('input');
        input.placeholder = '手动添加屏蔽词';
        input.style.cssText = 'flex:1; padding:4px 6px; border:1px solid #333; border-radius:6px; background:#0b0b0b; color:#fff;';
        const addBtn = document.createElement('button');
        addBtn.textContent = '添加';
        addBtn.style.cssText = 'padding:4px 8px; cursor:pointer;';
        inputRow.appendChild(input);
        inputRow.appendChild(addBtn);

        const quickRow = document.createElement('div');
        quickRow.style.cssText = 'display:flex; gap:6px; margin-bottom:8px;';
        const addSelBtn = document.createElement('button');
        addSelBtn.textContent = '添加选中';
        addSelBtn.style.cssText = 'flex:1; padding:4px 6px; cursor:pointer;';
        const hint = document.createElement('div');
        hint.textContent = '快捷键:Alt+B 添加选中文本';
        hint.style.cssText = 'flex:2; color:#aaa; align-self:center;';
        quickRow.appendChild(addSelBtn);
        quickRow.appendChild(hint);

        const actions = document.createElement('div');
        actions.style.cssText = 'margin-top:8px; display:flex; gap:6px;';

        const clearBtn = document.createElement('button');
        clearBtn.textContent = '清空';
        clearBtn.style.cssText = 'flex:1; padding:4px 6px; cursor:pointer;';

        const closeBtn = document.createElement('button');
        closeBtn.textContent = '关闭';
        closeBtn.style.cssText = 'flex:1; padding:4px 6px; cursor:pointer;';

        actions.appendChild(clearBtn);
        actions.appendChild(closeBtn);

        panel.appendChild(header);
        panel.appendChild(inputRow);
        panel.appendChild(quickRow);
        panel.appendChild(list);
        panel.appendChild(actions);
        document.documentElement.appendChild(panel);

        function renderList() {
            list.innerHTML = '';
            if (!userWords.length) {
                const empty = document.createElement('div');
                empty.textContent = '暂无自定义屏蔽词';
                empty.style.cssText = 'color:#888; padding:4px 0;';
                list.appendChild(empty);
                return;
            }
            userWords.forEach((w, idx) => {
                const row = document.createElement('div');
                row.style.cssText = 'display:flex; justify-content:space-between; align-items:center; padding:4px 0; border-bottom:1px dashed #333;';
                const text = document.createElement('span');
                text.textContent = w;
                const del = document.createElement('button');
                del.textContent = '删除';
                del.style.cssText = 'margin-left:8px; cursor:pointer;';
                del.addEventListener('click', () => {
                    userWords.splice(idx, 1);
                    saveUserWords();
                    renderList();
                    scheduleScan();
                });
                row.appendChild(text);
                row.appendChild(del);
                list.appendChild(row);
            });
        }

        clearBtn.addEventListener('click', () => {
            userWords = [];
            saveUserWords();
            renderList();
            scheduleScan();
        });
        closeBtn.addEventListener('click', () => {
            panel.style.display = 'none';
        });

        function togglePanel() {
            renderList();
            panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
        }

        const toggleBtn = document.createElement('div');
        toggleBtn.textContent = '屏蔽词';
        toggleBtn.style.cssText = [
            'position:fixed',
            'right:16px',
            'bottom:16px',
            'background:#111',
            'color:#fff',
            'border:1px solid #444',
            'border-radius:999px',
            'padding:6px 10px',
            'font-size:12px',
            'cursor:pointer',
            'z-index:2147483647'
        ].join(';');
        toggleBtn.addEventListener('click', togglePanel);
        document.documentElement.appendChild(toggleBtn);
    }

    function toast(message) {
        const node = document.createElement('div');
        node.textContent = message;
        node.style.cssText = [
            'position:fixed',
            'right:16px',
            'bottom:16px',
            'background:#222',
            'color:#fff',
            'border:1px solid #444',
            'padding:8px 10px',
            'border-radius:8px',
            'font-size:12px',
            'z-index:2147483647'
        ].join(';');
        document.documentElement.appendChild(node);
        setTimeout(() => node.remove(), 1600);
    }

    function init() {
        scanAll();
        const observer = new MutationObserver(handleMutations);
        observer.observe(document.documentElement, { childList: true, subtree: true });
        window.addEventListener('load', scheduleScan);
        window.addEventListener('popstate', scheduleScan);
        const originalPushState = history.pushState;
        const originalReplaceState = history.replaceState;
        history.pushState = function () {
            const result = originalPushState.apply(this, arguments);
            scheduleScan();
            return result;
        };
        history.replaceState = function () {
            const result = originalReplaceState.apply(this, arguments);
            scheduleScan();
            return result;
        };
        window.addEventListener('scroll', () => { if (Math.random() < 0.08) scheduleScan(); }, { passive: true });
        setInterval(scheduleScan, 1200);
        createManagePanel();
        document.addEventListener('keydown', (event) => {
            if (event.altKey && !event.ctrlKey && !event.metaKey && event.key.toLowerCase() === 'b') {
                const sel = getSelectionText();
                if (sel) addUserWord(sel);
            }
        }, { capture: true });
    }

    if (document.documentElement) {
        init();
    } else {
        document.addEventListener('readystatechange', () => {
            if (document.documentElement) init();
        }, { once: true });
    }

    console.log('✅ X 强力隐藏器已加载(宁杀错不放过)');
})();
        addBtn.addEventListener('click', () => {
            addUserWord(input.value);
            input.value = '';
        });
        input.addEventListener('keydown', (event) => {
            if (event.key === 'Enter') {
                addUserWord(input.value);
                input.value = '';
            }
        });
        addSelBtn.addEventListener('click', () => {
            const sel = getSelectionText();
            if (sel) addUserWord(sel);
        });