mirror of
https://github.com/streamwall/streamwall.git
synced 2025-12-06 01:45:37 -05:00
Add back TwitchBot
This commit is contained in:
269
package-lock.json
generated
269
package-lock.json
generated
@@ -3860,11 +3860,36 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/debug": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
|
||||
"integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/ms": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/diff-match-patch": {
|
||||
"version": "1.0.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz",
|
||||
"integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg=="
|
||||
},
|
||||
"node_modules/@types/duplexify": {
|
||||
"version": "3.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.4.tgz",
|
||||
"integrity": "sha512-2eahVPsd+dy3CL6FugAzJcxoraWhUghZGEQJns1kTKfCXWKJ5iG/VkaB05wRVrDKHfOFKqb0X0kXh91eE99RZg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ejs": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz",
|
||||
"integrity": "sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/electron-squirrel-startup": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/electron-squirrel-startup/-/electron-squirrel-startup-1.0.2.tgz",
|
||||
@@ -3954,6 +3979,12 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/ms": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
|
||||
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/mysql": {
|
||||
"version": "2.15.26",
|
||||
"resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz",
|
||||
@@ -4661,6 +4692,12 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
|
||||
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/at-least-node": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||
@@ -4726,8 +4763,7 @@
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/base-x": {
|
||||
"version": "5.0.1",
|
||||
@@ -4841,7 +4877,6 @@
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -5147,7 +5182,6 @@
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
@@ -5429,8 +5463,7 @@
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
@@ -5573,6 +5606,44 @@
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/dank-twitch-irc": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/dank-twitch-irc/-/dank-twitch-irc-4.3.0.tgz",
|
||||
"integrity": "sha512-6ezjPDzwhOhifsiUhllmojlmkrDwMS/TbFVdVOTtq1KcKBzDYPAcpZN8d1jUUf1ICWVu85Dx9Xe66gErbabTYA==",
|
||||
"deprecated": "I (randers) am no longer supporting or updating dank-twitch-irc. While it may continue to work, I'm no longer making sure it will continue to do so in the future. This package will also not receive any dependency or security updates. For this reason I recommend you to choose a different library in your projects, or to fork this project to continue development on it. If somebody makes a high-quality fork of this project, you can contact me and I can link to your fork in this deprecation notice here. Thank you.",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/duplexify": "^3.6.0",
|
||||
"debug-logger": "^0.4.1",
|
||||
"duplexify": "^4.1.1",
|
||||
"eventemitter3": "^4.0.7",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"lodash.pickby": "^4.6.0",
|
||||
"make-error-cause": "^2.3.0",
|
||||
"ms": "^2.1.3",
|
||||
"randomstring": "^1.1.5",
|
||||
"semaphore-async-await": "^1.5.1",
|
||||
"simple-websocket": "^9.0.0",
|
||||
"split2": "^3.2.1",
|
||||
"ts-toolbelt": "^8.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/dank-twitch-irc/node_modules/eventemitter3": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dank-twitch-irc/node_modules/split2": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
|
||||
"integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"readable-stream": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
@@ -5649,6 +5720,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/debug-logger": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/debug-logger/-/debug-logger-0.4.1.tgz",
|
||||
"integrity": "sha512-bLX6pxuWO6KMXBRk6vpLgHqWXiuLbKp8kLL/wNEA4rgU8wsNLaw3UNz0NfOi1bcN0JwjFwSfxhldzU5Bc6P5RQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/debug-logger/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/debug-logger/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
@@ -5934,6 +6029,21 @@
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ejs": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
|
||||
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"jake": "^10.8.5"
|
||||
},
|
||||
"bin": {
|
||||
"ejs": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "33.2.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-33.2.1.tgz",
|
||||
@@ -7560,6 +7670,36 @@
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/filelist": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
||||
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"minimatch": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/filelist/node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/filelist/node_modules/minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/filename-reserved-regex": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
|
||||
@@ -8235,7 +8375,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -9045,6 +9184,24 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/jake": {
|
||||
"version": "10.9.2",
|
||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz",
|
||||
"integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"async": "^3.2.3",
|
||||
"chalk": "^4.0.2",
|
||||
"filelist": "^1.0.4",
|
||||
"minimatch": "^3.1.2"
|
||||
},
|
||||
"bin": {
|
||||
"jake": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -9341,6 +9498,12 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||
},
|
||||
"node_modules/lodash.camelcase": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.get": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
@@ -9353,6 +9516,12 @@
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.pickby": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz",
|
||||
"integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/log-symbols": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
||||
@@ -9469,8 +9638,16 @@
|
||||
"node_modules/make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
|
||||
},
|
||||
"node_modules/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==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"make-error": "^1.3.5"
|
||||
}
|
||||
},
|
||||
"node_modules/make-fetch-happen": {
|
||||
"version": "10.2.1",
|
||||
@@ -9660,7 +9837,6 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@@ -10929,7 +11105,6 @@
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -10963,6 +11138,30 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/randomstring": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.3.1.tgz",
|
||||
"integrity": "sha512-lgXZa80MUkjWdE7g2+PZ1xDLzc7/RokXVEQOv5NN2UOTChW1I8A9gha5a9xYBOqgaSoI6uJikDmCU8PyRdArRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"randombytes": "2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"randomstring": "bin/randomstring"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
@@ -11633,6 +11832,15 @@
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/semaphore-async-await": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz",
|
||||
"integrity": "sha512-b/ptP11hETwYWpeilHXXQiV5UJNJl7ZWWooKRE5eBIYWoom6dZ0SluCIdCtKycsMtZgKWE01/qAw6jblw1YVhg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
@@ -11901,6 +12109,33 @@
|
||||
"kolorist": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-websocket": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-websocket/-/simple-websocket-9.1.0.tgz",
|
||||
"integrity": "sha512-8MJPnjRN6A8UCp1I+H/dSFyjwJhp6wta4hsVRhjf8w9qBHRzxYt14RaOcjvQnhD1N4yKOddEjflwMnQM4VtXjQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"queue-microtask": "^1.2.2",
|
||||
"randombytes": "^2.1.0",
|
||||
"readable-stream": "^3.6.0",
|
||||
"ws": "^7.4.2"
|
||||
}
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
@@ -12432,7 +12667,6 @@
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
@@ -12671,6 +12905,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/ts-toolbelt": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-8.4.0.tgz",
|
||||
"integrity": "sha512-hnGJXIgC49ZuF5g5oDthoge8t4cvT0dYg2pYO5C6yV/HmUUy1koooU2U/5K2N+Uw++hcXQpJAToLRa+GRp28Sg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
|
||||
@@ -14093,7 +14333,7 @@
|
||||
}
|
||||
},
|
||||
"packages/streamwall": {
|
||||
"version": "2.0.0-pre1",
|
||||
"version": "2.0.0-pre2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
@@ -14102,6 +14342,8 @@
|
||||
"bufferutil": "^4.0.9",
|
||||
"chokidar": "^4.0.3",
|
||||
"color": "^5.0.0",
|
||||
"dank-twitch-irc": "^4.3.0",
|
||||
"ejs": "^3.1.10",
|
||||
"electron-squirrel-startup": "^1.0.1",
|
||||
"esbuild-register": "^3.6.0",
|
||||
"hls.js": "^1.5.18",
|
||||
@@ -14132,6 +14374,7 @@
|
||||
"@electron/fuses": "^1.8.0",
|
||||
"@preact/preset-vite": "^2.10.1",
|
||||
"@types/color": "^4.2.0",
|
||||
"@types/ejs": "^3.1.5",
|
||||
"@types/electron-squirrel-startup": "^1.0.2",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/ws": "^8.5.13",
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"@electron/fuses": "^1.8.0",
|
||||
"@preact/preset-vite": "^2.10.1",
|
||||
"@types/color": "^4.2.0",
|
||||
"@types/ejs": "^3.1.5",
|
||||
"@types/electron-squirrel-startup": "^1.0.2",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/ws": "^8.5.13",
|
||||
@@ -48,6 +49,8 @@
|
||||
"bufferutil": "^4.0.9",
|
||||
"chokidar": "^4.0.3",
|
||||
"color": "^5.0.0",
|
||||
"dank-twitch-irc": "^4.3.0",
|
||||
"ejs": "^3.1.10",
|
||||
"electron-squirrel-startup": "^1.0.1",
|
||||
"esbuild-register": "^3.6.0",
|
||||
"hls.js": "^1.5.18",
|
||||
|
||||
202
packages/streamwall/src/main/TwitchBot.ts
Normal file
202
packages/streamwall/src/main/TwitchBot.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
import Color from 'color'
|
||||
import {
|
||||
ChatClient,
|
||||
LoginError,
|
||||
PrivmsgMessage,
|
||||
SlowModeRateLimiter,
|
||||
} from 'dank-twitch-irc'
|
||||
import ejs from 'ejs'
|
||||
import EventEmitter from 'events'
|
||||
import { StreamList, StreamwallState } from 'streamwall-shared'
|
||||
import { matchesState } from 'xstate'
|
||||
import { StreamwallConfig } from '.'
|
||||
|
||||
const VOTE_RE = /^!(\d+)$/
|
||||
|
||||
type TwitchBotConfig = StreamwallConfig['twitch'] & {
|
||||
username: string
|
||||
token: string
|
||||
channel: string
|
||||
}
|
||||
|
||||
export default class TwitchBot extends EventEmitter {
|
||||
config: TwitchBotConfig
|
||||
announceTemplate: ejs.TemplateFunction
|
||||
voteTemplate: ejs.TemplateFunction
|
||||
client: ChatClient
|
||||
streams: StreamList
|
||||
listeningURL: string | null
|
||||
dwellTimeout: NodeJS.Timeout | undefined
|
||||
announceTimeouts: Map<string, NodeJS.Timeout>
|
||||
votes: Map<number, number>
|
||||
|
||||
constructor(config: TwitchBotConfig) {
|
||||
super()
|
||||
const { username, token, vote } = config
|
||||
this.config = config
|
||||
this.announceTemplate = ejs.compile(config.announce.template)
|
||||
|
||||
const client = new ChatClient({
|
||||
username,
|
||||
password: `oauth:${token}`,
|
||||
rateLimits: 'default',
|
||||
})
|
||||
client.use(new SlowModeRateLimiter(client, 0))
|
||||
this.client = client
|
||||
|
||||
this.streams = []
|
||||
this.listeningURL = null
|
||||
this.dwellTimeout = undefined
|
||||
this.announceTimeouts = new Map()
|
||||
|
||||
if (vote.interval) {
|
||||
this.voteTemplate = ejs.compile(config.vote.template)
|
||||
this.votes = new Map()
|
||||
setInterval(this.tallyVotes.bind(this), vote.interval * 1000)
|
||||
}
|
||||
|
||||
client.on('ready', () => {
|
||||
this.onReady()
|
||||
})
|
||||
client.on('error', (err) => {
|
||||
console.error('Twitch connection error:', err)
|
||||
if (err instanceof LoginError) {
|
||||
client.close()
|
||||
}
|
||||
})
|
||||
client.on('close', (err) => {
|
||||
console.log('Twitch bot disconnected.')
|
||||
if (err != null) {
|
||||
console.error('Twitch bot disconnected due to error:', err)
|
||||
}
|
||||
})
|
||||
client.on('PRIVMSG', (msg) => {
|
||||
this.onMsg(msg)
|
||||
})
|
||||
}
|
||||
|
||||
connect() {
|
||||
const { client } = this
|
||||
client.connect()
|
||||
}
|
||||
|
||||
async onReady() {
|
||||
const { client } = this
|
||||
const { channel, color: colorText } = this.config
|
||||
const color = Color(colorText)
|
||||
await client.setColor({
|
||||
r: color.red(),
|
||||
g: color.green(),
|
||||
b: color.blue(),
|
||||
})
|
||||
await client.join(channel)
|
||||
this.emit('connected')
|
||||
}
|
||||
|
||||
onState({ views, streams }: StreamwallState) {
|
||||
this.streams = streams
|
||||
|
||||
const listeningView = views.find(({ state }) =>
|
||||
matchesState(state, 'displaying.running.audio.listening'),
|
||||
)
|
||||
if (!listeningView) {
|
||||
return
|
||||
}
|
||||
|
||||
const listeningURL = listeningView.context.content?.url ?? null
|
||||
if (listeningURL === this.listeningURL) {
|
||||
return
|
||||
}
|
||||
this.listeningURL = listeningURL
|
||||
this.onListeningURLChange(listeningURL)
|
||||
}
|
||||
|
||||
onListeningURLChange(listeningURL: string | null) {
|
||||
if (!listeningURL) {
|
||||
return
|
||||
}
|
||||
|
||||
const { announce } = this.config
|
||||
clearTimeout(this.dwellTimeout)
|
||||
this.dwellTimeout = setTimeout(() => {
|
||||
if (!this.announceTimeouts.has(listeningURL)) {
|
||||
this.announce()
|
||||
}
|
||||
}, announce.delay * 1000)
|
||||
}
|
||||
|
||||
async announce() {
|
||||
const { client, listeningURL, streams } = this
|
||||
const { channel, announce } = this.config
|
||||
|
||||
if (!client.ready || !listeningURL) {
|
||||
return
|
||||
}
|
||||
|
||||
const stream = streams.find((s) => s.link === listeningURL)
|
||||
if (!stream) {
|
||||
return
|
||||
}
|
||||
|
||||
const msg = this.announceTemplate({ stream })
|
||||
await client.say(channel, msg)
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
this.announceTimeouts.delete(listeningURL)
|
||||
if (this.listeningURL === listeningURL) {
|
||||
this.announce()
|
||||
}
|
||||
}, announce.interval * 1000)
|
||||
this.announceTimeouts.set(listeningURL, timeout)
|
||||
}
|
||||
|
||||
async tallyVotes() {
|
||||
const { client } = this
|
||||
const { channel } = this.config
|
||||
if (this.votes.size === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let voteCount = 0
|
||||
let selectedIdx = null
|
||||
for (const [idx, value] of this.votes) {
|
||||
if (value > voteCount) {
|
||||
voteCount = value
|
||||
selectedIdx = idx
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIdx === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const msg = this.voteTemplate({ selectedIdx, voteCount })
|
||||
await client.say(channel, msg)
|
||||
|
||||
// Index spaces starting with 1
|
||||
this.emit('setListeningView', selectedIdx - 1)
|
||||
|
||||
this.votes = new Map()
|
||||
}
|
||||
|
||||
onMsg(msg: PrivmsgMessage) {
|
||||
const { vote } = this.config
|
||||
if (!vote.interval) {
|
||||
return
|
||||
}
|
||||
|
||||
const match = msg.messageText.match(VOTE_RE)
|
||||
if (!match) {
|
||||
return
|
||||
}
|
||||
|
||||
let idx
|
||||
try {
|
||||
idx = Number(match[1])
|
||||
} catch (err) {
|
||||
return
|
||||
}
|
||||
|
||||
this.votes.set(idx, (this.votes.get(idx) || 0) + 1)
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
} from './data'
|
||||
import StreamdelayClient from './StreamdelayClient'
|
||||
import StreamWindow from './StreamWindow'
|
||||
import TwitchBot from './TwitchBot'
|
||||
|
||||
const SENTRY_DSN =
|
||||
'https://e630a21dcf854d1a9eb2a7a8584cbd0b@o459879.ingest.sentry.io/5459505'
|
||||
@@ -54,6 +55,21 @@ export interface StreamwallConfig {
|
||||
control: {
|
||||
endpoint: string
|
||||
}
|
||||
twitch: {
|
||||
channel: string | null
|
||||
username: string | null
|
||||
token: string | null
|
||||
color: string
|
||||
announce: {
|
||||
template: string
|
||||
interval: number
|
||||
delay: number
|
||||
}
|
||||
vote: {
|
||||
template: string
|
||||
interval: number
|
||||
}
|
||||
}
|
||||
telemetry: {
|
||||
sentry: boolean
|
||||
}
|
||||
@@ -157,6 +173,61 @@ function parseArgs(): StreamwallConfig {
|
||||
describe: 'URL of control server endpoint',
|
||||
default: null,
|
||||
})
|
||||
.group(
|
||||
[
|
||||
'twitch.channel',
|
||||
'twitch.username',
|
||||
'twitch.token',
|
||||
'twitch.color',
|
||||
'twitch.announce.template',
|
||||
'twitch.announce.interval',
|
||||
'twitch.vote.template',
|
||||
'twitch.vote.interval',
|
||||
],
|
||||
'Twitch Chat',
|
||||
)
|
||||
.option('twitch.channel', {
|
||||
describe: 'Name of Twitch channel',
|
||||
default: null,
|
||||
})
|
||||
.option('twitch.username', {
|
||||
describe: 'Username of Twitch bot account',
|
||||
default: null,
|
||||
})
|
||||
.option('twitch.token', {
|
||||
describe: 'Password of Twitch bot account',
|
||||
default: null,
|
||||
})
|
||||
.option('twitch.color', {
|
||||
describe: 'Color of Twitch bot username',
|
||||
default: '#ff0000',
|
||||
})
|
||||
.option('twitch.announce.template', {
|
||||
describe: 'Message template for stream announcements',
|
||||
default:
|
||||
'SingsMic <%- stream.source %> <%- stream.city && stream.state ? `(${stream.city} ${stream.state})` : `` %> <%- stream.link %>',
|
||||
})
|
||||
.option('twitch.announce.interval', {
|
||||
describe:
|
||||
'Minimum time interval (in seconds) between re-announcing the same stream',
|
||||
number: true,
|
||||
default: 60,
|
||||
})
|
||||
.option('twitch.announce.delay', {
|
||||
describe: 'Time to dwell on a stream before its details are announced',
|
||||
number: true,
|
||||
default: 30,
|
||||
})
|
||||
.option('twitch.vote.template', {
|
||||
describe: 'Message template for vote result announcements',
|
||||
default:
|
||||
'Switching to #<%- selectedIdx %> (with <%- voteCount %> votes)',
|
||||
})
|
||||
.option('twitch.vote.interval', {
|
||||
describe: 'Time interval (in seconds) between votes (0 to disable)',
|
||||
number: true,
|
||||
default: 0,
|
||||
})
|
||||
.group(['telemetry.sentry'], 'Telemetry')
|
||||
.option('telemetry.sentry', {
|
||||
describe: 'Enable error reporting to Sentry',
|
||||
@@ -402,6 +473,26 @@ async function main(argv: ReturnType<typeof parseArgs>) {
|
||||
streamdelayClient.connect()
|
||||
}
|
||||
|
||||
const {
|
||||
username: twitchUsername,
|
||||
token: twitchToken,
|
||||
channel: twitchChannel,
|
||||
} = argv.twitch
|
||||
if (twitchUsername && twitchToken && twitchChannel) {
|
||||
console.debug('Setting up Twitch bot...')
|
||||
const twitchBot = new TwitchBot({
|
||||
...argv.twitch,
|
||||
username: twitchUsername,
|
||||
token: twitchToken,
|
||||
channel: twitchChannel,
|
||||
})
|
||||
twitchBot.on('setListeningView', (idx) => {
|
||||
streamWindow.setListeningView(idx)
|
||||
})
|
||||
stateEmitter.on('state', () => twitchBot.onState(clientState))
|
||||
twitchBot.connect()
|
||||
}
|
||||
|
||||
const dataSources = [
|
||||
...argv.data['json-url'].map((url) => {
|
||||
console.debug('Setting data source from json-url:', url)
|
||||
|
||||
Reference in New Issue
Block a user