Better Twitter Monkey Edition

Low effort port of the Better Twitter Chrome Extension.

  1. // ==UserScript==
  2. // @name Better Twitter Monkey Edition
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description Low effort port of the Better Twitter Chrome Extension.
  6. // @author me, oslego
  7. // @match https://twitter.com/*
  8. // @grant none
  9. // @run-at document-start
  10. // ==/UserScript==
  11.  
  12. /*
  13. NOT MY WORK.
  14. Code ported over from here with minimal effort lol.
  15. https://github.com/oslego/better-twitter
  16. */
  17.  
  18. const userPrefs = {
  19. //CONFIGURE START - Flip the values from true/false depending if you want to enable the feature.
  20. "bt--nofame": {
  21. value: false,
  22. label: "No fame: Hide number of followers and following count",
  23. },
  24. "bt--nopopularity": {
  25. value: true,
  26. label: "No vanity: Hide number of tweet likes, retweets and replies",
  27. },
  28. "bt--nopromoted": {
  29. value: true,
  30. label: "Hide promoted tweets",
  31. },
  32. "bt--noretweets": {
  33. value: false,
  34. label: "Hide retweets"
  35. },
  36. "bt--nolikedtweets": {
  37. value: true,
  38. label: "Hide tweets liked by others"
  39. },
  40. "bt--notrends": {
  41. value: true,
  42. label: "Hide “Trends for you”",
  43. },
  44. "bt--nowtf": {
  45. value: true,
  46. label: "Hide “Who to follow”",
  47. },
  48. "bt--nofooter": {
  49. value: true,
  50. label: "Hide website footer",
  51. },
  52. //CONFIGURE END
  53. }
  54.  
  55. const contentCSS = `
  56. /* Hide promoted tweets */
  57. .bt--nopromoted [aria-label^="timeline" i][aria-label$="timeline" i] div[bt-promoted],
  58. .bt--nopromoted [aria-label^="timeline" i][aria-label$="tweets" i] div[bt-promoted] {
  59. display: none;
  60. }
  61.  
  62. /* Hide someone else's liked tweets showing in timelines */
  63. .bt--nolikedtweets [aria-label^="timeline" i][aria-label$="timeline" i] div[bt-likedtweet],
  64. .bt--nolikedtweets [aria-label^="timeline" i][aria-label$="tweets" i] div[bt-likedtweet] {
  65. display: none;
  66. }
  67.  
  68. /* Hide retweets */
  69. .bt--noretweets [aria-label^="timeline" i][aria-label$="timeline" i] div[bt-retweet],
  70. .bt--noretweets [aria-label^="timeline" i][aria-label$="tweets" i] div[bt-retweet] {
  71. display: none;
  72. }
  73.  
  74. /* Hide "Who to Follow" from users' timelines aside from search result timelines
  75. https://github.com/oslego/better-twitter/issues/12
  76. */
  77. .bt--nowtf [aria-label^="timeline" i][aria-label$="timeline" i]:not([aria-label~="search" i]) div[bt-wtf],
  78. .bt--nowtf [aria-label^="timeline" i][aria-label$="tweets" i] div[bt-wtf] {
  79. display: none;
  80. }
  81.  
  82. /* Find "promoted" icons, then mark their ancestor <div> as a promoted tweet */
  83. .bt--nopromoted path[d^="M20.75"] {
  84. animation: bt-marker-promoted 0s 1;
  85. }
  86. @keyframes bt-marker-promoted { to { outline-color: inherit } }
  87.  
  88. /* Find "retweeted" icons, then mark their ancestor <div> as a retweet */
  89. .bt--noretweets path[d^="M23.615 15.477c-"] {
  90. animation: bt-marker-retweet 0s 1;
  91. }
  92. @keyframes bt-marker-retweet { to { outline-color: inherit } }
  93.  
  94. /* Find "liked tweet" icons next to "Someone liked" annotations, then mark their ancestor <div> as a retweet
  95. The path for "filled heart" is identical to the one used when you yourself like a tweet.
  96. When the icon is used in context of the "Someone liked" annotation,
  97. the host <svg> is an only child of its parent so we can differentiate on that. This is fragile.
  98. FIXME: Find a way to match the tweet annotation container for "Someone liked" or "Someone retweeted".
  99. */
  100. .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"] {
  101. animation: bt-marker-likedtweet 0s 1;
  102. }
  103. @keyframes bt-marker-likedtweet { to { outline-color: inherit } }
  104.  
  105. /* Find "Follow" buttons, then mark their ancestor <div> as a who-to-follow prompt */
  106. .bt--nowtf [data-testid$="-follow"] {
  107. animation: bt-marker-wtf 0s 1;
  108. }
  109. @keyframes bt-marker-wtf { to { outline-color: inherit } }
  110.  
  111. /* Find the "Who to follow" container from the sidebar */
  112. .bt--nowtf [aria-label*="who to follow" i]{
  113. animation: bt-marker-wtf-sidebar 0s 1;
  114. }
  115. @keyframes bt-marker-wtf-sidebar { to { outline-color: inherit } }
  116.  
  117. .bt--nowtf .bt-marker-wtf-sidebar {
  118. display: none !important;
  119. }
  120.  
  121. /* Hide "Trends for you" box */
  122. .bt--notrends [aria-label*="trending" i] {
  123. display: none !important;
  124. }
  125.  
  126. /* Hide "Footer" box */
  127. .bt--nofooter [aria-label="footer" i] {
  128. display: none !important;
  129. }
  130.  
  131. /* Hide tweet reply count */
  132. .bt--nopopularity [data-testid="reply"] span {
  133. display: none !important;
  134. }
  135.  
  136. /* Hide tweet retweet count */
  137. .bt--nopopularity [href$="/retweets"] span,
  138. .bt--nopopularity [data-testid="retweet"] span,
  139. .bt--nopopularity [data-testid="unretweet"] span {
  140. display: none !important;
  141. }
  142.  
  143. /* Hide tweet like count */
  144. .bt--nopopularity [data-testid="like"] span,
  145. .bt--nopopularity [data-testid="unlike"] span,
  146. /* Hide the likes count on a single tweet page, but not the Likes tab on the user profile page */
  147. .bt--nopopularity [href$="/likes"]:not([role="tab"]) span {
  148. display: none !important;
  149. }
  150.  
  151. /* Hide all profile stats from user cards */
  152. .bt--nofame [href$="/following"],
  153. .bt--nofame [href$="/followers"] {
  154. display: none !important;
  155. }
  156. `;
  157.  
  158.  
  159.  
  160.  
  161. function applyPrefs() {
  162. Object.entries(userPrefs).forEach(([id, pref]) => {
  163. document.documentElement.classList.toggle(id, pref.value);
  164. })
  165. }
  166.  
  167. const addGlobalStyle = (css) => {
  168. var head, style;
  169. head = document.getElementsByTagName('head')[0];
  170. if (!head) { return; }
  171. style = document.createElement('style');
  172. style.type = 'text/css';
  173. style.innerHTML = css;
  174. head.appendChild(style);
  175. }
  176.  
  177.  
  178. (function() {
  179. 'use strict';
  180.  
  181. addGlobalStyle(contentCSS);
  182. applyPrefs();
  183. document.addEventListener('animationstart', (e) => {
  184. switch (e.animationName) {
  185. case "bt-marker-likedtweet":
  186. e.target.closest('div:not([class])').setAttribute('bt-likedtweet', true)
  187. break;
  188. case "bt-marker-promoted":
  189. e.target.closest('div:not([class])').setAttribute('bt-promoted', true)
  190. break;
  191. case "bt-marker-retweet":
  192. e.target.closest('div:not([class])').setAttribute('bt-retweet', true)
  193. break;
  194. case "bt-marker-wtf-sidebar":
  195. // Mark the container's parent for the "Who To Follow" in the sidebar.
  196. e.target.parentNode.classList.add(e.animationName)
  197. break;
  198. case "bt-marker-wtf":
  199. const container = e.target.closest('div:not([class])');
  200. container.setAttribute('bt-wtf', true);
  201.  
  202. // If found, mark the container for the "Who to Follow" heading
  203. const prevContainer = container.previousElementSibling;
  204. if (prevContainer.querySelector('h2')) {
  205. prevContainer.setAttribute('bt-wtf', true);
  206. }
  207.  
  208. // If found, mark the container for "show more" link
  209. const nextContainer = container.nextElementSibling;
  210. if (nextContainer.querySelector('[href^="/i/connect_people"]')) {
  211. nextContainer.setAttribute('bt-wtf', true);
  212. }
  213. break;
  214.  
  215. }
  216. });
  217. })();
  218.  
  219.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址