-
Notifications
You must be signed in to change notification settings - Fork 0
/
removebots.user.js
216 lines (211 loc) · 9.54 KB
/
removebots.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// ==UserScript==
// @name Hide Bot Comments
// @namespace https://theusaf.org
// @version 1.14.0
// @description Removes comments made by bots on websites such as YouTube.
// @author theusaf
// @match https://www.youtube.com/**
// @match https://www.facebook.com/plugins/comments.php*
// @match https://www.facebook.com/plugins/feedback.php*
// @copyright 2022 theusaf
// @license MIT
// @grant none
// ==/UserScript==
const SITES = Object.freeze({
YOUTUBE: {
hostname: "www.youtube.com",
checks: [
// starts with too much whitespace
/^\s{2,}/,
// only links and other punctuation
/^(\s*@.+)?\s*(https:\/\/[^\s]+)(https:\/\/[^\s]+|\n.\s])+$/,
// all caps and a link
/^(\s*@.+)?\s*[A-Z\s\r\n!]*https:\/\/[^\s]+[A-Z\s\r\n!]*$/,
// A link and a random message afterwards
/^(\s*@.+)?\s*https:\/\/[^\s]+(\n|.|\s)*(Here'?s the full video.*?this video|It'll blow your mind\.|This is where (the )?world'?s first " ?Rick Rolled" started\.?|[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,
// word + link
/^(\s*@.+)?\s*(This|[Ww]ow!?|Last fight|Yo)\s*https:\/\/[^\s]+/,
// phrase + line + link
/((Here'?s the clip thank|^Link to the clip|Finally.*?the clip u all|is a brain burner|Let'?s be honest we|I have been waiting so long|by having this:|[iI]t.?s finally here|Finally.*is finally here|it is finally there|you .*will never love|[\u0401\u0451\u0410-\u044f,.:]{15,}|HOW STRONG IS KETTLE\?!|EXPOSED:|IS FREAK!|IS GARBAGE!{1,}|shocking truth|his subscribers|will stop watching|THE GAME|After watching this video you will never love).*|(yes\.?|deceives.*subscribers:\.{1,}|Finally it'?s here\.?(\s*YES)?)|^Link to the clip part 2|10,000.*?!|This is the clip u all.*:|Link to the clip\.? [Tt]hank me later|^Here you go|^yo\b|full vid -)(\n|\s)(\n|.)*https:\/\/[^\s]+/,
// various languages + line + link
/^[\p{Script=Cyrillic}\s!\.]*(\n|\s)(\n|.)*https:\/\/((www|m)\.)?youtu[^\s]+/iu,
// link + random "word"
/^(\s*@.+)?\s*https:\/\/[^\s]+\s*[a-z]+\s*$/,
// link with a star at the end??
/https:\/\/youtu.be\/\w+\*/,
// ...
/SWEET-GIRL|xvideos|specialdate|HOTGIRL|PRIVATE S\*X|over 18|Anna is a beautiful girl|adult porn videos/i,
// suspicious websites
/beautyzone\.\w+|[a-z]+\.online|\.cam|lust\.\w+|[a-z]+\.monster|\.host|\.uno|\.fun|asian\w*\.\w+|she.*\.online|\w*teen\.\w+/i,
// too many "-"
/-{5,}/,
// single, somewhat strange word
/^([ĤHh]ii|Ye|[Bb]ruhh|[Aa]awww?|🆁🆄🅷\s?!*)$/,
// common phrase
/Send(.|\n)*?direct message(.|\n)*?(won a gift|your prize)|BECOME THE MOST HATED|Thanks for watching..? messages|I'm not scared of ghosts,? and you\?|SCREAMING IN H[E3]LL BECAUSE MY.*?BETTER|I MADE.*VIDS|is bad i make better content|оп му с[hН]аппе[ІlL]|I MAKE.*CONTENT|my videos are better|^I.m better than|I UPLOAD.*VIDEO|I (make|made).*(video|content)| (● ´ω ` ●) ✨💕|[Oo]mg.*it.?s finally here|I POST [A-Z\s]*?VIDEOS|HATE COMMENT|I can read you mind brother|SPECIAL FOR YOU|l1ke my v1deo|small channel trying to grow| YouT\*ber|MY CONTENT|MY NAME|at my profile|My video|pedophile😱|MY WORLD RECORD|(^Yes.{0,5}$)|said this to a fan|Read my name|[Mm]y mom.*subscribers|r[\.\s]e[\.\s]a[\.\s]d[\.\s]? m[\.\s]y[\.\s]? n[\.\s]a[\.\s]m[\.\s]e|literally begging|MY VIDEOS?|my playlist|fucking cringe|[Dd][Oo][Nn].?[Tt] read my name/,
// replies to bots/about bots
/already bots|When the bots|@.*a bot|@Don'?t read my|@.*ok.*[Ii].*wont|remove bots|^(ro)?bot+$|with bots|hi bot|bots.*get worse|why are.*bots|bots.*everywhere|bot repl.*row|there are.{0,15}bots|oh god.*bots|report.*bots|so many.*?bots|holy bots|do nothing about bots|bots.*common/i,
// upside down chars
/[ㄥϛㄣƐᄅƖ⅄Λ∩┴ɹԀ˥ʞſפℲƎƆ∀ʎʍʌʇɹɯʞɾᴉɥƃɟǝɔɐ]/,
// just a single, weird character
/^.$/s,
// invisible characters
/[\u200e]/u,
(text) => {
const matches = text.match(/[\u{0E80}-\u{0EFF}]/gu)?.length ?? 0;
if (
matches / text.length > 0.5 &&
/Don.?t tran?slate|Do not tran?slate/i.test(text)
) {
return true;
}
},
(text) => {
const charSets = [
{
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
matchPercent: 0.4,
},
{
regex: /[ᴀʙᴄᴅᴇғɢʜɪᴊᴋʟᴍɴᴏᴘᴏ̨ʀsᴛᴜᴠᴡxʏᴢ\s]/g,
matchPercent: 0.5,
},
{
regex: /[\u{1D538}-\u{1D56B}\u{1D400}-\u{1D433}]/gu, // math letter symbols
matchPercent: 0.3,
},
];
for (const check of charSets) {
const { regex, matchPercent } = check,
matches = text.match(regex)?.length ?? 0;
if (matches / text.length > matchPercent && text.length > 10) {
return true;
}
}
},
// Username checks
(_, node) => {
const usernameNode = node.querySelector("#author-text"),
userImage = node.querySelector("#img"),
username = usernameNode.textContent.trim(),
BAD_NAMES = [
// remove
/^SUB FOR SUB$/,
],
HIDE_NAMES = [
// don't remove, just hide pic and name
];
for (const regex of BAD_NAMES) {
if (regex.test(username)) {
return true;
}
}
for (const regex of HIDE_NAMES) {
if (regex.test(username)) {
userImage.src = "data:application/svg+xml,<svg></svg>";
}
}
return false;
},
],
getCommentText(node) {
if (node.nodeName === "YTD-COMMENT-RENDERER") {
return node.querySelector("#content-text").textContent;
}
},
},
FACEBOOK_EMBED: {
hostname: "www.facebook.com",
checks: [
// "Easy cash" scams
/easy cash|earning money is very easy.*https?:\/\/|work online|real passive income|(making|paid|get) over \$?\d+k?|salary from home/s,
// Scammy manga sites
/(I liked it.*?recommend|try this manga.*?https?s:\/\/|you should try:|[Ss]hare a cartoon website|top [a-z]*?(comic|website)|there is no cost|try this one out|[Jj]ust read this|you [a-z\s]*?want [a-z\s]*?manga|(tons|a lot) of [a-z\s]*?man[gh][wu]?a|You can find the last part here|looking forward to seeing where this goes|YET ANOTHER RECOMMENDATION|enjoy another manga|I prefer this type of comic|hottest comics|Google led me|will love this one|I like this one: |FEE IS FREE|another [a-z\s]*?manga|WEBSITE[A-Z\s]*FREE|good read|must check this out|read more:|300 or more chapters|comics for free|website [a-z\s]*?manga:|favorite mange which I have read|\*{1,} SPOILER ALERT \*{1,}|FREE ACCESS|FREE (TO|FOR) READ).*(\n\s)*(https?:\/\/[^\s]+|\n.\s])+/,
/geoagiphy\.com|.giphy\.com/,
/(manga|story|site|website).*?:\s?(https?:\/\/[^\s]+|\n.\s])+$/,
// Other weird comments/scams
/look at a website|very popular .*?website|Amazon gift card/,
/^i love sex$/,
],
options: {
initialScan: () => {
return document.querySelectorAll(".clearfix");
},
},
getCommentText(node) {
if (node.classList?.contains("clearfix")) {
try {
return node?.lastElementChild.lastElementChild.lastElementChild
.firstElementChild.children[1].textContent;
} catch (err) {
return null;
}
}
},
},
}),
site = getCurrentSite(),
commentMutationListener = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
const text = site.getCommentText(node);
if (text) {
if (isCommentLikelyBotComment(text, site, node)) {
node.style.display = "none";
}
}
}
}
});
commentMutationListener.observe(document.body, {
subtree: true,
childList: true,
});
/**
* Determines whether a comment is likely spam.
*
* @param {string} text The comment's content
* @param {object} site The website the comment is from
* @param {Node} node
* @return {Boolean}
*/
function isCommentLikelyBotComment(text, site, node) {
for (const check of site.checks) {
if (typeof check === "function") {
if (check(text, node)) {
console.log("Filter Check Failed");
console.log(text);
return true;
}
} else {
// assume regex
if (check.test(text)) {
console.log("Regex Check Failed");
console.log(check);
console.log(text);
return true;
}
}
}
return false;
}
function getCurrentSite() {
for (let key in SITES) {
const site = SITES[key];
if (location.hostname === site.hostname) {
return site;
}
}
}
if (site.options?.initialScan) {
const items = site.options.initialScan();
for (const node of items) {
const text = site.getCommentText(node);
if (text) {
if (isCommentLikelyBotComment(text, site, node)) {
node.style.display = "none";
}
}
}
}