tasbot/bot/index.ts

182 lines
6.7 KiB
TypeScript
Raw Permalink Normal View History

2023-03-07 15:46:32 +00:00
import {
MatrixClient,
SimpleFsStorageProvider,
AutojoinRoomsMixin,
} from "matrix-bot-sdk";
const http = require("http");
// probably the worst code you have seen in your life
const bannedKeywords = [
['Sus', 'thigh high'],
['Amogus!!', 'amogus', 'among us'],
['LGBTQQIAAP++ propaganda',
'transgender', 'trans rights',
[
'thigh', 'sock', 'computer'
],
'transhumanist evolution', 'pride parade', 'pride flag', 'gay pride'
],
['Chinese cartoons', 'anime', 'manga', 'loli', 'azur lane', 'mihoyo', 'kancolle', 'neko', 'touhou', 'foxgirl', 'wolf girl', 'ayanamikodon', 'hatsune miku', 'vocaloid', 'mikudayo', 'kyoto animation'],
['Furries', 'fursona', 'fursuit', 'e621', 'furry fandom', 'furry art'],
['Gore', ' gore ', ' guro ', ' gory '],
];
// This will be the URL where clients can reach your homeserver. Note that this might be different
// from where the web/chat interface is hosted. The server must support password registration without
// captcha or terms of service (public servers typically won't work).
const homeserverUrl = "https://trygve.me";
// Use the access token you got from login or registration above.
const accessToken = "your token";
// In order to make sure the bot doesn't lose its state between restarts, we'll give it a place to cache
// any information it needs to. You can implement your own storage provider if you like, but a JSON file
// will work fine for this example.
const storage = new SimpleFsStorageProvider("hello-bot.json");
// Finally, let's create the client and set it to autojoin rooms. Autojoining is typical of bots to ensure
// they can be easily added to any room.
const client = new MatrixClient(homeserverUrl, accessToken, storage);
AutojoinRoomsMixin.setupOnClient(client);
// Before we start the bot, register our command handler
client.on("room.event", handleCommand);
// Now that everything is set up, start the bot. This will start the sync loop and run until killed.
client.start().then(() => console.log("Bot started!"));
// This is the command handler we registered a few lines up
async function handleCommand(roomId: string, event: any) {
let expression = '';
let image_url = '';
if (
event['content']?.['msgtype'] == 'm.image'
) {
image_url = homeserverUrl + "/_matrix/media/r0/download/" + (event['content']?.['url']).slice(6);
expression = 'image';
}
if (
event["content"]["avatar_url"]
) {
image_url = homeserverUrl + "/_matrix/media/r0/download/" + (event['content']?.['avatar_url']).slice(6);
expression = 'pfp';
}
if (event['sender'] === await client.getUserId()) return;
if (image_url == '') return;
console.log('New image received, analyzing...');
analyze_image(image_url, function(degenerate, degenerateKeywords, fullDegenerateKeywords, response) {
if (degenerate) {
console.log('====Degeneracy Detected!====');
console.log('User: ' + event['sender'] + ' sent image with url: ' + image_url);
console.log("Full keywords: " + fullDegenerateKeywords);
console.log("Sent keywords: " + degenerateKeywords);
console.log(response);
console.log('https://matrix.to/#/' + roomId + '/' + event['event_id'] + '?via=willy.club&via=trygve.me&via=matrix.org');
console.log('============================');
// determine what type of event it was
if (expression == 'image') {
client.redactEvent(roomId, event['event_id']);
client.sendText(roomId, 'Woah! Please refrain from posting images containing: "' + degenerateKeywords + '".');
} else {
client.kickUser(event['sender'], roomId, 'Please change your profile picture');
}
} else {
console.log('=======Nothing found========');
console.log('User: ' + event['sender'] + ' sent image with url: ' + image_url);
console.log(response);
console.log('https://matrix.to/#/' + roomId + '/' + event['event_id'] + '?via=willy.club&via=trygve.me&via=matrix.org');
console.log('============================');
}
});
}
function analyze_image(image_url, callback) {
http.get(`http://localhost:5000/?image_url=` + image_url, resp => {
let data = "";
// A chunk of data has been recieved.
resp.on("data", chunk => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on("end", () => {
let response = JSON.parse(data).message;
let responseWithoutComma = response.replace(',', ' ');
let degenerate = false;
let degenerateKeywords = '';
let fullDegenerateKeywords = '';
bannedKeywords.forEach(keyword => {
if (Array.isArray(keyword)) {
let alreadyAddedKeywordForThisGroup = false;
let skippedFirstIterationBecauseItsTheTitle = false;
keyword.forEach(subKeyword => {
if (!skippedFirstIterationBecauseItsTheTitle) {
skippedFirstIterationBecauseItsTheTitle = true;
return;
}
if (Array.isArray(subKeyword)) {
let allOfThemMatch = true;
subKeyword.forEach(subsubKeyword => {
if(responseWithoutComma.includes(subsubKeyword)) {
fullDegenerateKeywords += subsubKeyword + ',';
} else {
allOfThemMatch = false;
}
});
if (allOfThemMatch) {
degenerate = true;
if (!alreadyAddedKeywordForThisGroup) {
degenerateKeywords += keyword[0] + ',';
alreadyAddedKeywordForThisGroup = true;
}
}
} else if (responseWithoutComma.includes(subKeyword)) {
degenerate = true;
if (!alreadyAddedKeywordForThisGroup) {
degenerateKeywords += keyword[0] + ',';
fullDegenerateKeywords += subKeyword + ',';
alreadyAddedKeywordForThisGroup = true;
}
}
});
} else if (responseWithoutComma.includes(keyword)) {
degenerate = true;
degenerateKeywords += keyword + ',';
fullDegenerateKeywords += keyword + ',';
}
});
degenerateKeywords = degenerateKeywords.substr(0, degenerateKeywords.length -1);
fullDegenerateKeywords = fullDegenerateKeywords.substr(0, fullDegenerateKeywords.length -1);
if (degenerate) {
callback(true, degenerateKeywords, fullDegenerateKeywords, response);
} else {
callback(false, '', '', response);
}
});
});
}
// sometimes we dont have permission to redact messages, lets just ignore that
process.on('uncaughtException', function (exception) {
console.log('An error occured but it was probably not that important');
//console.log(exception);
});