-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdoorman.user.js
330 lines (283 loc) · 11 KB
/
doorman.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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// ==UserScript==
// @name Doorman - Imposter Helper
// @namespace https://leoverto.github.io
// @version 1.7
// @author Leo Verto
// @include https://gremlins-api.reddit.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addValueChangeListener
// @updateurl https://github.com/LeoVerto/doorman/raw/master/doorman.user.js
// @require https://github.com/LeoVerto/doorman/raw/master/doorman-lib.js?v=1.7
// ==/UserScript==
const VERSION = "1.7";
const SUBMIT_ABRA_URL = "https://librarian.abra.me/submit";
const SUBMIT_SPACESCIENCE_URL = "https://spacescience.tech/api.php";
function setState(note, hint, state) {
if (state === "") {
return;
}
// State conflict
if (hint.hasAttribute("state") && hint.getAttribute("state") !== state && !hint.hasAttribute("overwriteable")) {
state = "conflict";
}
if (state === "bot") {
note.setAttribute("style", "background-color: green;");
} else if (state === "human") {
note.setAttribute("style", "background-color: darkred;");
} else if (state === "maybe_human") {
note.setAttribute("style", "background-color: rgba(139, 00, 00, 50%);");
// State conflict
} else {
note.setAttribute("style", "background-color: orange;");
hint.textContent("Database conflict!");
}
hint.setAttribute("state", state);
}
function setHint(note, text, state="", overwriteable=false) {
let hint = note.getElementsByClassName("doorman-hint")[0];
// Hint tag does not already exist
if (!hint) {
hint = document.createElement("i");
hint.setAttribute("class", "doorman-hint");
// Set overwriteable attribute so we can check later
if (overwriteable) {
hint.setAttribute("overwriteable", "");
}
setState(note, hint, state);
note.appendChild(hint);
hint.textContent = text;
// Only overwrite if previously set as overwriteable
} else if (hint.hasAttribute("overwriteable")) {
hint.textContent = text;
setState(note, hint, state);
}
/*// Add to message
} else {
let regex = /\(.*\)/
hint.textContent = `(${regex.exec(hint.textContent)}, ${text})`;
setState(note, hint, state);
}*/
}
function appendHint(note, text) {
let hint = note.getElementsByClassName("doorman-hint")[0];
if (hint) {
hint.textContent += ", " + text;
} else {
setHint(note, text, "", true);
}
}
function getAnswers() {
var notes = document.getElementsByTagName("gremlin-note");
if (notes) {
var answers = [];
for (let note of notes) {
let id = note.getAttribute("id");
let msg = note.getAttribute("aria-label").substr(19);
answers.push({id: id, msg: msg});
}
return answers;
}
}
async function processAnswers(answers) {
let notes = document.getElementsByTagName("gremlin-note");
if (notes.length > 0) {
let abra = await checkExistingAbra(Object.values(answers.map(x => x.msg)))
.catch(error => console.log('error', error));
let promises = [];
for (let i = 0; i < notes.length; i++) {
// Handle results from own db
if (abra[i] !== "unknown") {
promises.append(handleExisting(notes[i], abra[i], "abra.me, own db"));
}
// Check if the message is a backronym
promises.push(checkBackronym(answers[i].msg)
.then(handleExisting(notes[i], "", "spells HUMAN")));
// Check spacescience.tech
promises.push(checkExistingSpacescience(answers[i].id, GM_getValue("strict", true), GM_getValue("threshold", 2))
.then(result => handleExisting(notes[i], result, "spacescience.tech")));
// Check ocean.rip
promises.push(checkExistingOcean(answers[i].msg)
.then(result => handleExisting(notes[i], result, "ocean.rip")));
}
// Wait until all requests have been handled
await Promise.all(promises.map(p => p.catch(e => e)))
.catch(e => console.log(e));
let bot_answers = [];
let unknown_answers = [];
let conflicts = false;
for (let note of notes) {
// If note hint is not set
let hint = note.getElementsByClassName("doorman-hint")[0];
if (!hint || hint.getAttribute("state") === "maybe_human") {
unknown_answers.push(note);
} else if (hint.getAttribute("state") === "bot") {
bot_answers.push(note);
} else if (hint.getAttribute("state") === "conflict") {
conflicts = true;
}
}
console.log(unknown_answers.length + " unknown answers left.");
// Autoclicker
if (GM_getValue("autoclick", false) && !conflicts) {
// Click known bot answer
if (bot_answers.length > 0) {
bot_answers[0].click();
return;
// Click unknown answer
} else if (unknown_answers.length == 1) {
unknown_answers[0].click();
return;
}
}
// Only check detector when there's more than one unknown answer left
if (unknown_answers.length > 1){
// Check detector
for (let i = 0; i < notes.length; i++) {
if (unknown_answers.includes(notes[i])) {
checkDetector(answers[i].msg)
.catch(error => console.log('error', error))
.then(percentage => appendHint(notes[i], Math.round(Number(percentage)*100)+"% bot"));
}
}
}
}
}
async function handleExisting(note, result, source) {
if (result === "known fake") {
setHint(note, `${result} (${source})`, "bot");
} else if (result === "known human") {
setHint(note, `${result} (${source})`, "human");
} else if (result === "maybe human") {
setHint(note, `below threshold (${source})`, "maybe_human", true)
}
}
function submitResults() {
var notes = document.getElementsByTagName("gremlin-note");
if (notes) {
let chosen_text = "";
let result = "";
let answers = [];
for (let note of notes) {
let state = note.getAttribute("state");
let id = note.getAttribute("id");
let text_regex = /^\s*(.*)\n/
let text = text_regex.exec(note.innerHTML)[1];
answers.push({id: id, msg: text});
if (state !== "none") {
// Selected answer
chosen_text = text;
result = state === "correct" ? "WIN" : "LOSE";
}
}
// Kick off submission in parallel, we don't care about the responses.
submitResultsAbra(chosen_text, result, answers.map(x => x.msg));
submitResultsSpacescience(chosen_text, result, answers.map(x => [x.id, x.msg]));
}
}
async function submitResultsAbra(chosen_text, result, option_texts) {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({"chosen_text": chosen_text, option_texts, "result": result});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
console.log("Submitting results");
fetch(SUBMIT_ABRA_URL, requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
async function submitResultsSpacescience(answer, result, options) {
let room = {"options": options};
let body = new FormData();
body.append("answer", answer);
body.append("result", result);
body.append("room", JSON.stringify(room));
let res = await (await fetch(SUBMIT_SPACESCIENCE_URL, {
method: "post",
body
})).text();
return JSON.parse(res);
}
function handleGremlinAction(e) {
const type = e.detail.type;
switch (type) {
case "begin":
console.log("begin");
break;
case "link":
if (!window.location.href.startsWith("https://gremlins-api.reddit.com/results")) {
// We have to wait a bit for reddit to get the results but after 300ms they redirect us
console.log("Submitting results in 250ms");
setTimeout(submitResults, 250);
}
break;
default:
console.log("default");
}
}
async function addMenu(app) {
let html = `
<p style="float: right; margin-top: 0;">Doorman ${VERSION}</p>
<div style="display: inline-block;">
<input type="checkbox" id="doorman-autoclick">
<label for="doorman-autoclick">Enable Autoclicker</label>
</div>
<div style="display: inline-block;">
<input type="number" id="doorman-threshold" min="1" style="width: 2rem; color: black; margin-left: 5rem;"></input>
<label for="doorman-threshold">Report threshold</label>
</div>
<div style="display: inline-block;">
<input type="checkbox" id="doorman-implicit">
<label for="doorman-implicit">
Use implicit data from spacescience, increase threshold to 5 or higher if you use this.
</label>
</div>
`
let div = document.createElement("div");
div.setAttribute("id", "doorman-options");
div.innerHTML = html;
app.appendChild(div);
let autoclick = document.getElementById("doorman-autoclick");
autoclick.checked = GM_getValue("autoclick", false);
autoclick.addEventListener("change", function () {
GM_setValue("autoclick", this.checked);
});
let implicit = document.getElementById("doorman-implicit");
implicit.checked = !GM_getValue("strict", true);
implicit.addEventListener("change", function () {
GM_setValue("strict", !this.checked);
});
let threshold = document.getElementById("doorman-threshold");
threshold.value = GM_getValue("threshold", 2);
threshold.addEventListener("change", function () {
GM_setValue("threshold", parseInt(this.value));
});
}
function run() {
var app = document.getElementsByTagName("gremlin-app")[0];
if (app) {
addMenu(app);
var answers = getAnswers();
console.log(answers);
processAnswers(answers);
app.addEventListener("gremlin-action", handleGremlinAction);
// Autoclick "Keep Going!" if we're on the results page
if (window.location.href.startsWith("https://gremlins-api.reddit.com/results")) {
if (GM_getValue("autoclick", false)) {
for (let a of app.getElementsByTagName("a")) {
if (a.textContent === "Keep Going!") {
a.click();
}
}
}
}
}
}
(function() {
setTimeout(run, 100);
})();