Greasy Fork is available in English.

Better Twitter Monkey Edition

Low effort port of the Better Twitter Chrome Extension.

// ==UserScript==
// @name         Better Twitter Monkey Edition
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  Low effort port of the Better Twitter Chrome Extension.
// @author       me, oslego
// @match        https://twitter.com/*
// @grant        none
// @run-at document-start
// ==/UserScript==

/*
NOT MY WORK.
Code ported over from here with minimal effort lol.
https://github.com/oslego/better-twitter
*/

const userPrefs = {
    //CONFIGURE START - Flip the values from true/false depending if you want to enable the feature.
  "bt--nofame": {
    value: false,
    label: "No fame: Hide number of followers and following count",
  },
  "bt--nopopularity": {
    value: true,
    label: "No vanity: Hide number of tweet likes, retweets and replies",
  },
  "bt--nopromoted": {
    value: true,
    label: "Hide promoted tweets",
  },
  "bt--noretweets": {
    value: false,
    label: "Hide retweets"
  },
  "bt--nolikedtweets": {
    value: true,
    label: "Hide tweets liked by others"
  },
  "bt--notrends": {
    value: true,
    label: "Hide “Trends for you”",
  },
  "bt--nowtf": {
    value: true,
    label: "Hide “Who to follow”",
  },
  "bt--nofooter": {
    value: true,
    label: "Hide website footer",
  },
    //CONFIGURE END
}

const contentCSS = `
/* Hide promoted tweets */
.bt--nopromoted [aria-label^="timeline" i][aria-label$="timeline" i] div[bt-promoted],
.bt--nopromoted [aria-label^="timeline" i][aria-label$="tweets" i] div[bt-promoted] {
	display: none;
}

/* Hide someone else's liked tweets showing in timelines */
.bt--nolikedtweets [aria-label^="timeline" i][aria-label$="timeline" i] div[bt-likedtweet],
.bt--nolikedtweets [aria-label^="timeline" i][aria-label$="tweets" i] div[bt-likedtweet] {
	display: none;
}

/* Hide retweets */
.bt--noretweets [aria-label^="timeline" i][aria-label$="timeline" i] div[bt-retweet],
.bt--noretweets [aria-label^="timeline" i][aria-label$="tweets" i] div[bt-retweet] {
	display: none;
}

/* Hide "Who to Follow" from users' timelines aside from search result timelines
	 https://github.com/oslego/better-twitter/issues/12
*/
.bt--nowtf [aria-label^="timeline" i][aria-label$="timeline" i]:not([aria-label~="search" i]) div[bt-wtf],
.bt--nowtf [aria-label^="timeline" i][aria-label$="tweets" i] div[bt-wtf] {
	display: none;
}

/* Find "promoted" icons, then mark their ancestor <div> as a promoted tweet */
.bt--nopromoted path[d^="M20.75"] {
	animation: bt-marker-promoted 0s 1;
}
@keyframes bt-marker-promoted { to { outline-color: inherit } }

/* Find "retweeted" icons, then mark their ancestor <div> as a retweet */
.bt--noretweets path[d^="M23.615 15.477c-"] {
	animation: bt-marker-retweet 0s 1;
}
@keyframes bt-marker-retweet { to { outline-color: inherit } }

/* Find "liked tweet" icons next to "Someone liked" annotations, then mark their ancestor <div> as a retweet
	 The  path for "filled heart" is identical to the one used when you yourself like a tweet.
	 When the icon is used in context of the "Someone liked" annotation,
	 the host <svg> is an only child of its parent so we can differentiate on that. This is fragile.
	 FIXME: Find a way to match the tweet annotation container for "Someone liked" or "Someone retweeted".
*/
.bt--nolikedtweets svg:only-child path[d="M12 21.638h-.014C9.403 21.59 1.95 14.856 1.95 8.478c0-3.064 2.525-5.754 5.403-5.754 2.29 0 3.83 1.58 4.646 2.73.814-1.148 2.354-2.73 4.645-2.73 2.88 0 5.404 2.69 5.404 5.755 0 6.376-7.454 13.11-10.037 13.157H12z"] {
	animation: bt-marker-likedtweet 0s 1;
}
@keyframes bt-marker-likedtweet { to { outline-color: inherit } }

/* Find "Follow" buttons, then mark their ancestor <div> as a who-to-follow prompt */
.bt--nowtf [data-testid$="-follow"] {
	animation: bt-marker-wtf 0s 1;
}
@keyframes bt-marker-wtf { to { outline-color: inherit } }

/* Find the "Who to follow" container from the sidebar */
.bt--nowtf [aria-label*="who to follow" i]{
	animation: bt-marker-wtf-sidebar 0s 1;
}
@keyframes bt-marker-wtf-sidebar { to { outline-color: inherit } }

.bt--nowtf .bt-marker-wtf-sidebar {
	display: none !important;
}

/* Hide "Trends for you" box */
.bt--notrends [aria-label*="trending" i] {
	display: none !important;
}

/* Hide "Footer" box */
.bt--nofooter [aria-label="footer" i] {
	display: none !important;
}

/* Hide tweet reply count */
.bt--nopopularity [data-testid="reply"] span {
	display: none !important;
}

/* Hide tweet retweet count */
.bt--nopopularity [href$="/retweets"] span,
.bt--nopopularity [data-testid="retweet"] span,
.bt--nopopularity [data-testid="unretweet"] span {
  display: none !important;
}

/* Hide tweet like count */
.bt--nopopularity [data-testid="like"] span,
.bt--nopopularity [data-testid="unlike"] span,
/* Hide the likes count on a single tweet page, but not the Likes tab on the user profile page */
.bt--nopopularity [href$="/likes"]:not([role="tab"]) span {
	display: none !important;
}

/* Hide all profile stats from user cards */
.bt--nofame [href$="/following"],
.bt--nofame [href$="/followers"] {
	display: none !important;
}
`;




function applyPrefs() {
  Object.entries(userPrefs).forEach(([id, pref]) => {
    document.documentElement.classList.toggle(id, pref.value);
  })
}

const addGlobalStyle = (css) => {
    var head, style;
    head = document.getElementsByTagName('head')[0];
    if (!head) { return; }
    style = document.createElement('style');
    style.type = 'text/css';
    style.innerHTML = css;
    head.appendChild(style);
}


(function() {
    'use strict';

    addGlobalStyle(contentCSS);
    applyPrefs();
    document.addEventListener('animationstart', (e) => {
        switch (e.animationName) {
            case "bt-marker-likedtweet":
                e.target.closest('div:not([class])').setAttribute('bt-likedtweet', true)
                break;
            case "bt-marker-promoted":
                e.target.closest('div:not([class])').setAttribute('bt-promoted', true)
                break;
            case "bt-marker-retweet":
                e.target.closest('div:not([class])').setAttribute('bt-retweet', true)
                break;
            case "bt-marker-wtf-sidebar":
                // Mark the container's parent for the "Who To Follow" in the sidebar.
                e.target.parentNode.classList.add(e.animationName)
                break;
            case "bt-marker-wtf":
                const container = e.target.closest('div:not([class])');
                container.setAttribute('bt-wtf', true);

                // If found, mark the container for the "Who to Follow" heading
                const prevContainer = container.previousElementSibling;
                if (prevContainer.querySelector('h2')) {
                    prevContainer.setAttribute('bt-wtf', true);
                }

                // If found, mark the container for "show more" link
                const nextContainer = container.nextElementSibling;
                if (nextContainer.querySelector('[href^="/i/connect_people"]')) {
                    nextContainer.setAttribute('bt-wtf', true);
                }
                break;

        }
    });
})();