2020-06-26 12:13:00 -05:00
|
|
|
import * as db from "./database";
|
|
|
|
import {config} from "./config";
|
2020-06-27 02:36:45 -05:00
|
|
|
import {io} from "./http";
|
2020-06-26 12:13:00 -05:00
|
|
|
import * as irc from "irc";
|
2020-06-27 02:36:45 -05:00
|
|
|
import * as discord from "discord.js";
|
2020-06-27 05:25:40 -05:00
|
|
|
import * as twitch from "dank-twitch-irc";
|
2020-10-17 20:17:24 -05:00
|
|
|
import * as xmpp from "simple-xmpp";
|
|
|
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
2020-06-26 12:13:00 -05:00
|
|
|
|
|
|
|
var ircClient;
|
2020-10-17 20:17:24 -05:00
|
|
|
var xmppIgnore: Array<string> = [];
|
2020-10-17 22:07:30 -05:00
|
|
|
var xmppJoined: Array<string> = [];
|
2020-06-26 12:13:00 -05:00
|
|
|
var twitchClient;
|
2020-07-04 09:53:12 -05:00
|
|
|
var twitchArr: Array<string> = [];
|
2020-06-26 12:13:00 -05:00
|
|
|
var discordClient;
|
|
|
|
var liveUsers: Array<any>;
|
|
|
|
var chatIntegration: Array<any>;
|
|
|
|
|
|
|
|
async function init() {
|
|
|
|
setInterval(updateUsers, 20000);
|
|
|
|
setInterval(updateInteg, 60000);
|
2020-06-27 02:36:45 -05:00
|
|
|
if(config['chat']['discord']['enabled']){
|
|
|
|
discordClient = new discord.Client();
|
|
|
|
discordClient.once('ready', ()=>{ console.log('Discord bot ready')});
|
2020-07-04 03:09:32 -05:00
|
|
|
discordClient.on('message', async (msg) => {
|
2020-06-27 02:36:45 -05:00
|
|
|
if(msg['author']['bot']) return;
|
|
|
|
var lu = getUsr(msg['channel']['name'], 'discord')
|
|
|
|
for(var i=0;i<lu.length;i++){
|
2020-07-04 03:09:32 -05:00
|
|
|
sendAll(lu[i], [msg['author']['username'], await normalizeDiscordMsg(msg)], "discord");
|
2020-06-27 02:36:45 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
discordClient.login(config['chat']['discord']['token']);
|
|
|
|
}
|
|
|
|
if(config['chat']['irc']['enabled']){
|
2020-06-27 03:23:04 -05:00
|
|
|
ircClient = new irc.Client(config['chat']['irc']['server'], config['chat']['irc']['nickname'], {
|
|
|
|
userName: config['chat']['irc']['username'],
|
|
|
|
realName: config['chat']['irc']['realname'],
|
|
|
|
port: config['chat']['irc']['port'],
|
|
|
|
secure: config['chat']['irc']['tls'],
|
|
|
|
sasl: config['chat']['irc']['sasl'],
|
|
|
|
password: config['chat']['irc']['password'],
|
|
|
|
});
|
|
|
|
ircClient.addListener('error', (message) => {
|
|
|
|
console.log('IRC Client Error: ', message);
|
|
|
|
});
|
|
|
|
ircClient.once('registered', () => {
|
|
|
|
console.log("IRC Client Ready");
|
|
|
|
});
|
|
|
|
ircClient.on('message', (from, to, msg) => {
|
|
|
|
var lu = getUsr(to, 'irc');
|
|
|
|
for(var i=0;i<lu.length;i++){
|
|
|
|
sendAll(lu[i], [from, msg], "irc")
|
|
|
|
}
|
|
|
|
});
|
2020-06-27 02:36:45 -05:00
|
|
|
}
|
|
|
|
if(config['chat']['xmpp']['enabled']){
|
2020-10-17 20:17:24 -05:00
|
|
|
xmpp.on('online', (data) => {
|
|
|
|
console.log("XMPP Client Ready");
|
|
|
|
});
|
|
|
|
xmpp.on('groupchat', function(conference, from, message, stamp) {
|
|
|
|
if(xmppIgnore.findIndex((e) => { return e === conference }) !== -1) return false;
|
|
|
|
if(from === config['chat']['xmpp']['nickname']) return false;
|
|
|
|
console.log(from+'\n'+conference+'\n'+message+'\n'+stamp);
|
|
|
|
var lu = getUsr(conference, "xmpp");
|
|
|
|
for(var i=0;i<lu.length;i++){
|
|
|
|
sendAll(lu[i], [from, message], "xmpp")
|
|
|
|
}
|
|
|
|
});
|
|
|
|
xmpp.connect({
|
|
|
|
jid: config['chat']['xmpp']['jid'],
|
|
|
|
password: config['chat']['xmpp']['password'],
|
|
|
|
host: config['chat']['xmpp']['server'],
|
|
|
|
port: config['chat']['xmpp']['port']
|
|
|
|
});
|
2020-06-27 02:36:45 -05:00
|
|
|
}
|
|
|
|
if(config['chat']['twitch']['enabled']){
|
2020-06-27 05:25:40 -05:00
|
|
|
twitchClient = new twitch.ChatClient({
|
|
|
|
username: config['chat']['twitch']['username'],
|
|
|
|
password: config['chat']['twitch']['password'],
|
|
|
|
});
|
|
|
|
twitchClient.on('ready', () => {
|
|
|
|
console.log("Twitch Client Ready");
|
|
|
|
});
|
|
|
|
twitchClient.on("error", (error) => {
|
|
|
|
if (error != null) {
|
|
|
|
console.error("Twitch Client Error: ", error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
twitchClient.on("PRIVMSG", (msg) => {
|
|
|
|
if(msg['senderUserID'] === twitchClient['userStateTracker']['globalState']['userID']) return;
|
|
|
|
var lu = getUsr(msg['channelName'], 'twitch');
|
|
|
|
for(var i=0;i<lu.length;i++){
|
|
|
|
sendAll(lu[i], [msg['displayName'], msg['messageText']], "twitch");
|
|
|
|
}
|
|
|
|
});
|
2020-07-04 09:53:12 -05:00
|
|
|
//this library doesn't internally track which channels are currently joined, so we have to do it ourself
|
|
|
|
twitchClient.on('JOIN', (m) => {
|
|
|
|
if(twitchArr.indexOf(m['channelName']) === -1)
|
|
|
|
twitchArr.push(m['channelName']);
|
|
|
|
});
|
|
|
|
twitchClient.on('PART', (m) => {
|
|
|
|
if(twitchArr.indexOf(m['channelName']) !== -1)
|
|
|
|
twitchArr.splice(twitchArr.indexOf(m['channelName']), 1);
|
|
|
|
});
|
2020-06-27 05:25:40 -05:00
|
|
|
twitchClient.connect();
|
2020-06-27 02:36:45 -05:00
|
|
|
}
|
2020-06-26 12:13:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
async function updateUsers() {
|
|
|
|
liveUsers = await db.query('SELECT username FROM user_meta WHERE live=true');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function updateInteg() {
|
|
|
|
if(liveUsers.length === 0) {
|
|
|
|
chatIntegration = [];
|
2020-08-08 23:50:57 -05:00
|
|
|
if(config['chat']['irc']['enabled']) updateIRCChan();
|
|
|
|
if(config['chat']['twitch']['enabled']) updateTwitchChan();
|
2020-10-17 20:17:24 -05:00
|
|
|
if(config['chat']['xmpp']['enabled']) updateXmppChan();
|
2020-06-26 12:13:00 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(liveUsers.length === 1) {
|
2020-06-27 02:36:45 -05:00
|
|
|
chatIntegration = await db.query('SELECT * FROM chat_integration WHERE username='+db.raw.escape(liveUsers[0]['username']));
|
2020-08-08 23:50:57 -05:00
|
|
|
if(config['chat']['irc']['enabled']) updateIRCChan();
|
|
|
|
if(config['chat']['twitch']['enabled']) updateTwitchChan();
|
2020-10-17 20:17:24 -05:00
|
|
|
if(config['chat']['xmpp']['enabled']) updateXmppChan();
|
2020-06-26 12:13:00 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
var qs: string;
|
|
|
|
for(var u in liveUsers) {
|
2020-06-27 02:36:45 -05:00
|
|
|
qs += db.raw.escape(u['username']) + " OR username=";
|
2020-06-26 12:13:00 -05:00
|
|
|
}
|
|
|
|
qs = qs.substring(0, qs.length - 13);
|
2020-06-27 02:36:45 -05:00
|
|
|
chatIntegration = await db.query('SELECT * FROM chat_integration WHERE username='+qs);
|
2020-08-08 23:50:57 -05:00
|
|
|
if(config['chat']['irc']['enabled']) updateIRCChan();
|
|
|
|
if(config['chat']['twitch']['enabled']) updateTwitchChan();
|
2020-10-17 20:17:24 -05:00
|
|
|
if(config['chat']['xmpp']['enabled']) updateXmppChan();
|
2020-06-26 12:13:00 -05:00
|
|
|
}
|
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
async function sendAll(user: string, msg: Array<string>, src: string) {
|
|
|
|
//msg should be an array containing first the username of the user who sent the message
|
|
|
|
//followed by the message text
|
|
|
|
//[sender, message]
|
2020-06-26 12:13:00 -05:00
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
//user string is the user whose chat is being mirrored
|
2020-06-26 12:13:00 -05:00
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
if(user === null) return;
|
2020-06-26 12:13:00 -05:00
|
|
|
|
2020-06-27 03:23:04 -05:00
|
|
|
if(src !== "irc") sendIRC(getCh(user, "irc"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]);
|
2020-06-27 05:25:40 -05:00
|
|
|
if(src !== "twitch") sendTwitch(getCh(user, "twitch"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]);
|
2020-06-27 02:36:45 -05:00
|
|
|
if(src !== "discord") sendDiscord(getCh(user, "discord"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]);
|
2020-10-17 20:17:24 -05:00
|
|
|
if(src !== "xmpp") sendXMPP(getCh(user, "xmpp"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]);
|
2020-06-27 02:36:45 -05:00
|
|
|
if(src !== "web") sendWeb(user, ['['+src.toUpperCase()+']'+msg[0], msg[1]]);
|
|
|
|
}
|
2020-06-26 12:13:00 -05:00
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
async function sendIRC(channel: string, msg: string) {
|
|
|
|
if(!config['chat']['irc']['enabled']) return;
|
|
|
|
if(channel === null) return;
|
2020-06-27 03:23:04 -05:00
|
|
|
ircClient.say(channel, msg);
|
2020-06-26 12:13:00 -05:00
|
|
|
}
|
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
async function sendDiscord(channel: string, msg: string) {
|
|
|
|
if(!config['chat']['discord']['enabled']) return;
|
|
|
|
if(channel === null) return;
|
|
|
|
var ch = discordClient.channels.find('name', channel);
|
|
|
|
ch.send(msg);
|
|
|
|
}
|
2020-06-26 12:13:00 -05:00
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
async function sendXMPP(channel: string, msg: string) {
|
|
|
|
if(!config['chat']['xmpp']['enabled']) return;
|
|
|
|
if(channel === null) return;
|
2020-10-17 20:17:24 -05:00
|
|
|
xmpp.send(channel, msg, true);
|
2020-06-26 12:13:00 -05:00
|
|
|
}
|
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
async function sendTwitch(channel: string, msg: string) {
|
|
|
|
if(!config['chat']['twitch']['enabled']) return;
|
|
|
|
if(channel === null) return;
|
2020-06-27 05:25:40 -05:00
|
|
|
twitchClient.say(channel, msg);
|
2020-06-27 02:36:45 -05:00
|
|
|
}
|
2020-06-26 12:13:00 -05:00
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
async function sendWeb(channel: string, msg: Array<string>) {
|
|
|
|
if(channel === null) return;
|
|
|
|
io.to(channel).emit('MSG', {nick: msg[0], msg: msg[1], room: channel});
|
2020-06-26 12:13:00 -05:00
|
|
|
}
|
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
function getCh(usr: string, itype: string): string{
|
|
|
|
for(var i=0;i<chatIntegration.length;i++){
|
|
|
|
if(chatIntegration[i]['username'] === usr){
|
|
|
|
if(chatIntegration[i][itype].trim() !== "" && chatIntegration[i][itype] !== null) return chatIntegration[i][itype];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2020-06-26 12:13:00 -05:00
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
function getUsr(channel: string, ctype: string): Array<string>{
|
|
|
|
var list: Array<string> = [];
|
|
|
|
for(var i=0;i<chatIntegration.length;i++){
|
|
|
|
if(chatIntegration[i][ctype] === channel) list.push(chatIntegration[i]['username']);
|
|
|
|
}
|
|
|
|
return list;
|
2020-06-26 12:13:00 -05:00
|
|
|
}
|
|
|
|
|
2020-06-27 03:23:04 -05:00
|
|
|
async function updateIRCChan() {
|
2020-07-04 09:53:12 -05:00
|
|
|
var ilist: Array<string> = [];
|
2020-06-27 03:23:04 -05:00
|
|
|
for(var i=0;i<chatIntegration.length;i++){
|
2020-07-04 09:53:12 -05:00
|
|
|
if(chatIntegration[i]['irc'].trim() !== "" && chatIntegration[i]['irc'] !== null) {
|
|
|
|
ilist.push(chatIntegration[i]['irc']);
|
|
|
|
}
|
2020-06-27 03:23:04 -05:00
|
|
|
}
|
2020-07-04 09:53:12 -05:00
|
|
|
//do this to avoid duplicate channel joins
|
|
|
|
//and leave IRC channels when done
|
|
|
|
var tmp: Array<string> = ilist.filter(n => !Object.keys(ircClient.chans).includes(n)); //channels to join
|
|
|
|
for(var i=0;i<tmp.length;i++){
|
|
|
|
ircClient.join(tmp[i]);
|
|
|
|
}
|
|
|
|
tmp = Object.keys(ircClient.chans).filter(n => !ilist.includes(n)); //channels to part
|
|
|
|
for(var i=0;i<tmp.length;i++){
|
|
|
|
ircClient.part(tmp[i]);
|
2020-06-27 03:23:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-27 05:25:40 -05:00
|
|
|
async function updateTwitchChan() {
|
2020-07-04 09:53:12 -05:00
|
|
|
var ilist: Array<string> = [];
|
2020-06-27 05:25:40 -05:00
|
|
|
for(var i=0;i<chatIntegration.length;i++){
|
2020-07-04 09:53:12 -05:00
|
|
|
if(chatIntegration[i]['twitch'].trim() !== "" && chatIntegration[i]['twitch'] !== null) ilist.push(chatIntegration[i]['twitch']);
|
|
|
|
}
|
|
|
|
//do this to avoid duplicate channel joins
|
|
|
|
//and leave twitch channels when done
|
|
|
|
var tmp: Array<string> = ilist.filter(n => !twitchArr.includes(n)); //channels to join
|
|
|
|
for(var i=0;i<tmp.length;i++){
|
|
|
|
twitchClient.join(tmp[i]);
|
2020-06-27 05:25:40 -05:00
|
|
|
}
|
2020-07-04 09:53:12 -05:00
|
|
|
tmp = twitchArr.filter(n => !ilist.includes(n)); //channels to part
|
|
|
|
for(var i=0;i<tmp.length;i++){
|
|
|
|
twitchClient.part(tmp[i]);
|
2020-06-27 05:25:40 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-04 03:09:32 -05:00
|
|
|
async function normalizeDiscordMsg(msg): Promise<string>{
|
|
|
|
var nmsg: string=msg['content'];
|
|
|
|
|
|
|
|
//normalize user mentions
|
|
|
|
var uarray = await msg['mentions']['users'].array();
|
|
|
|
var karray = await msg['mentions']['users'].keyArray();
|
|
|
|
for(var i=0;i<karray.length;i++){
|
|
|
|
var usr = uarray[i];
|
|
|
|
nmsg = nmsg.replace(new RegExp('<@!'+karray[i]+'>', 'g'), '@'+usr['username']);
|
|
|
|
}
|
|
|
|
|
|
|
|
//normalize emoji
|
|
|
|
var e = nmsg.match(new RegExp('<:\\w+:[0-9]+>', 'g'));
|
|
|
|
//<:.+:.+>
|
|
|
|
if(e !== null)
|
|
|
|
for (var i=0;i<e.length;i++){
|
|
|
|
nmsg = nmsg.replace(e[i], e[i].match(new RegExp(':\\w+:', 'g'))[0]);
|
|
|
|
}
|
|
|
|
//in 10 minutes, I will have forgot what all of this regex does.
|
|
|
|
|
|
|
|
//normalize role mentions
|
|
|
|
var uarray = await msg['mentions']['roles'].array();
|
|
|
|
var karray = await msg['mentions']['roles'].keyArray();
|
|
|
|
for(var i=0;i<karray.length;i++){
|
|
|
|
var role = uarray[i];
|
|
|
|
nmsg = nmsg.replace(new RegExp('<@&'+karray[i]+'>', 'g'), '@'+role['name']);
|
|
|
|
}
|
|
|
|
|
|
|
|
//normalize channel mentions
|
|
|
|
var c = nmsg.match(new RegExp('<#[0-9]+>', 'g'));
|
|
|
|
if(c !== null)
|
|
|
|
for(var i=0;i<c.length;i++){
|
|
|
|
nmsg = nmsg.replace(c[i], '#'+discordClient.channels.get(c[i].match(new RegExp('[0-9]+', 'g'))[0])['name']);
|
|
|
|
}
|
|
|
|
|
|
|
|
//fuck me this better work
|
|
|
|
|
|
|
|
return nmsg;
|
|
|
|
}
|
|
|
|
|
2020-10-17 20:17:24 -05:00
|
|
|
function xmppJoin(room: string): void{
|
2020-10-17 22:07:30 -05:00
|
|
|
if(xmppJoined.findIndex((e) => { return e === room }) !== -1) return;
|
|
|
|
var stanza = new xmpp.Element('presence', {"to": room+'/'+config['chat']['xmpp']['nickname']}).c('x', { xmlns: 'http://jabber.org/protocol/muc' }).c('history', { maxstanzas: 0, seconds: 0});
|
2020-10-17 20:17:24 -05:00
|
|
|
xmpp.conn.send(stanza);
|
|
|
|
xmppIgnore = xmppIgnore.concat([room]);
|
|
|
|
xmpp.join(room+'/'+config['chat']['xmpp']['nickname']);
|
2020-10-17 22:07:30 -05:00
|
|
|
xmppJoined = xmppJoined.concat([room]);
|
2020-10-17 20:17:24 -05:00
|
|
|
sleep(4000).then(() => {
|
|
|
|
xmppIgnore = xmppIgnore.filter((item) => {
|
|
|
|
return item !== room;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateXmppChan(): void{
|
|
|
|
for(var i=0;i<chatIntegration.length;i++){
|
|
|
|
if(chatIntegration[i]['xmpp'].trim() !== "" && chatIntegration[i]['xmpp'] !== null) xmppJoin(chatIntegration[i]['xmpp']);
|
|
|
|
}
|
|
|
|
//we can't really leave channels so I'll come back to that.
|
|
|
|
}
|
|
|
|
|
2020-06-27 02:36:45 -05:00
|
|
|
export { init, sendAll };
|