Created
January 14, 2026 09:45
-
-
Save behnamazimi/2736163efb6cbd2362acae1c503a0f35 to your computer and use it in GitHub Desktop.
Find non-followers on X
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
| // Highlights accounts you follow that don't follow you back on X | |
| // Run in browser console while on your Following list | |
| const CELL_SELECTOR = 'div[data-testid="cellInnerDiv"]'; | |
| const FOLLOWS_TEXT = 'Follows you'; | |
| const nonFollowers = new Set(); | |
| let lastScrollHeight = 0; | |
| let stableCount = 0; | |
| function extractUsername(cell) { | |
| const link = cell.querySelector('a[href^="/"]'); | |
| return link?.pathname.slice(1) || null; | |
| } | |
| function updateCell(cell) { | |
| const text = cell.innerText; | |
| const username = extractUsername(cell); | |
| if (!username) return; | |
| if (!text.includes(FOLLOWS_TEXT)) { | |
| nonFollowers.add(username); | |
| } | |
| if (nonFollowers.has(username)) { | |
| cell.style.border = '2px solid red'; | |
| } else { | |
| cell.style.border = ''; | |
| } | |
| } | |
| async function scrollToEnd() { | |
| return new Promise(resolve => { | |
| const interval = setInterval(() => { | |
| const scrollHeight = document.body.scrollHeight; | |
| const viewportHeight = window.innerHeight; | |
| const currentPosition = window.scrollY; | |
| const atBottom = currentPosition + viewportHeight >= scrollHeight - 10; | |
| if (atBottom) { | |
| if (scrollHeight === lastScrollHeight) { | |
| stableCount++; | |
| if (stableCount >= 3) { | |
| clearInterval(interval); | |
| window.scrollTo(0, 0); | |
| console.log(`✓ Found ${nonFollowers.size} non-followers`); | |
| console.log('Export: copy(Array.from(nonFollowers).sort())'); | |
| resolve(); | |
| } | |
| } else { | |
| stableCount = 0; | |
| lastScrollHeight = scrollHeight; | |
| window.scrollBy(0, viewportHeight); | |
| } | |
| } else { | |
| window.scrollBy(0, viewportHeight); | |
| } | |
| }, 200); | |
| }); | |
| } | |
| new MutationObserver(mutations => { | |
| mutations.forEach(m => { | |
| if (m.type === 'childList') { | |
| m.addedNodes.forEach(node => { | |
| if (node.nodeType !== 1) return; | |
| if (node.matches?.(CELL_SELECTOR)) { | |
| updateCell(node); | |
| } else { | |
| node.querySelectorAll?.(CELL_SELECTOR).forEach(updateCell); | |
| } | |
| }); | |
| } else { | |
| const cell = m.target.closest?.(CELL_SELECTOR); | |
| if (cell) updateCell(cell); | |
| } | |
| }); | |
| }).observe(document.body, { | |
| childList: true, | |
| subtree: true, | |
| characterData: true, | |
| attributes: true | |
| }); | |
| scrollToEnd(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment