X - Optimized Tweet Buttons

You can freely show or hide the buttons on a tweet, including Reply, Retweet, Like, View Count, Bookmark, and Share. The interface supports switching between Chinese and English.

Instalează acest script?
Script sugerat de autor

Poate îți va plăcea șiX Copy Tweet Link Helper.

Instalează acest script
// ==UserScript==
// @name         X - Optimized Tweet Buttons
// @name:zh-TW   X - 優化推文按鈕
// @name:zh-CN   X - 优化推文按钮
// @namespace    http://tampermonkey.net/
// @version      5.4
// @description  You can freely show or hide the buttons on a tweet, including Reply, Retweet, Like, View Count, Bookmark, and Share. The interface supports switching between Chinese and English.
// @description:zh-TW 可以自由顯示/隱藏,推文上的按鈕,包括,回覆、轉推、喜歡、觀看次數、書籤、分享等按鈕,並且有中英兩種功能語言可以切換
// @description:zh-CN 可以自由显示/隐藏,推文上的按钮,包括,回覆、转推、喜欢、观看次数、书签、分享等按钮,并且有中英两种功能语言可以切换
// @author       chatgpt
// @match        https://twitter.com/*
// @match        https://x.com/*
// @grant        GM_registerMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // === 性能優化核心 ===
    const OPT = {
        debounceTime: 500,
        observerConfig: {
            childList: true,
            subtree: true,
            attributes: false,
            characterData: false
        }
    };

    // === 配置系統 ===
    const CONFIG_KEY = 'XButtonSettings';
    const defaults = {
        hideReply: true,
        hideRetweet: true,
        hideBookmark: true,
        hideViews: true,
        hideShare: true,
        hideLike: false,
        language: 'EN'
    };

    const config = {
        get() {
            return { ...defaults, ...GM_getValue(CONFIG_KEY, {}) };
        },
        update(key, value) {
            const current = this.get();
            GM_setValue(CONFIG_KEY, { ...current, [key]: value });
        }
    };

    // === 多語言系統 ===
    const i18n = {
        EN: {
            reply: 'Reply',
            retweet: 'Retweet',
            bookmark: 'Bookmark',
            views: 'View count',
            share: 'Share',
            like: 'Like',
            language: 'Language'
        },
        'ZH-TW': {
            reply: '回覆',
            retweet: '轉推',
            bookmark: '書籤',
            views: '觀看次數',
            share: '分享',
            like: '喜歡',
            language: '語言'
        }
    };

    function t() {
        const { language } = config.get();
        return i18n[language] || i18n.EN;
    }

    // === 樣式管理 ===
    const style = {
        element: null,
        rules: new Map([
            ['hideReply', '[data-testid="reply"] { display: none !important; }'],
            ['hideRetweet', '[data-testid="retweet"] { display: none !important; }'],
            ['hideBookmark', '[data-testid="bookmark"] { display: none !important; }'],
            ['hideViews', 'a[href*="/analytics"] { display: none !important; }'],
            // 只隱藏原生分享,不隱藏帶有下載圖示的(通常是腳本插入)
            ['hideShare', `
                button[aria-label="Share Post"]:not(:has(svg g.download)),
                button[aria-label="分享貼文"]:not(:has(svg g.download)),
                button[aria-label="分享"]:not(:has(svg g.download)),
                button[aria-label="Compartir publicación"]:not(:has(svg g.download))
                { display: none !important; }
            `],
            ['hideLike', '[data-testid="like"], [data-testid="unlike"] { display: none !important; }']
        ]),
        init() {
            if (!document.getElementById('x-btn-hider-styles')) {
                this.element = document.createElement('style');
                this.element.id = 'x-btn-hider-styles';
                document.head.appendChild(this.element);
            } else {
                this.element = document.getElementById('x-btn-hider-styles');
            }
            this.update();
        },
        update() {
            const currentConfig = config.get();
            const activeRules = Array.from(this.rules.entries())
                .filter(([key]) => currentConfig[key])
                .map(([, rule]) => rule);
            this.element.textContent = activeRules.join('\n');
        }
    };

    // === 選單系統 ===
    const menu = {
        cmds: [],
        build() {
            this.cmds = [];
            const currentConfig = config.get();
            const items = [
                { key: 'hideReply', label: t().reply },
                { key: 'hideRetweet', label: t().retweet },
                { key: 'hideBookmark', label: t().bookmark },
                { key: 'hideViews', label: t().views },
                { key: 'hideShare', label: t().share },
                { key: 'hideLike', label: t().like }
            ];
            items.forEach(({ key, label }) => {
                const status = currentConfig[key] ? '✅' : '❌';
                this.cmds.push(GM_registerMenuCommand(
                    `${label} ${status}`,
                    () => {
                        config.update(key, !config.get()[key]);
                        location.reload(); // 直接刷新頁面
                    }
                ));
            });
            // 語言切換
            let langStatus = '';
            if (currentConfig.language === 'EN') {
                langStatus = 'EN';
            } else {
                langStatus = '中文';
            }
            this.cmds.push(GM_registerMenuCommand(
                `${t().language}: ${langStatus}`,
                () => {
                    config.update('language', currentConfig.language === 'EN' ? 'ZH-TW' : 'EN');
                    location.reload(); // 直接刷新頁面
                }
            ));
        }
    };

    // === 防抖工具函數 ===
    function debounce(func, delay) {
        let timer;
        return (...args) => {
            clearTimeout(timer);
            timer = setTimeout(() => func(...args), delay);
        };
    }

    const debouncedStyleUpdate = debounce(() => style.update(), OPT.debounceTime);

    // === 初始化流程 ===
    (function init() {
        style.init();
        menu.build();
        const observer = new MutationObserver(mutations => {
            if (mutations.some(m => m.addedNodes.length > 0)) {
                debouncedStyleUpdate();
            }
        });
        observer.observe(document.body, OPT.observerConfig);
    })();
})();