Last active
April 4, 2025 08:21
-
-
Save zbalkan/0ae985b71bdcd0bee01ac1b8fd344c4d to your computer and use it in GitHub Desktop.
Block retweeters of a post
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
// Twitter (or what’s left of it — X) someimes gives headaches. | |
// I used the script of Isaac King at https://outsidetheasylum.blog/twitter-blocker/ at the beginning. | |
// But the HTTP 428 is a headache. At first I added some random latency one each and every 10th action. | |
// Then I blocked the queries to the bottlenecks like avatar loading API. | |
// Now, it is harder to get blocked by Twitter's rate limiting. | |
// Usage | |
// Pick the tweet you want to block th RTers. | |
// On the menu at the righthand side, click "View post engagements" | |
// Navigate to "Reposts" tab | |
// Open developer tools in Chrome | |
// Navigate to Network tab and uncheck "Disable cache" | |
// Navigate to Console tab | |
// Paste the line below into Console and hit enter | |
(async()=>{const shortPauseMin=250,shortPauseMax=750,longPauseEvery=10,longPauseMin=1000,longPauseMax=2000;if(!/^https:\/\/x\.com\/[^\/]+\/status\/\d+\/retweets/.test(location.href))throw new Error("This script only works on a tweet's retweeters page.");(function(){const b=/avatar_content|profile_image|users\/avatar|fleetline|useFetchProfileSections_canViewExpandedProfileQuery/i,m=new WeakMap,o=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(M,U,...r){m.set(this,U);return o.call(this,M,U,...r)};const s=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.send=function(...a){const u=m.get(this);if(u&&b.test(u))return this.abort();return s.apply(this,a)}})(),window.fetch=new Proxy(window.fetch,{apply:(t,e,a)=>/avatar_content|profile_image|users\/avatar|fleetline/i.test(a[0])?new Promise(()=>{}):t.apply(e,a)}),Object.defineProperty(Image.prototype,"src",{set(v){/pbs\.twimg\.com\/profile_images/.test(v)||this.setAttribute("src",v)}});const u={},s=async(t=shortPauseMin,e=shortPauseMax)=>new Promise(o=>setTimeout(o,Math.floor(Math.random()*(e-t+1))+t)),n=async t=>new Promise(e=>setTimeout(e,t)),c=()=>{let e=Array.from(document.querySelectorAll('[aria-label="Timeline: Reposts"] > div > div')).concat(Array.from(document.querySelectorAll('[aria-label="Timeline: Verified Followers"] > div > div'))).concat(Array.from(document.querySelectorAll('[aria-label="Timeline: Followers"] > div > div'))).concat(Array.from(document.querySelectorAll('[aria-label="Timeline: List members"] > div > div')));for(let t of e)try{let e=t.firstChild.firstChild.firstChild.firstChild.children[1].firstChild.firstChild.firstChild.firstChild.firstChild;if(e.href&&!u[e.href])return e}catch(o){}return!1},d=e=>{let t=document.querySelector('[data-testid="Dropdown"]')||document.querySelector('[data-testid="sheetDialog"]');if(!t)return!1;let l=Array.from(t.children);for(let o of l)try{if(o.children[1].firstChild.firstChild.textContent.startsWith(e+" @"))return o}catch(r){}return console.log("Could not find "+e.toLowerCase()+" button"),!1},a=async(e,t)=>{for(u[e.href]=!0,e.click();null===document.querySelector('[data-testid="userActions"]');)await n(10);for(document.querySelector('[data-testid="userActions"]').firstChild.click();!document.querySelector('[data-testid="Dropdown"]')&&!document.querySelector('[data-testid="sheetDialog"]');)await n(10);let o=d(t);if(o&&(o.click(),"Block"===t&&(await n(50),document.querySelector('[data-testid="confirmationSheetConfirm"]')?.click()),await n(50)),history.back(),await n(10),!o)return!1;for(;!document.querySelector('[aria-label="Timeline: Reposts"]')&&!document.querySelector('[aria-label="Timeline: Verified Followers"]')&&!document.querySelector('[aria-label="Timeline: Followers"]')&&!document.querySelector('[aria-label="Timeline: List members"]');)await n(10);return!0},m=async()=>{let e=document.querySelector("[data-viewportview=true]")||document.documentElement,t=e.scrollTop,o=performance.now();for(;!c();){if(e.scrollTop+=100,e.scrollTop===t){if(performance.now()-o>=2e3)return}else o=performance.now();t=e.scrollTop,await n(1)}},f=async e=>{let t=0;for(;;){console.log("Starting script");await m();console.log("Scrolled");let l=c();if(l){let h="@"+l.href.split("/").pop();console.log("Located next account:",h);let o=await a(l,e);console.log("Successfully blocked the account",h),o&&t++,await s(),t%longPauseEvery===0&&(console.log("Taking a breath..."),await s(longPauseMin,longPauseMax))}else {alert(`${t} people ${e.toLowerCase()}ed.`);return}}};f("Block")})(); | |
// You can edit the pause durations if you like. Here are the defaults: | |
const shortPauseMin = 200, | |
shortPauseMax = 500, | |
longPauseEvery = 10, | |
longPauseMin = 1000, | |
longPauseMax = 2000; | |
// PSA: Please do not copy paste thing you saw internet randomly. | |
// Either investigate the code by yourself or use any GPT of your choice to understand what it does. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment