X(Twitter) Like and Retweet with One Click

This script adds a button that combines liking and retweeting in one click.

目前為 2024-10-15 提交的版本,檢視 最新版本

// ==UserScript==
// @name         X(Twitter) Like and Retweet with One Click
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  This script adds a button that combines liking and retweeting in one click.
// @author       RayBTA
// @match        https://*.x.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // function to like and retweet
    function likeAndRetweet(post, button) {
        const likeButton = post.querySelector('[data-testid="like"]');
        const retweetButton = post.querySelector('[data-testid="retweet"]');
        const unlikeButton = post.querySelector('[data-testid="unlike"]');
        const undoRetweetButton = post.querySelector('[data-testid="unretweet"]');

        if (button.liked) {
            if (unlikeButton) {
                unlikeButton.click();
            }
            if (undoRetweetButton) {
                undoRetweetButton.click();
                setTimeout(() => {
                    const confirmUnretweetButton = document.querySelector('[data-testid="unretweetConfirm"]');
                    if (confirmUnretweetButton) confirmUnretweetButton.click();
                }, 0);
            }
        } else {
            if (likeButton) {
                likeButton.click();
            }
            if (retweetButton) {
                retweetButton.click();
                setTimeout(() => {
                    const confirmRetweetButton = document.querySelector('[data-testid="retweetConfirm"]');
                    if (confirmRetweetButton) confirmRetweetButton.click();
                }, 0);
            }
        }

        button.liked = !button.liked;
    }

    // Function to add "L & R" button
    function addLikeRetweetButton(post) {
        if (post.querySelector('.auto-like-retweet')) return;

        const button = document.createElement('button');
        button.innerText = "L & R";
        button.classList.add('auto-like-retweet');
        button.liked = false;

        // Check if post is already liked and retweeted
        const unlikeButton = post.querySelector('[data-testid="unlike"]');
        const undoRetweetButton = post.querySelector('[data-testid="unretweet"]');

        if (unlikeButton || undoRetweetButton) {
            button.liked = true;
        }

        button.style.marginLeft = "10px";
        button.style.padding = "5px 8px";
        button.style.backgroundColor = "transparent";
        button.style.color = "#1DA1F2";
        button.style.border = "1px solid #1DA1F2";
        button.style.borderRadius = "20px";
        button.style.cursor = "pointer";
        button.style.fontSize = "14px";
        button.style.fontWeight = "bold";
        button.style.transition = "background-color 0.3s";

        button.onmouseover = () => button.style.backgroundColor = "rgba(29, 161, 242, 0.1)";
        button.onmouseout = () => button.style.backgroundColor = "transparent";

        button.addEventListener('click', () => likeAndRetweet(post, button));

        const actionBar = post.querySelector('[role="group"]');
        if (actionBar) actionBar.appendChild(button);
    }

    // Function to observe new posts
    function observePosts() {
        const observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === 1 && node.matches('.css-175oi2r')) {
                        addLikeRetweetButton(node);
                    }
                });
            });
        });

        const feed = document.querySelector('main, [aria-label="Timeline: Your Home Timeline"], [role="main"]');
        if (feed) {
            observer.observe(feed, { childList: true, subtree: true });
            feed.querySelectorAll('.css-175oi2r').forEach(post => addLikeRetweetButton(post));
        } else {
            setTimeout(observePosts, 2000);
        }
    }

    observePosts();
})();