X adblock script

This commit is contained in:
Sam Hadow 2025-04-20 14:07:54 +02:00
parent b5072717d3
commit 59a945728d
2 changed files with 100 additions and 0 deletions

View File

@ -0,0 +1,5 @@
Scripts are in the script folder. Please use a userscript manager like [greasemonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/) to use them.
## X-adblock
Script to automatically block accounts posting ads on x.com. [Ublock Origin](https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/) is a much better option. But this script was written thinking "If I block every single account posting ads would I stop seeing ads on twitter? How much time would it take?", still unanswered for now.

95
scripts/X-adblock.user.js Normal file
View File

@ -0,0 +1,95 @@
// ==UserScript==
// @name X Ad Auto-Blocker
// @version 0.1
// @description Automatically block accounts posting ads on x.com
// @match https://x.com/*
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
const processed = new WeakSet();
function waitForSelector(selector, timeout = 3000) {
return new Promise((resolve, reject) => {
const element = document.querySelector(selector);
if (element) return resolve(element);
const observer = new MutationObserver((_, obs) => {
const el = document.querySelector(selector);
if (el) {
obs.disconnect();
resolve(el);
}
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(() => {
observer.disconnect();
reject(new Error(`Timeout waiting for selector: ${selector}`));
}, timeout);
});
}
async function processAdSpan(span) {
try {
processed.add(span);
const container = span.parentElement?.parentElement;
if (!container) return;
const moreBtn = container.querySelector('button[data-testid="caret"]');
if (!moreBtn) return;
moreBtn.click();
const blockItem = await waitForSelector('div[data-testid="block"]');
if (/^\s*Block\s+@.+/i.test(blockItem.innerText)) {
blockItem.click();
} else {
const closeBtn = await waitForSelector('button[aria-label="Close"]');
closeBtn.click();
return;
}
const confirmBtn = await waitForSelector('button[data-testid="confirmationSheetConfirm"]');
confirmBtn.click();
// close "buy X premium" popup
const sheetClose = await waitForSelector('button[data-testid="app-bar-close"]');
sheetClose.click();
console.log('Blocked account posting ads');
} catch (err) {
console.error('Error processing ad span:', err);
}
}
const observer = new MutationObserver((mutations) => {
for (const m of mutations) {
m.addedNodes.forEach(node => {
if (node.nodeType !== 1) return;
// observe these spans to spot ads
const spans = node.matches && node.matches('span.css-1jxf684.r-bcqeeo.r-1ttztb7.r-qvutc0.r-poiln3')
? [node]
: Array.from(node.querySelectorAll('span.css-1jxf684.r-bcqeeo.r-1ttztb7.r-qvutc0.r-poiln3'));
spans.forEach(span => {
if (span.textContent.trim() === 'Ad' && !processed.has(span)) {
processAdSpan(span);
}
});
});
}
});
observer.observe(document.body, { childList: true, subtree: true });
// Initial scan
document.querySelectorAll('span.css-1jxf684.r-bcqeeo.r-1ttztb7.r-qvutc0.r-poiln3').forEach(span => {
if (span.textContent.trim() === 'Ad' && !processed.has(span)) {
processAdSpan(span);
}
});
})();