Twitter: view more replies and remove shit

View more replies and remove shit from twitter

当前为 2021-07-23 提交的版本,查看 最新版本

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