Last active
July 30, 2025 17:01
-
-
Save bogorad/b677bacdb49a9eed4fdb4665dea5caba to your computer and use it in GitHub Desktop.
block x ads, unhide text - tampermonkey script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Twitter/X Ad Hider & Auto-Expander | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.4 | |
| // @description Hides promoted tweets (ads) and automatically clicks "Show more" to expand long tweets in the timeline. | |
| // @author Your Name (or alias) | |
| // @match *://*.twitter.com/* | |
| // @match *://x.com/* | |
| // @grant none | |
| // @run-at document-idle | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // --- Selectors --- | |
| const AD_TEXT_SELECTOR = './/span[text()="Ad"]'; // XPath selector for the "Ad" text | |
| const AD_CONTAINER_SELECTOR = 'div[data-testid="cellInnerDiv"]'; // CSS selector for the container to hide | |
| // NEW: Selector for the "Show more" button in tweets. | |
| const SHOW_MORE_BUTTON_SELECTOR = 'button[data-testid="tweet-text-show-more-link"]'; | |
| // --- Core Functions --- | |
| // Function to find and hide ads within a given node or the whole document | |
| function hideAds(node = document) { | |
| try { | |
| const xpathResult = document.evaluate( | |
| AD_TEXT_SELECTOR, | |
| node, | |
| null, | |
| XPathResult.ORDERED_NODE_ITERATOR_TYPE, | |
| null | |
| ); | |
| let adSpan; | |
| while ((adSpan = xpathResult.iterateNext())) { | |
| const adContainer = adSpan.closest(AD_CONTAINER_SELECTOR); | |
| if (adContainer && adContainer.style.display !== 'none') { | |
| // console.log('Hiding Ad:', adContainer); | |
| adContainer.style.display = 'none'; | |
| } | |
| } | |
| } catch (error) { | |
| console.error('Twitter/X Ad Hider Error during hiding:', error); | |
| } | |
| } | |
| // NEW: Function to find and click "Show more" buttons within a given node. | |
| // This is adapted from the logic you provided. | |
| function autoExpandTweets(node = document) { | |
| try { | |
| // Find all potential "Show more" buttons within the scanned node. | |
| const showMoreButtons = node.querySelectorAll(SHOW_MORE_BUTTON_SELECTOR); | |
| showMoreButtons.forEach(button => { | |
| // The offsetParent check is a reliable way to see if an element is currently visible on the page. | |
| if (button.offsetParent !== null) { | |
| // console.log('Expanding tweet...'); | |
| button.click(); | |
| } | |
| }); | |
| } catch (error) { | |
| console.error('Twitter/X Auto-Expander Error:', error); | |
| } | |
| } | |
| // NEW: A combined function to process new content. | |
| function processNode(node) { | |
| hideAds(node); | |
| autoExpandTweets(node); | |
| } | |
| // --- MutationObserver Setup --- | |
| const targetNode = document.body; | |
| if (!targetNode) { | |
| console.error('Twitter/X Script: Could not find target node to observe.'); | |
| return; | |
| } | |
| const config = { | |
| childList: true, | |
| subtree: true | |
| }; | |
| // Callback function now calls our combined processor. | |
| const callback = function(mutationsList, observer) { | |
| for (const mutation of mutationsList) { | |
| if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { | |
| mutation.addedNodes.forEach(node => { | |
| // We only need to check element nodes. | |
| if (node.nodeType === Node.ELEMENT_NODE) { | |
| // Process each new node for both ads and "Show more" links. | |
| processNode(node); | |
| } | |
| }); | |
| } | |
| } | |
| }; | |
| const observer = new MutationObserver(callback); | |
| try { | |
| observer.observe(targetNode, config); | |
| // console.log('Twitter/X Script: Observer started.'); | |
| } catch (error) { | |
| console.error('Twitter/X Script Error starting observer:', error); | |
| } | |
| // --- Initial Run --- | |
| // Run once on script load to catch content already present. | |
| setTimeout(() => { | |
| // console.log('Twitter/X Script: Running initial scan...'); | |
| // Run the combined processor on the whole document body. | |
| processNode(document.body); | |
| }, 500); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment