Twitter Enhancement

Remove promoted tweets and ads from Twitter feed

// ==UserScript==
// @name         Twitter Enhancement
// @namespace    http://tampermonkey.net/
// @version      1.1.1
// @description  Remove promoted tweets and ads from Twitter feed
// @author       aspen138
// @match        *://twitter.com/*
// @match        *://x.com/*
// @grant        none
// @license      MIT
// @grant        GM_addStyle
// @icon         https://about.twitter.com/etc/designs/about2-twitter/public/img/favicon-32x32.png
// ==/UserScript==


// Twitter Ad Remover
(function() {
    function hideAd(node) {
        if (
            !node ||
            node.nodeName !== "DIV" ||
            node.getAttribute("data-testid") !== "cellInnerDiv"
        ) {
            return;
        }

        const adArticle = node.querySelector("div[data-testid='placementTracking'] > article");
        if (!adArticle) {
            return;
        }

        node.style.cssText += "display: none;";
    }

    // Observe for newly added nodes and hide ads in them
    new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            mutation.addedNodes.forEach(hideAd);
        });

        // Hide the sidebar ad
        const sidebarAd = document.querySelector("#react-root > div > div > div.css-175oi2r.r-1f2l425.r-13qz1uu.r-417010.r-18u37iz > main > div > div > div > div.css-175oi2r.r-aqfbo4.r-10f7w94.r-1hycxz > div > div.css-175oi2r.r-1hycxz.r-gtdqiz > div > div > div > div:nth-child(3) > div > aside");
        if (sidebarAd) {
            sidebarAd.style.display = 'none';
        }
    }).observe(document.body, {
        childList: true,
        subtree: true
    });

    // Initial pass to hide existing ads
    document.querySelectorAll("div[data-testid='cellInnerDiv']").forEach(hideAd);

    function removePromotedTweets(node) {
        node = node || document.body;
        const tweets = node.querySelectorAll('article[data-testid="tweet"]');

        tweets.forEach((tweet) => {
            const adLabel = tweet.querySelector('div[dir="ltr"] > span');
            if (adLabel && (adLabel.textContent === 'Promoted' || adLabel.textContent === 'Ad')) {
                tweet.remove();
            }
        });
    }

    // Initial removal of promoted tweets
    removePromotedTweets();

    // Observe the DOM for changes and remove newly added promoted tweets
    new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            mutation.addedNodes.forEach(function(node) {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    removePromotedTweets(node);
                }
            });
        });
    }).observe(document.body, {
        childList: true,
        subtree: true
    });
})();



// I can understand summarizing a user's profile. But what's the point of summarizing a tweet that's not even very long????
// hide Grok xAI "explain this post"
(function() {
    'use strict';

    // Inject a <style> tag with display: none !important for the specific SVG elements
    const style = document.createElement('style');
    style.innerHTML = 'button[aria-label="Grok actions"] { display: none !important; }';
    document.head.appendChild(style);

    // Select all specific SVG elements based on their class names
    const svgElements = document.querySelectorAll('button[aria-label="Grok actions"]');

    // Hide each matched SVG element
    svgElements.forEach(svg => {
        svg.style.display = 'none';
    });
})();