Block Promoted Tweets and Stuff

If twitter promotes their tweet, we'll block it, or your money back!

נכון ליום 24-07-2023. ראה הגרסה האחרונה.

// ==UserScript==
// @name           Block Promoted Tweets and Stuff
// @name:fr        Bloque les Gazouillis Sponsorisés et Tout Ça
// @namespace      Itsnotlupus Industries
// @match          https://twitter.com/*
// @grant          none
// @version        1.5
// @author         -
// @description    If twitter promotes their tweet, we'll block it, or your money back!
// @description:fr Si twitter promouvois leur gazouillage, on les bloque, ou remboursé!
// @license        MIT
// @require        https://greatest.deepsurf.us/scripts/468394-itsnotlupus-tiny-utilities/code/utils.js
// @require        https://unpkg.com/[email protected]/dist/moduleraid.umd.js
// ==/UserScript==
/*jshint esversion: 11 */
/*globals $$$: false */

(async ()=> {

  // English twitter strings we use to find the bits of page content we need.
  const strings = [ 'Verified', 'Promoted', 'More', 'Get Verified'];

  const i18n = { 'en': strings.reduce((o, v) => (o[v]=v,o), {}) };
  const lang = document.documentElement.lang;
  if (lang !== 'en') {
    // Translate those strings using Twitter's own data.
    // This means this script works with all languages Twitter supports.
    const mR = new moduleraid({ entrypoint: "webpackChunk_twitter_responsive_web", debug: false });
    const [[,twitterI18N]] = mR.findConstructor('knownLanguages');
    await twitterI18N.loadLanguage('en');
    const stringIds = strings.map(s=>Object.keys(twitterI18N).find(k => twitterI18N[k]===s));
    await twitterI18N.loadLanguage(lang);
    i18n[lang] = stringIds.map(id => twitterI18N[id]).reduce((o,v,i) => (o[strings[i]]=v,o), {});
  }

  const t = s => i18n[lang]?.[s] ?? s;

  // inject styles to hide elmo's upselling - respect yoself, don't buy a checkmark
  addStyles(`
  [aria-label="${t`Verified`}"] {
    display: none !important;
  }
  `);

  // auto-block promoters.
  (async function blockPromotedAccounts() {
    while (true) {
      const tweets = await untilDOM(()=>$$$(`//article[@role='article']/div/div/div/div/div/div/div/span[text()='${t`Promoted`}']/../../../../..`));
      for (const tweet of tweets) {
        const moreButton = tweet.querySelector(`[aria-label="${t`More`}"]`);
        if (moreButton) {
          console.log("Found a promoted Tweet!", tweet.innerText);
          moreButton.click();
          (await untilDOM('[data-testid="block"]')).click();
          (await untilDOM('[data-testid="confirmationSheetConfirm"]')).click();
          console.log("Blocked tweet promoter");
        }
      }
      // twitter is buggy, so blocking someone doesn't necessarily remove their tweets immediately. sleep on it.
      await sleep(500);
    }
  })();

  // remove "Get Verified" upsell in the right column
  (async function removeGetVerifiedBlock() {
    while (true) {
      (await untilDOM(() => $$$(`.//*[text()[contains(.,'${t`Get Verified`}')]]/../../..`)[0])).remove();
    }
  })();

})();