Twitter: view more replies and remove useless sections

View more replies and remove shit from twitter

当前为 2021-12-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Twitter: view more replies and remove useless sections
  3. // @description View more replies and remove shit from twitter
  4. // @author MK
  5. // @namespace max44
  6. // @homepage https://greasyfork.org/en/users/309172-max44
  7. // @include https://twitter.com/*
  8. // @include https://mobile.twitter.com/*
  9. // @icon https://www.google.com/s2/favicons?domain=twitter.com
  10. // @version 1.3.5
  11. // @license MIT
  12. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
  13. // @grant none
  14. // @run-at document-idle
  15. // ==/UserScript==
  16.  
  17. (function () {
  18. 'use strict';
  19.  
  20. function findAndClick(selector, observer) {
  21. const elem = document.querySelector(selector);
  22. if (elem != null) {
  23. elem.click();
  24. observer.disconnect();
  25. }
  26. }
  27.  
  28. function isLink(element) {
  29. return element.getAttribute("role") === "link";
  30. }
  31.  
  32. function isParentLink(element, parentN) {
  33. if (isLink(element)) return true;
  34.  
  35. for (let i = 0; i <= parentN; i++) {
  36. element = element.parentElement;
  37. if (isLink(element)) return true;
  38. }
  39.  
  40. return false;
  41. }
  42.  
  43. const config = {childList: true, subtree: true};
  44. // Replies list
  45. const repliesSelector = "[aria-labelledby^='accessible-list'][role='region'][class='css-1dbjc4n']";
  46. // "View more replies" button on preview tweets
  47. const viewMoreSelector = "[href*='i/status/']" +
  48. "[role='link']" +
  49. "[data-focusable='true']" +
  50. "[class^='css-4rbku5 css-18t94o4 css-1dbjc4n r-1loqt21 r-1ny4l3l'][class$='r-o7ynqc r-6416eg']" +
  51. " > div > span";
  52. // "Show additional replies, including those that may contain offensive content" button
  53. const offensiveSelector = "div[role='button']" +
  54. "[tabindex='0']" +
  55. "[class^='css-18t94o4 css-1dbjc4n r-1niwhzg r-42olwf r-sdzlij r-1phboty r-rs99b7'][class$='r-o7ynqc r-6416eg r-lrvibr']" +
  56. " > div > span > span";
  57. // "Show replies" and "Show more replies" buttons
  58. const moreRepliesSelector = "div[role='button']" +
  59. "[tabindex='0']" +
  60. "[class^='css-18t94o4 css-1dbjc4n r-1777fci r-1pl7oy7 r-1ny4l3l r-o7ynqc r-6416eg r-13qz1uu']" +
  61. " > div > div > span";
  62. //"div[class='css-1dbjc4n r-16y2uox r-1wbh5a2 r-1777fci'] " +
  63. //"div[class^='css-901oao'][class$='r-qvutc0'][dir='auto'] " +
  64. //"span[class^='css-901oao css-16my406'][class$='r-bcqeeo r-qvutc0']";
  65. //const refreshAfterFaultSelector = "div[role='button']" +
  66. // "[tabindex='0']" +
  67. // "[class^='css-18t94o4 css-1dbjc4n r-1kihuf0']" +
  68. // "[class$='r-42olwf r-sdzlij r-1phboty r-rs99b7 r-2o02ov r-ero68b r-vkv6oe r-1ny4l3l r-1fneopy r-o7ynqc r-6416eg r-lrvibr']";// " +
  69. // //"> div > span > span";
  70.  
  71. setTimeout(function () {
  72. // For preview tweets, tweets that are opened from external sources may has a special format where only a few replies are shown and the rest are replaced
  73. // by a "More Tweets" section that contains popular tweets from random accounts that may or may not be related to the previewed tweet
  74. const previewSelector = "[data-testid='primaryColumn'] " +
  75. "[class='css-1dbjc4n r-yfoy6g r-18bvks7 r-1ljd8xs r-13l2t4g r-1phboty r-1jgb5lz r-11wrixw r-61z16t r-1ye8kvj r-13qz1uu r-184en5c']";
  76. const preview = document.querySelector(previewSelector);
  77.  
  78. if (preview != null) {
  79. const viewMore = document.querySelector(viewMoreSelector);
  80.  
  81. if (viewMore != null) viewMore.click();
  82. }
  83. }, 3000);
  84.  
  85. const rootCallback = function (mutationsList, observer) {
  86. const repliesNode = document.querySelector(repliesSelector);
  87.  
  88. if (repliesNode != null) {
  89. const offensiveObserver = new MutationObserver(offensiveCallback);
  90. const moreRepliesObserver = new MutationObserver(moreRepliesCallback);
  91. //const refreshAfterFaultObserver = new MutationObserver(refreshAfterFaultCallback);
  92. offensiveObserver.observe(repliesNode, config);
  93. moreRepliesObserver.observe(repliesNode, config);
  94. //refreshAfterFaultObserver.observe(repliesNode, config);
  95. }
  96.  
  97. //Remove useless sections
  98. $( "span:contains('Who to follow')" ).parent().parent().parent().parent().parent().hide().next().hide().next().hide().next().hide().next().hide().next().hide();
  99. $( "span:contains('Topics to follow')" ).parent().parent().parent().parent().parent().hide().next().hide().next().hide();
  100. $( "article span:contains('Promoted')" ).parent().parent().parent().parent().parent().hide().next().hide().next().hide();
  101. $( "span:contains('Promoted by')" ).parent().parent().parent().parent().hide().next().hide().next().hide();
  102. $( "span:contains('Promoted Tweet')" ).parent().parent().parent().hide();
  103. $( "span:contains('Promoted')" ).parent().parent().parent().parent().hide();
  104. $( "span:contains('Trends for you')" ).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().hide();
  105. $( "span:contains('Expand your timeline with Topics')" ).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().hide();
  106. $( "span:contains('Discover new Lists')" ).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().hide();
  107. //-----$( "div[aria-label='Set as not interested']" ).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().remove();
  108. $( "div[aria-label='Set as not interested']" ).parent().parent().parent().parent().parent().parent().parent().hide();
  109. $( "span:contains('Open app')" ).parent().parent().hide();
  110. /*$( "span:contains('Who to follow')" ).parent().parent().parent().parent().parent().hide().next().hide().next().hide().next().hide().next().hide().next().hide();
  111. $( "span:contains('Topics to follow')" ).parent().parent().parent().parent().parent().hide().next().hide().next().hide().next().hide();
  112. $( "article span:contains('Promoted')" ).parent().parent().parent().parent().parent().hide().next().hide().next().hide().next().hide();
  113. $( "span:contains('Promoted by')" ).parent().parent().parent().parent().hide().next().hide().next().hide().next().hide();
  114. $( "span:contains('Promoted Tweet')" ).parent().parent().parent().parent().hide();
  115. $( "span:contains('Promoted')" ).parent().parent().parent().parent().parent().hide();
  116. $( "span:contains('Trends for you')" ).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().hide();
  117. $( "span:contains('Expand your timeline with Topics')" ).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().hide();
  118. $( "span:contains('Discover new Lists')" ).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().hide();
  119. //-----$( "div[aria-label='Set as not interested']" ).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().remove();
  120. $( "div[aria-label='Set as not interested']" ).parent().parent().parent().parent().parent().parent().parent().parent().remove();
  121. $( "span:contains('Open app')" ).parent().parent().parent().hide();*/
  122. };
  123.  
  124. const offensiveCallback = function (mutationsList, observer) {
  125. findAndClick(offensiveSelector, observer);
  126. };
  127.  
  128. const moreRepliesCallback = function (mutationsList, observer) {
  129. findAndClick(moreRepliesSelector, observer);
  130. /*const moreRepliesNodes = document.querySelectorAll(moreRepliesSelector);
  131.  
  132. for (let elem of moreRepliesNodes) {
  133. if (isParentLink(elem, 4)) continue;
  134. elem.click();
  135. }*/
  136. };
  137.  
  138. //const refreshAfterFaultCallback = function (mutationsList, observer) {
  139. // findAndClick(refreshAfterFaultSelector, observer);
  140. //};
  141.  
  142. const rootNode = document.querySelector("#react-root");
  143. if (rootNode != null) {
  144. const rootObserver = new MutationObserver(rootCallback);
  145. rootObserver.observe(rootNode, config);
  146. }
  147.  
  148. })();