Skip to content

Instantly share code, notes, and snippets.

@kunalt4
Forked from adalinesimonian/block-the-blue.md
Last active May 5, 2023 00:55
Show Gist options
  • Save kunalt4/f4094d9d3e2c7e587440c4385dbb5544 to your computer and use it in GitHub Desktop.
Save kunalt4/f4094d9d3e2c7e587440c4385dbb5544 to your computer and use it in GitHub Desktop.
Block all verified Twitter accounts on screen

#BlockTheBlue

Table of Contents

What is this?

The script at the bottom will block verified Twitter accounts whose tweets are visible on the current page. This is a hacky fork of adalinesimonian's gist, which includes blocking only accounts you do not follow and who do not have more than 1M followers.

Screen capture

To run this script, paste it into your browser's developer tools console, usually accessible by pressing F12 or Cmd+Shift+I.

To stop the execution of this script for any reason, just refresh the page.

Bookmarklet

You can also pin this script to your browser's bookmarks bar, and click it to run it on any Twitter page. To do this, create a new bookmark, and paste the following code into the URL field:

javascript:(async()=>{const e=e=>new Promise(t=>{let o=document.querySelector(e);if(o)return void t(o);const l=new MutationObserver(()=>{(o=document.querySelector(e))&&(l.disconnect(),t(o))});l.observe(document.body,{childList:!0,subtree:!0})}),t=(()=>{let e=document.getElementById("visual-log");return e||((e=document.createElement("div")).id="visual-log",e.style.position="fixed",e.style.bottom="0",e.style.left="0",e.style.zIndex="9999",e.style.backgroundColor="white",e.style.padding="1em",e.style.border="1px solid black",e.style.borderRadius="1em",e.style.margin="1em",e.style.maxHeight="50vh",e.style.maxWidth="50vw",e.style.overflowY="scroll",e.style.fontFamily="monospace",document.body.appendChild(e),e)})(),o=e=>{const o=document.createElement("div");o.innerText=e,o.style.opacity="1",o.style.transition="opacity 1s",o.style.marginBottom="0.5em",t.appendChild(o),setTimeout(()=>{o.style.opacity="0",setTimeout(()=>{t.removeChild(o)},1e3)},4e3)};let l;for(;l=document.querySelector('[role="article"]:has(> * > * > * > * > * > * > * > * > * > * > * > * > * > * > * > [aria-label="Verified account"] > g > path:not([clip-rule="evenodd"])) [aria-label="More"]');){const t=[...l.closest('[role="article"]').querySelector('[data-testid="User-Name"]').querySelectorAll('[role="link"]:not(:has(time))')].map(e=>e.innerText).join(" ");l.click(),(await e('[data-testid="block"]')).click(),(await e('[data-testid="confirmationSheetConfirm"]')).click(),o(`Blocked ${t}`),await new Promise(e=>setTimeout(e,800))}o("No more verified accounts to block")})();

You can then click the bookmark to run the script on any Twitter page. Keep in mind that the copy of the script in the bookmark will not be updated alongside this file, so you may want to check back here for updates.

Screenshot

If you don't trust the above bookmarklet, you can create your own by copying the code below into a JavaScript minifier, such as the one at https://skalman.github.io/UglifyJS-online/, and then pasting the minified code into the URL field of a new bookmark with javascript: at the beginning.

Finding Verified Accounts

You can locate tweets by verified accounts by searching for -filter:verified filter:blue_verified in the Twitter search bar.

Firefox Users

You need to first enable the :has() CSS pseudo-class in about:config. Browse to about:config, accept the warning, and search for layout.css.has-selector.enabled. If it is set to false, double-click it to change it to true.

Screenshot
This is what you should see when your settings are correct.

Disclaimer

This script is provided as-is, and is not guaranteed to work. It may stop working at any time if Twitter changes their website. It is your responsibility to ensure that you are using this script in accordance with Twitter's terms of service. Otherwise, you may experience rate limiting, account lockouts, or other issues I cannot foresee.

The Script

;(async () => {
    const waitSeconds = 2 // How long to wait in between blocking accounts, in
    // seconds. If you're getting rate limited or logged out, try increasing this
    // time span so that you're not making too many requests too quickly.
    const waitForElement = (selector) =>
      new Promise((resolve) => {
        let element = document.querySelector(selector)
        if (element) {
          resolve(element)
          return
        }
        const observer = new MutationObserver(() => {
          element = document.querySelector(selector)
          if (element) {
            observer.disconnect()
            resolve(element)
          }
        })
        observer.observe(document.body, { childList: true, subtree: true })
      })
    const createVisualLog = () => {
      // Create a visual log to show what's happening
      let log = document.getElementById('visual-log')
      if (log) {
        return log
      }
      log = document.createElement('div')
      log.id = 'visual-log'
      log.style.position = 'fixed'
      log.style.bottom = '0'
      log.style.left = '0'
      log.style.zIndex = '9999'
      log.style.backgroundColor = 'white'
      log.style.padding = '1em'
      log.style.border = '1px solid black'
      log.style.borderRadius = '1em'
      log.style.margin = '1em'
      log.style.maxHeight = '50vh'
      log.style.maxWidth = '50vw'
      log.style.overflowY = 'scroll'
      log.style.fontFamily = 'monospace'
      document.body.appendChild(log)
      return log
    }

    const checkFollowers = (html) => {
        return html.innerText.includes('Followers')
    }

    const log = createVisualLog()
    const logMessage = (message) => {
      // add a message element that fades out and is removed after 5 seconds
      const messageElement = document.createElement('div')
      messageElement.innerText = message
      messageElement.style.opacity = '1'
      messageElement.style.transition = 'opacity 1s'
      messageElement.style.marginBottom = '0.5em'
      log.appendChild(messageElement)
      setTimeout(() => {
        messageElement.style.opacity = '0'
        setTimeout(() => {
          log.removeChild(messageElement)
        }, 1000)
      }, 4000)
    }
    let more
    while (
      (more = document.querySelector(
        '[role="article"]:has(> * > * > * > * > * > * > * > * > * > * > * > * > * > * > * > [aria-label="Verified account"] > g > path:not([clip-rule="evenodd"])) [aria-label="More"]'
      ))
    ) {
      userNameList = [
          ...more
            .closest('[role="article"]')
            .querySelector('[data-testid="User-Name"]')
            .querySelectorAll('[role="link"]:not(:has(time))')
        ]
      username = userNameList.map((el) => el.innerText).join(' ')
      twtUser = userNameList[0]
  
      twtUser.dispatchEvent(
          new MouseEvent(
              'mouseover', {
                  'view':window,
                  'bubbles':true,
                  'cancelable':true 
              }
          )
      )
      ;(await waitForElement('[data-testid="HoverCard"]'))
  
      await new Promise((resolve) => setTimeout(resolve, 1000))
      hoverCard = document.querySelector('[data-testid="HoverCard"]')
      hoverCardLinks = hoverCard.querySelectorAll('[role="link"]')
  
      checkMillion = Array.from(hoverCardLinks).filter(checkFollowers)[0].innerText.includes('M')
      checkFollowing = hoverCard.innerText.startsWith('Following')
  
      if(!checkMillion && !checkFollowing) {
          more.click()
          ;(await waitForElement('[data-testid="block"]')).click()
          ;(await waitForElement('[data-testid="confirmationSheetConfirm"]')).click()
          logMessage(`Blocked ${username}`)
      }
      else {
          logMessage(`Did not block ${username}`)
          //temporarily change label so as to not go into a loop
          twtUser.querySelector('[aria-label="Verified account"]').ariaLabel = "ItsOk"
      }
  
      twtUser.dispatchEvent(
          new MouseEvent(
              'mouseout', {
                  'view':window,
                  'bubbles':true,
                  'cancelable':true 
              }
          )
      )
      
      await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000))
    }
    logMessage('No more verified accounts to block')
  })()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment