deekchat_renachan/client.js

1042 lines
22 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require("fs");
const websocket = require("ws");
const fetch = require("node-fetch");
const formdata = require("form-data");
const he = require("he");
const cheerio = require("cheerio");
const ddg = require("duckduckgo-images-api");
var mmm = require("mmmagic");
var Magic = mmm.Magic;
var http = require("http");
const emitter = require("events");
const deek = new emitter();
const name = "rena_chan";
const password = "still no";
const userid = 12;
var channels = [];
var ws = [];
var results_cache = [];
var is_pp_xeno = false;
var ddg_mod = true; // dont show porn in .img
var global_page = 1; // .img page
var raid = false; // raid?
var img_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"DNT": "1",
"Connection": "keep-alive"
};
var fortunes = [
"You will meet a dark stranger.",
"You will be eaten by a grue.",
"Your fortune: Bad Luck.",
"Your fortune: Good Luck.",
"Your fortune: Reply hazy, try again.",
"Your fortune: Outlook not so good.",
"Your fortune: YES.",
"Your fortune: NO.",
"Your fortune: Absolutely.",
"Your fortune: Very doubtful.",
"Your fortune: Cannot predict now.",
"Your fortune: Signs point to yes.",
"Your fortune: Don't count on it.",
"Your fortune: You may rely on it.",
"Your fortune: Concentrate and ask again.",
"Your fortune: The future is uncertain.",
"Your fortune: :fuck-off: fuck you"
];
var headers = {
"User-Agent": "renabot",
"Origin": "https://deek.chat"
};
/*
HTTP server bullshit
*/
const http_bullshit_handler = function(req, res){
switch(req.url){
case "/":
res.setHeader("Content-Type", "text/html");
res.writeHead(200);
res.end('<body style="color:#fff;background:#000;"><h1>all work and no play makes deek a dull boy</h1>');
break;
case "/kys":
res.setHeader("Content-Type", "text/html");
res.writeHead(200);
res.end('<body style="color:red;background:#000;"><h1>bang!</h1>');
send(1, "Resharted from web interface");
setTimeout(function(){
fs.utimesSync(__filename, Date.now(), Date.now());
}, 1000);
break;
default:
res.writeHead(404);
res.end("fuck you");
break;
}
}
const http_bullshit = http.createServer(http_bullshit_handler);
http_bullshit.listen(6969, "0.0.0.0", function(){
console.log("HTTP bullshit running");
});
/*
Helper functions
*/
async function getmime(file){
return new Promise(function(resolve, reject){
var magic = new Magic(mmm.MAGIC_MIME_TYPE);
magic.detect(file, function(err, result){
if(err){
resolve([
"image/png",
"png",
false
]);
}else{
resolve([
result,
result.split("/")[1],
true
]);
}
});
});
}
function removehtml(html){
return he.decode(html.replace(/<[^>]+>/ig,""));
};
async function serveddg(msg, results, page){
page--;
try{
var res = await fetch(
results[page].image,
{
headers: img_headers,
signal: AbortSignal.timeout(3000)
}
);
var res_get = await res.buffer();
var m = await getmime(res_get);
if(
m[2] === false ||
m[0].split("/")[0] != "image"
){
var res = await fetch(
results[page].thumbnail,
{
headers: img_headers,
signal: AbortSignal.timeout(5000)
}
);
var res_get = await res.buffer();
}
}catch(err){
var res = await fetch(
results[page].thumbnail,
{
headers: img_headers,
signal: AbortSignal.timeout(5000)
}
);
var res_get = await res.buffer();
}
send(
msg,
"Page " + (page + 1) + "/" + (results.length) + "\n[" + results[page].width + "x" + results[page].height + "] " + results[page].title + "\n" + results[page].url,
res_get
);
}
/*
Websocket functions
*/
async function send(channel, text, file = null, forcemime = null){
if(typeof channel == "object"){
channel = channel.channel;
}
if(file === null){
ws.send(JSON.stringify({
type: "messageEnd",
data: text,
roomId: channel
}));
return;
}
/*
Send file
*/
if(forcemime === null){
var mimetype = await getmime(file);
}else{
var mimetype = forcemime;
}
var form_data = new formdata();
form_data.append("text", text);
form_data.append(
"files[]",
file,
{
contentType: mimetype[0],
name: "file",
filename: "file." + mimetype[1]
}
);
var headers_copy = headers;
headers_copy["Content-Type"] = form_data.getHeaders()["content-type"];
fetch("https://deek.chat/message/send/" + channel, {
method: 'POST',
body: form_data,
headers: headers_copy
});
}
/*
Handshake
*/
async function handshake(name, password){
/*
Get cookie
*/
console.log("logging in as " + name);
const form = new formdata();
form.append("name", name);
form.append("password", password);
form.append("submit", "log+in");
try{
var login = await fetch(
"https://deek.chat/login/submit",
{
method: "POST",
redirect: "manual",
body: form,
headers: headers
}
);
}catch(err){
console.log("Could not login. Trying again in 10 seconds...");
setTimeout(function(){
fs.utimesSync(__filename, Date.now(), Date.now());
}, 10000);
return;
}
var cookie = await login.headers.get("set-cookie");
var api_token = cookie.match(/api_token=([^;]+)/);
var session_id = cookie.match(/session_id=([^;]+)/);
if(
api_token === null ||
typeof api_token[1] != "string" ||
typeof session_id[1] != "string"
){
deek.emit("error", "Could not get api_token or session_id !!");
return;
}
headers.cookie = "session_id=" + session_id[1] + "; api_token=" + api_token[1];
/*
Connect to websocket serber
*/
ws = new websocket(
"wss://deek.chat/ws",
{
protocolVersion: 13,
encoding: "utf8",
headers: headers
}
);
ws.once("open", function(){
deek.emit("login");
});
ws.once("close", function(){
deek.emit("close");
});
ws.on("message", function(message, isbin){
if(isbin){ return; }
var m = JSON.parse(message.toString("utf8"));
if(typeof m.type == "undefined"){
return;
}
switch(m.type){
case "message":
case "messageEnd":
for(var k=0; k<m.data.mentions.length; k++){
m.data.mentions[k].id = m.data.mentions[k].userId;
delete m.data.mentions[k].userId;
}
for(var k=0; k<m.data.replies.length; k++){
m.data.replies[k].id = m.data.replies[k].userId;
m.data.replies[k] = m.data.replies[k].replyMessageId;
delete m.data.replies[k].userId;
delete m.data.replies[k].replyMessageId;
}
m.data.files = m.data.files === null ? [] : m.data.files;
var files = [];
for(var k=0; k<m.data.files.length; k++){
files.push("https://deek.chat/storage/files/" + m.data.files[k].name);
}
deek.emit(
"message",
{
text: removehtml(m.data.text),
id: m.data.id,
files: files,
mentions: m.data.mentions,
replies: m.data.replies,
channel: m.roomId
},
{
name: m.data.name,
id: m.userId,
picture: m.data.profilePicture == "" ? null : "https://deek.chat/storage/profilePictures/" + m.data.profilePicture
}
);
break;
case "files":
var files = [];
if(m.data.files !== null){
for(var k=0; k<m.data.files.length; k++){
files.push("https://deek.chat/storage/files/" + m.data.files[k].name);
}
}
deek.emit(
"message",
{
text: removehtml(m.data.text),
id: m.data.id,
files: files,
mentions: m.data.mentions,
replies: m.data.replies,
channel: m.roomId
},
{
name: m.data.name,
id: m.data.userId,
picture: m.data.profilePicture == "" ? null : "https://deek.chat/storage/profilePictures/" + m.data.profilePicture
}
);
break;
default:
//console.warn(m);
break;
}
});
}
/*
User defined FUN-ctions!!!
*/
async function fetch_xeno(recording, index, msg){
index--;
var filereq = await fetch(
recording[index].file,
{headers: img_headers}
);
var file = await filereq.buffer();
send(
msg,
"Page " + (index + 1) + "/" + recording.length + "\n" +
">" + recording[index].en + " in " + recording[index].cnt + " (" + recording[index].loc + ")\n" +
recording[index].rmk,
file,
[
"audio/mpeg",
"mp3"
]
);
}
deek.on("login", function(channel){
console.log("Connected to websocket xoxo");
});
deek.on("message", async function(msg, user){
if(
(
user.id === 13 || // me lol
user.id === 14 || // aves
user.id === 8 || // aves again
user.id === 30 || // eagle
user.id === 2 || // deek
raid === false
) === false
){
return;
}
if(
user.id === userid ||
user.name == name
){
return;
}
/*
if(user.id === 5311){
user.name = msg.text.split(">")[0].substr(1);
msg.text = msg.text.split(">").splice(1).join(">").trim();
}*/
switch(msg.text.toLowerCase()){
case "hello rena":
case "hi rena":
case "what's up rena":
case "whats up rena":
send(msg, "hi " + user.name);
return;
case "/help":
send(msg, "lmao newfag");
return;
case "fuck you rena":
send(msg, "fuck you eagle");
return;
}
/*
shitty embed support
*/
if(link = msg.text.match(/https?:\/\/[^ \n\r'>]+/)){
link = link[0];
try{
if(tweet = link.match(/https?:\/\/(?:www\.)?(twitter|x)\.com\/[A-Za-z0-9_]+\/status\/([0-9]+)/i)){
tweet = tweet[1];
var res = await fetch("https://cdn.syndication.twimg.com/tweet-result?id=" + tweet + "&token=2rkokdcv41v");
var json = await res.json();
var title = json.user.name + " (@" + json.user.screen_name + ") " + " on twatter";
var description = json.text;
}else if(watch = link.match(/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/i)){
watch = watch[1];
var res = await fetch("https://youtube.com/oembed?url=/watch?v=" + watch);
var json = await res.json();
var title = json.title;
var description = "By " + json.author_name;
}else{
var res = await fetch(
link,
{
headers: img_headers,
signal: AbortSignal.timeout(5000)
}
);
var headers_arr = [...res.headers];
var headers = [];
for(i=0; i<headers_arr.length; i++){
headers[headers_arr[i][0]] = headers_arr[i][1];
}
if(
!headers["content-type"] ||
headers["content-type"].split(";")[0] != "text/html" ||
(
!headers["content-length"] &&
parseInt(headers["content-length"]) > 10485760 // 10MB
)
){
var text = "This thingy^ ";
if(headers["content-type"]){
var format = headers["content-type"].split("/");
format = format[format.length - 1].split(";")[0];
text += "is a " + format + " file ";
}else{
text += "is uhh... something.. err.. "
}
if(headers["content-length"]){
var filesize = Math.round(parseInt(headers["content-length"]) / 1048576);
text += "that weighs " + (Math.round(parseInt(headers["content-length"]) / 1048576)) + "MB!!";
}else{
text += "that uhh weighs something probably idk!!!";
}
text += " lol thats all i know fuck you";
send(msg, text);
return;
}
// cancerous code ahead
var buffer = await res.buffer();
const parser = cheerio.load(buffer);
// get title
var title = "Unknown title lol, shit website";
var tag_title = parser("title");
var tag_name_og_title = parser("meta[name='og:title']");
var tag_property_og_title = parser("meta[property='og:title']");
if(tag_name_og_title.length !== 0){ title = tag_name_og_title.attr("content"); }
if(tag_property_og_title.length !== 0){ title = tag_property_og_title.attr("content"); }
if(tag_title.length !== 0){ title = tag_title.text(); }
// get description
var description = "Unknown description lol, stupid website do not click";
var tag_name_description = parser("meta[name='description']");
var tag_name_og_description = parser("meta[name='og:description']");
var tag_property_description = parser("meta[property='description']");
var tag_property_og_description = parser("meta[property='og:description']");
if(typeof tag_name_description.attr("content") != "undefined"){description = tag_name_description.attr("content"); }
if(typeof tag_name_og_description.attr("content") != "undefined"){description = tag_name_og_description.attr("content"); }
if(typeof tag_property_description.attr("content") != "undefined"){description = tag_property_description.attr("content"); }
if(typeof tag_property_og_description.attr("content") != "undefined"){description = tag_property_og_description.attr("content"); }
if(typeof tag_name_description.attr("value") != "undefined"){description = tag_name_description.attr("value"); }
if(typeof tag_name_og_description.attr("value") != "undefined"){description = tag_name_og_description.attr("value"); }
if(typeof tag_property_description.attr("value") != "undefined"){description = tag_property_description.attr("value"); }
if(typeof tag_property_og_description.attr("value") != "undefined"){description = tag_property_og_description.attr("value"); }
}
var text = "";
description = description.split("\n");
for(var i=0; i<description.length; i++){
text += "\n>" + description[i];
}
send(msg, title + text);
}catch(err){
send(msg, "Stupid retarded website alert!!!! I got an error accessing this shit...\n>" + err);
}
return;
}
/*
Commands
*/
var regex = msg.text.match(/^\.([^ ]+)(?: (.*))?/);
if(
regex === null ||
typeof regex[1] == "undefined"
){
return;
}
var cmd = regex[1];
if(typeof regex[2] != "undefined"){
var value = regex[2];
}else{
var value = "";
}
switch(cmd.toLowerCase()){
case "raid":
if(
(
user.id === 13 || // me lol
user.id === 14 || // aves
user.id === 8 || // aves again
user.id === 30 || // eagle
user.id === 2 // deek
) === false
){
break;
}
if(raid === false){
raid = true;
send(msg, "Ignoring all messages from now on, fuck you lol!!");
}else{
raid = false;
send(msg, "Now listening to messages!!!");
}
break;
case "rc":
case "reconnect":
if(user.id !== 13){
break;
}
send(msg, "brb");
setTimeout(function(){
fs.utimesSync(__filename, Date.now(), Date.now());
}, 1000);
break;
case "ping":
send(msg, "Pong!!!!");
break;
case "dice":
case "roll":
case "d":
case "r":
value = parseInt(value);
if(isNaN(value)){
value = 6;
}
if(value <= 1){
send(
msg,
"Rolling a " + value + " faced dice...\nWait what?? " +
"You fucking shit, a black hole just appeared!!!!!! Oh my fucking shit!!!!!"
);
return;
}
send(
msg,
"Rolling a " + value + " faced dice...\nAnd you got " +
(
Math.floor(Math.random() * value + 1)
) + "!!!"
);
break;
case "mumble":
case "m":
var port = 64738;
if(value == ""){
var ip = "lolcat.ca";
}else{
var value = value.split(":");
if(value.length >= 2){
var port = value[1];
}
var ip = value[0];
}
try{
var res = await fetch("https://lolcat.ca/api/mumble/?ip=" + ip + "&port=" + port);
var res_get = await res.json();
if(res_get.status != "ok"){
send(msg, "An error occured... " + res_get.status);
return;
}
res_get = res_get.server;
var servername = res_get.name === null ? res_get.domains[0] : res_get.name;
var website = res_get.website === null ? "No website available" : res_get.website;
send(
msg,
">Server information for " + servername + ":\n" +
"Known domains => " + res_get.domains.join(", ") + "\n" +
"Ping => " + res_get.ping + "\n" +
"Users => " + res_get.online + "/" + res_get.max + "\n" +
"Bandwidth => " + res_get.bandwidth + "\n" +
"Country => " + res_get.country.name + " (" + res_get.country.code + ")\n" +
"Version => " + res_get.version + "\n" +
"Website => " + website
);
}catch(err){
send(msg, "lolcat.ca api sucks and is offline and dead");
}
break;
case "prop":
try{
var res = await fetch("https://www.hamqsl.com/solarn0nbh.php");
var res_get = await res.buffer();
send(msg, "Good news: the sun has not yet exploded", res_get);
}catch(err){
send(msg, "Could not fetch image!!! FUCK!!!!111\n" + err);
}
break;
case "img":
case "im":
case "i":
if(value.trim() == ""){
send(msg, "You need to search for something cum licker!!!");
return;
}
global_page = 1;
ddg.image_search(
{
query: value,
moderate: ddg_mod,
iterations: 1
}
).then(async results => {
is_pp_xeno = false;
results_cache = results;
if(results.length === 0){
send(msg, "No results found for " + value + "!!");
return;
}
await serveddg(msg, results, 1);
});
break;
case "boobs":
case "boob":
case "nsfw":
switch(value.toLowerCase()){
case "yes":
case "y":
case "1":
case "yea":
case "true":
case "yup":
send(msg, "I will now show boobs when using .img");
ddg_mod = false;
break;
case "no":
case "n":
case "nae":
case "false":
case "no":
case "off":
case "nope":
case "nah":
case "0":
send(msg, "I will now prevent eagle from jacking off in main chat");
ddg_mod = true;
break;
default:
var active = ddg_mod ? "NOT " : "";
send(msg, "I will " + active + "show boobs. Use .boobs <yes:no> to toggle");
break;
}
break;
case "page":
case "p":
value = parseInt(value);
if(
isNaN(value) ||
value == ""
){
send(msg, "You didn't enter a valid number you dumbass!!");
return;
}
if(results_cache.length === 0){
send(msg, "Search buffer doesn't contain any links you horse fucker!!");
return;
}
if(
value > results_cache.length ||
value <= 0
){
send(msg, "Page offset must be between 1 and " + results_cache.length + " you dumbass!!");
return;
}
global_page = value;
if(is_pp_xeno){
await fetch_xeno(results_cache, value, msg);
break;
}
await serveddg(msg, results_cache, value);
break;
case "pp":
global_page++;
if(global_page > results_cache.length){
send(msg, "You reached the end of results stupid kike sucker!!");
return;
}
if(is_pp_xeno){
await fetch_xeno(results_cache, global_page, msg);
break;
}
await serveddg(msg, results_cache, global_page);
break;
case "youtube":
case "jewtube":
case "yt":
if(value.trim() == ""){
send(msg, "You need to search for something cum licker!!!");
break;
}
try{
var res = await fetch("https://4get.zzls.xyz/api/v1/videos?s=" + encodeURIComponent(value));
var res_get = await res.json();
if(res_get.status != "ok"){
send(msg, "Shit!!!!! 4get sucks balls and returned this error: " + res_get.status);
break;
}
if(res_get.video.length === 0){
send(msg, "No results found for " + value + "!!");
break;
}
if(res_get.status != "ok"){
send(msg, "4get sucks!!!!! It returned ERRRO!!RRRO!!O!O!O!11\n>" + res_get.status);
break;
}
}catch(error){
send(msg, "4get returned invalid response!!!!!! piece of fuckgin shit!!!11!111");
}
var text = [];
for(var i=0; i<res_get.video.length; i++){
if(i === 3){
break;
}
text.push(
">Duration: " + (new Date(res_get.video[i].duration * 1000).toISOString().slice(11, 19)) +
" • Views: " + (new Intl.NumberFormat().format(res_get.video[i].views)) +
" • Author: " + res_get.video[i].author.name +
"\n" + res_get.video[i].title +
"\nⶠ" + res_get.video[i].url
);
}
send(msg, "Search results for \"" + value + "\"\n\n" + text.join("\n\n"));
break;
case "x":
case "xeno":
case "xeno-canto":
if(value.trim() == ""){
send(
msg,
"You must give me a search term you autistic cocksucker with no legs!!\nExample: .x owl"
);
break;
}
var res = await fetch("https://xeno-canto.org/api/2/recordings?query=" + encodeURIComponent(value));
var res_get = await res.json();
if(res_get.recordings.length === 0){
send(
msg,
"No recordings found for \"" + value + "\"!!!!!"
);
break;
}
global_page = 1;
is_pp_xeno = true;
results_cache = res_get.recordings;
await fetch_xeno(res_get.recordings, 1, msg);
break;
case "fortune":
case "f":
send(msg, fortunes[Math.floor(Math.random() * fortunes.length)]);
break;
case "help":
case "h":
send(
msg,
"== help menu ==\n\n" +
".help => lol idk\n" +
".img/.im/.i => search duckduckgo for birds\n" +
".boobs <yes:no> => Boobs?\n" +
".page/.p => get page offset for image search\n" +
".pp => get next page\n" +
".fortune/.f => fortune teller cause cynic cant code :trol:\n" +
".yt/.youtube => search the jewish propaganda catalog\n" +
".x/xeno => search for bird sounds\n" +
".roll/.r => Because deekchat was too slow\n" +
".mumble/.m <[optional]ip:port> => check if lolcat died\n" +
".prop => check if the sun has exploded or smth\n" +
".ping => spam deekchat"
);
break;
}
});
deek.on("close", function(channel){
console.log("It's over. Disconnected from websocket. Attempting reconnection in 10 seconds");
setTimeout(function(){
fs.utimesSync(__filename, Date.now(), Date.now());
}, 10000);
});
deek.on("error", function(message){
console.error("Serber error: " + message + ". Attempting reconnection in 10 seconds");
setTimeout(function(){
fs.utimesSync(__filename, Date.now(), Date.now());
}, 10000);
});
// connect to serber
handshake(name, password);