Hide Bot Comments

Removes comments made by bots on websites such as YouTube.

Fra 21.03.2022. Se den seneste versjonen.

  1. // ==UserScript==
  2. // @name Hide Bot Comments
  3. // @namespace https://theusaf.org
  4. // @version 1.6.3
  5. // @description Removes comments made by bots on websites such as YouTube.
  6. // @author theusaf
  7. // @match https://www.youtube.com/**
  8. // @copyright 2022 theusaf
  9. // @license MIT
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. const SITES = Object.freeze({
  14. YOUTUBE: [
  15. // starts with too much whitespace
  16. /^\s{2,}/,
  17. // only links and other punctuation
  18. /^(\s*@.+)?\s*(https:\/\/[^\s]+)(https:\/\/[^\s]+|\n.\s])+$/,
  19. // all caps and a link
  20. /^(\s*@.+)?\s*[A-Z\s\r\n!]*https:\/\/[^\s]+[A-Z\s\r\n!]*$/,
  21. // A link and a random message afterwards
  22. /^(\s*@.+)?\s*https:\/\/[^\s]+(\n|.|\s)*(It'll blow your mind\.|[dD]on'?t [mM]iss|Bots for u|Finally|💜|fax|only until|Bots are|:]|I found it :|Do not miss this|:\)|Ye[sp] ¤? (true|exactly)|(...?$))/i,
  23. // word + link
  24. /^(\s*@.+)?\s*(This|[Ww]ow!?)\s*https:\/\/[^\s]+/,
  25. // phrase + line + link
  26. /(Finally it's here\.?|deceives.*subscribers:\.{1,}|[\u0401\u0451\u0410-\u044f,.:]{15,}.*|EXPOSED:|IS FREAK!|IS GARBAGE!{1,}|shocking truth.*|his subscribers.*|will stop watching.*|yes\.?|THE GAME.*|After watching this video you will never love.*)(\n|\s)(\n|.)*https:\/\/[^\s]+/,
  27. // link + random "word"
  28. /^(\s*@.+)?\s*https:\/\/[^\s]+\s*[a-z]+\s*$/,
  29. // link with a star at the end??
  30. /https:\/\/youtu.be\/\w+\*/,
  31. // ...
  32. /PRIVATE S\*X|over 18|Anna is a beautiful girl/i,
  33. // suspicious websites
  34. /beautyzone\.\w+|\.cam|lust\.\w+|\.host|asian\w*\.\w+|\w*teen\.\w+/i,
  35. // too many "-"
  36. /-{5,}/,
  37. // single, somewhat strange word
  38. /^(Hii|Ye|Bruhh|Aawww?)$/,
  39. // common phrase
  40. / (● ´ω ●) ✨💕|I can read you mind brother|SPECIAL FOR YOU|l1ke my v1deo|small channel trying to grow| YouT\*ber|MY CONTENT|My video|pedophile😱|MY WORLD RECORD|(^Yes.{0,5}$)|said this to a fan|Read my name|[Mm]y mom.*subscribers|literally begging|MY VIDEOS?|my playlist|fucking cringe|[Dd][Oo][Nn]'?[Tt] read my name/,
  41. // replies to bots
  42. /@Don'?t read my|^(ro)?bot+$/i,
  43. // upside down chars
  44. /[ㄥϛㄣƐᄅƖ⅄Λ∩┴ɹԀ˥ʞſפℲƎƆ∀ʎʍʌʇɹɯʞɾᴉɥƃɟǝɔɐ]/,
  45. // just a single, weird character
  46. /^.$/,
  47. (text) => {
  48. const charSets = [
  49. {
  50. regex: /[\u{fe27}-\u{fe2f}\u{1df5}-\u{1dff}\u{1dc0}-\u{1de6}\u{1ab0}-\u{1abe}\u{0300}-\u{0333}\u{0339}-\u{033f}\u{0346}-\u{034a}\u{034b}-\u{034e}\u{0350}-\u{0357}\u{0358}-\u{035b}]/gu, // weird combining characters
  51. matchPercent: 0.4
  52. },
  53. {
  54. regex: /[ᴀʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘᴏ̨ʀsᴛᴜᴠᴡxʏᴢ\s]/g,
  55. matchPercent: 0.5
  56. },
  57. {
  58. regex: /[\u{1D538}-\u{1D56B}\u{1D400}-\u{1D433}]/gu, // math letter symbols
  59. matchPercent: 0.3
  60. },
  61. ];
  62. for (const check of charSets) {
  63. const { regex, matchPercent } = check,
  64. matches = text.match(regex)?.length ?? 0;
  65. if (matches / text.length > matchPercent && text.length > 10) {
  66. return true;
  67. }
  68. }
  69. }
  70. ]
  71. }),
  72. site = getCurrentSite(),
  73. commentMutationListener = new MutationObserver((mutations) => {
  74. for (const mutation of mutations) {
  75. for (const node of mutation.addedNodes) {
  76. const text = getCommentText(node, site);
  77. if (text) {
  78. if (isCommentLikelyBotComment(text, site)) {
  79. node.style.display = "none";
  80. }
  81. }
  82. }
  83. }
  84. });
  85.  
  86. commentMutationListener.observe(document.body, {
  87. subtree: true,
  88. childList: true
  89. });
  90.  
  91. /**
  92. * Determines whether a comment is likely spam.
  93. *
  94. * @param {String} text The comment's content
  95. * @param {Object} site The website the comment is from
  96. * @return {Boolean}
  97. */
  98. function isCommentLikelyBotComment(text, siteChecks) {
  99. for (const check of siteChecks) {
  100. if (typeof check === "function") {
  101. if (check(text)) {
  102. console.log("Filter Check Failed");
  103. console.log(text);
  104. return true;
  105. }
  106. } else {
  107. // assume regex
  108. if (check.test(text)) {
  109. console.log("Regex Check Failed");
  110. console.log(check);
  111. console.log(text);
  112. return true;
  113. }
  114. }
  115. }
  116. return false;
  117. }
  118.  
  119. function getCommentText(node, site) {
  120. switch (site) {
  121. case SITES.YOUTUBE: {
  122. if (node.nodeName === "YTD-COMMENT-RENDERER") {
  123. return node.querySelector("#content-text").textContent;
  124. }
  125. }
  126. }
  127. return null;
  128. }
  129.  
  130. function getCurrentSite() {
  131. switch (location.hostname) {
  132. case "www.youtube.com": {
  133. return SITES.YOUTUBE;
  134. }
  135. }
  136. }