Add working twitch chat relay

merge-requests/8/head
knotteye 4 years ago
parent 29d2090540
commit 19536d8b84
  1. 6
      install/config.example.yml
  2. 212
      package-lock.json
  3. 1
      package.json
  4. 41
      src/chat.ts

@ -42,9 +42,6 @@ chat:
discord:
enabled: false
token:
#server name is optional, will relay from messages from all matching channels in all servers
#if not specified
server:
xmpp:
enabled: false
@ -56,4 +53,5 @@ chat:
twitch:
enabled: false
username:
token:
#https://twitchapps.com/tmi/
password:

212
package-lock.json generated

@ -4,11 +4,23 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/debug": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
"integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
},
"@types/duplexify": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.0.tgz",
"integrity": "sha512-5zOA53RUlzN74bvrSGwjudssD9F3a797sDZQkiYpUOxW+WHaXTCPz4/d5Dgi6FKnOqZ2CpaTo0DhgIfsXAOE/A==",
"requires": {
"@types/node": "*"
}
},
"@types/node": {
"version": "12.7.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz",
"integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==",
"dev": true
"integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w=="
},
"a-sync-waterfall": {
"version": "1.0.1",
@ -81,6 +93,11 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"array-uniq": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz",
"integrity": "sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0="
},
"arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
@ -352,6 +369,27 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"dank-twitch-irc": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/dank-twitch-irc/-/dank-twitch-irc-3.2.6.tgz",
"integrity": "sha512-3OqEM38cJUwmiy4p0jpM1gzcdNj+yhcagqNBKq8BVGLkZLCpQ3gsdKhjweeB5/ddvnGZ/eAaYprbwNMTOiHLPw==",
"requires": {
"@types/debug": "^4.1.5",
"@types/duplexify": "^3.6.0",
"debug-logger": "^0.4.1",
"duplexify": "^4.1.1",
"eventemitter3": "^4.0.4",
"lodash.camelcase": "^4.3.0",
"lodash.pickby": "^4.6.0",
"make-error-cause": "^2.3.0",
"ms": "^2.1.2",
"randomstring": "^1.1.5",
"semaphore-async-await": "^1.5.1",
"simple-websocket": "^9.0.0",
"split2": "^3.1.1",
"ts-toolbelt": "^6.9.0"
}
},
"dateformat": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
@ -365,6 +403,29 @@
"ms": "^2.1.1"
}
},
"debug-logger": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/debug-logger/-/debug-logger-0.4.1.tgz",
"integrity": "sha1-4zhJw2njzTYbULKZ1xylIkuqGuE=",
"requires": {
"debug": "^2.1.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@ -422,6 +483,29 @@
}
}
},
"duplexify": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz",
"integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==",
"requires": {
"end-of-stream": "^1.4.1",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1",
"stream-shift": "^1.0.0"
},
"dependencies": {
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -432,6 +516,14 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"requires": {
"once": "^1.4.0"
}
},
"engine.io": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.0.tgz",
@ -536,6 +628,11 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"eventemitter3": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz",
"integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ=="
},
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
@ -871,6 +968,16 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
},
"lodash.pickby": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz",
"integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8="
},
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
@ -881,6 +988,14 @@
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g=="
},
"make-error-cause": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-2.3.0.tgz",
"integrity": "sha512-etgt+n4LlOkGSJbBTV9VROHA5R7ekIPS4vfh+bCAoJgRrJWdqJCBbpS3osRJ/HrT7R68MzMiY3L3sDJ/Fd8aBg==",
"requires": {
"make-error": "^1.3.5"
}
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -1207,6 +1322,27 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"queue-microtask": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.1.3.tgz",
"integrity": "sha512-zC1ZDLKFhZSa8vAdFbkOGouHcOUMgUAI/2/3on/KktpY+BaVqABkzDSsCSvJfmLbICOnrEuF9VIMezZf+T0mBA=="
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"requires": {
"safe-buffer": "^5.1.0"
}
},
"randomstring": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.1.5.tgz",
"integrity": "sha1-bfBij3XL1ZMpMNn+OrTpVqGFGMM=",
"requires": {
"array-uniq": "1.0.2"
}
},
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@ -1295,6 +1431,11 @@
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"semaphore-async-await": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz",
"integrity": "sha1-hXvvXjZEYBykuVcLh+nfXKEpdPo="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@ -1368,6 +1509,43 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"simple-websocket": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/simple-websocket/-/simple-websocket-9.0.0.tgz",
"integrity": "sha512-Q+u1BJ06/FR30xS1Sf6zDuL+vAdAA7VFqZ0TdKpmQKB2uNTAPKWQFFhUDV4YD7TDi7gSRJXoxv21WprNPR0ykQ==",
"requires": {
"debug": "^4.1.1",
"queue-microtask": "^1.1.0",
"randombytes": "^2.0.3",
"readable-stream": "^3.1.1",
"ws": "^7.0.0"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"ws": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz",
"integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w=="
}
}
},
"snekfetch": {
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz",
@ -1521,6 +1699,26 @@
}
}
},
"split2": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/split2/-/split2-3.1.1.tgz",
"integrity": "sha512-emNzr1s7ruq4N+1993yht631/JH+jaj0NYBosuKmLcq+JkGQ9MmTw1RB1fGaTCzUuseRIClrlSLHRNYGwWQ58Q==",
"requires": {
"readable-stream": "^3.0.0"
},
"dependencies": {
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
"sqlstring": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
@ -1531,6 +1729,11 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"stream-shift": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
},
"strftime": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.0.tgz",
@ -1631,6 +1834,11 @@
"yn": "^3.0.0"
}
},
"ts-toolbelt": {
"version": "6.9.9",
"resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.9.9.tgz",
"integrity": "sha512-5a8k6qfbrL54N4Dw+i7M6kldrbjgDWb5Vit8DnT+gwThhvqMg8KtxLE5Vmnft+geIgaSOfNJyAcnmmlflS+Vdg=="
},
"tweetnacl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",

@ -17,6 +17,7 @@
"bcrypt": "^3.0.6",
"body-parser": "^1.19.0",
"cookie-parser": "^1.4.4",
"dank-twitch-irc": "^3.2.6",
"dirty": "^1.1.0",
"discord.js": "^11.6.4",
"express": "^4.17.1",

@ -3,6 +3,7 @@ import {config} from "./config";
import {io} from "./http";
import * as irc from "irc";
import * as discord from "discord.js";
import * as twitch from "dank-twitch-irc";
var ircClient;
var xmppClient;
@ -52,7 +53,26 @@ async function init() {
}
if(config['chat']['twitch']['enabled']){
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");
}
});
twitchClient.connect();
}
}
@ -68,8 +88,8 @@ async function updateInteg() {
}
if(liveUsers.length === 1) {
chatIntegration = await db.query('SELECT * FROM chat_integration WHERE username='+db.raw.escape(liveUsers[0]['username']));
console.log('updated ci');
updateIRCChan();
updateTwitchChan();
return;
}
var qs: string;
@ -77,11 +97,9 @@ async function updateInteg() {
qs += db.raw.escape(u['username']) + " OR username=";
}
qs = qs.substring(0, qs.length - 13);
console.log('SELECT * FROM chat_integration WHERE username='+qs);
chatIntegration = await db.query('SELECT * FROM chat_integration WHERE username='+qs);
console.log('updated integrations');
console.log(chatIntegration);
updateIRCChan();
updateTwitchChan();
}
async function sendAll(user: string, msg: Array<string>, src: string) {
@ -94,7 +112,7 @@ async function sendAll(user: string, msg: Array<string>, src: string) {
if(user === null) return;
if(src !== "irc") sendIRC(getCh(user, "irc"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]);
//if(src !== "twitch") sendTwitch();
if(src !== "twitch") sendTwitch(getCh(user, "twitch"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]);
if(src !== "discord") sendDiscord(getCh(user, "discord"), '['+src.toUpperCase()+']'+msg[0]+': '+msg[1]);
//if(src !== "xmpp") sendXMPP();
if(src !== "web") sendWeb(user, ['['+src.toUpperCase()+']'+msg[0], msg[1]]);
@ -121,6 +139,7 @@ async function sendXMPP(channel: string, msg: string) {
async function sendTwitch(channel: string, msg: string) {
if(!config['chat']['twitch']['enabled']) return;
if(channel === null) return;
twitchClient.say(channel, msg);
}
async function sendWeb(channel: string, msg: Array<string>) {
@ -155,4 +174,14 @@ async function updateIRCChan() {
}
}
async function updateTwitchChan() {
var clist: Array<string> = [];
for(var i=0;i<chatIntegration.length;i++){
if(chatIntegration[i]['twitch'].trim() !== "" && chatIntegration[i]['twitch'] !== null) clist.push(chatIntegration[i]['twitch']);
}
for(var i=0;i<clist.length;i++){
twitchClient.join(clist[i]);
}
}
export { init, sendAll };