X/Twitter 一键屏蔽用户

在推特推文右下方添加一键屏蔽按钮

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         X/Twitter 一键屏蔽用户
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  在推特推文右下方添加一键屏蔽按钮
// @author       @Maige
// @match        https://twitter.com/*
// @match        https://x.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=twitter.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 配置参数
    const CONFIG = {
        buttonColor: 'rgb(83, 100, 113)',
        hoverColor: 'rgb(244, 33, 46)',
        timeouts: {
            init: 1500,
            menuAppear: 300,
            confirmAppear: 300,
            closeMenu: 300
        },
        selectors: {
            tweet: 'article[data-testid="tweet"]',
            actionBar: '[role="group"]',
            userLink: 'a[role="link"][href*="/"]',
            moreButton: '[data-testid="caret"]',
            menuItem: '[role="menuitem"]',
            confirmButton: 'div[role="button"]'
        }
    };

    // 定义屏蔽按钮的SVG图标,保持Twitter风格
    const blockIconSVG = `
        <svg viewBox="0 0 24 24" aria-hidden="true" class="r-4qtqp9 r-yyyyoo r-1xvli5t r-dnmrzs r-bnwqim r-1plcrui r-lrvibr r-1hdv0qi">
            <g>
                <path d="M12 3.75C7.99 3.75 4.75 7 4.75 11s3.24 7.25 7.25 7.25S19.25 15 19.25 11 16.01 3.75 12 3.75zm0 12.5c-2.9 0-5.25-2.35-5.25-5.25S9.1 5.75 12 5.75 17.25 8.1 17.25 11s-2.35 5.25-5.25 5.25z"></path>
                <path d="M12 2.75c-4.55 0-8.25 3.7-8.25 8.25s3.7 8.25 8.25 8.25 8.25-3.7 8.25-8.25S16.55 2.75 12 2.75zm0 14.5c-3.45 0-6.25-2.8-6.25-6.25S8.55 4.75 12 4.75s6.25 2.8 6.25 6.25-2.8 6.25-6.25 6.25z"></path>
                <path d="M18.35 4.35l-14 14 1.4 1.4 14-14-1.4-1.4z"></path>
            </g>
        </svg>
    `;

    // 监听DOM变化,为新加载的推文添加屏蔽按钮
    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            if (mutation.addedNodes && mutation.addedNodes.length > 0) {
                for (const node of mutation.addedNodes) {
                    if (node.nodeType === 1) { // 元素节点
                        const tweets = node.querySelectorAll(CONFIG.selectors.tweet);
                        if (tweets.length) tweets.forEach(addBlockButton);
                    }
                }
            }
        }
    });

    // 为已存在的推文添加屏蔽按钮
    function initExistingTweets() {
        const tweets = document.querySelectorAll(CONFIG.selectors.tweet);
        if (tweets.length) tweets.forEach(addBlockButton);
    }

    // 添加屏蔽按钮到推文
    function addBlockButton(tweet) {
        // 检查是否已经添加了屏蔽按钮
        if (tweet.querySelector('.one-click-block-btn')) return;

        // 查找推文的操作区域(右下角的分享、喜欢等按钮区域)
        const actionBar = tweet.querySelector(CONFIG.selectors.actionBar);
        if (!actionBar) return;

        // 创建屏蔽按钮
        const blockButton = document.createElement('div');
        blockButton.className = 'one-click-block-btn';
        blockButton.innerHTML = blockIconSVG;
        blockButton.title = '屏蔽此用户';
        blockButton.style.cssText = `
            cursor: pointer;
            display: inline-flex;
            margin-left: 8px;
            color: ${CONFIG.buttonColor};
        `;

        // 添加悬停效果
        blockButton.addEventListener('mouseover', () => blockButton.style.color = CONFIG.hoverColor);
        blockButton.addEventListener('mouseout', () => blockButton.style.color = CONFIG.buttonColor);

        // 添加点击事件
        blockButton.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            
            // 获取用户信息
            const userLink = tweet.querySelector(CONFIG.selectors.userLink);
            if (!userLink) return;
            
            const username = userLink.href.split('/').filter(Boolean).pop();
            if (!username) return;
            
            // 屏蔽用户
            blockUser(username, tweet);
        });

        // 将按钮添加到操作栏
        actionBar.appendChild(blockButton);
    }

    // 屏蔽用户的函数
    function blockUser(username, tweetElement) {
        // 查找用户的更多操作按钮
        const moreButton = tweetElement.querySelector(CONFIG.selectors.moreButton);
        if (!moreButton) {
            console.error(`无法找到用户 @${username} 的更多操作按钮`);
            return;
        }
        
        // 点击更多按钮
        moreButton.click();
        
        // 等待菜单出现并点击屏蔽选项
        setTimeout(() => {
            const blockOption = Array.from(document.querySelectorAll(CONFIG.selectors.menuItem))
                .find(item => item.textContent.includes('屏蔽') || item.textContent.includes('Block'));
            
            if (!blockOption) {
                document.body.click(); // 关闭菜单
                return;
            }
            
            // 点击屏蔽选项
            blockOption.click();
            
            // 等待确认对话框出现并确认
            setTimeout(() => {
                const confirmButton = Array.from(document.querySelectorAll(CONFIG.selectors.confirmButton))
                    .find(btn => btn.textContent.includes('屏蔽') || btn.textContent.includes('Block'));
                
                if (!confirmButton) {
                    document.body.click(); // 关闭菜单
                    return;
                }
                
                // 点击确认按钮
                confirmButton.click();
                console.log(`已屏蔽用户: @${username}`);
                
                // 关闭菜单
                setTimeout(() => document.body.click(), CONFIG.timeouts.closeMenu);
            }, CONFIG.timeouts.confirmAppear);
        }, CONFIG.timeouts.menuAppear);
    }

    // 初始化
    function init() {
        // 开始观察DOM变化
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
        
        // 处理已存在的推文
        setTimeout(initExistingTweets, CONFIG.timeouts.init);
        
        // 处理页面内导航(Twitter是SPA)
        let lastUrl = location.href;
        new MutationObserver(() => {
            const url = location.href;
            if (url !== lastUrl) {
                lastUrl = url;
                setTimeout(initExistingTweets, CONFIG.timeouts.init);
            }
        }).observe(document, {subtree: true, childList: true});
    }

    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();