diff --git a/.gitignore b/.gitignore index 5e6c27e..35c0657 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /local/ -node_modules/ \ No newline at end of file +node_modules/ +.DS_Store +test.sh +.vscode diff --git a/Procfile b/Procfile index f2d1f0b..9f8263b 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -worker: node index.js +worker: node src/main.js diff --git a/index.js b/index.js deleted file mode 100644 index 9af36e1..0000000 --- a/index.js +++ /dev/null @@ -1,10 +0,0 @@ -(async function(){ - global.dbClient = new (require('pg').Client)({ - connectionString: process.env.DATABASE_URL, - ssl: true, - }); - await dbClient.connect(); - - require('./src/main'); - -})().catch(error => {console.error(error.stack); process.exit(1);}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a1905cc --- /dev/null +++ b/package-lock.json @@ -0,0 +1,544 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "bson": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.9.tgz", + "integrity": "sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg==" + }, + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==" + }, + "buffer-writer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz", + "integrity": "sha1-Iqk2kB4wKa/NdUfrRIfOtpejvwg=" + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "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" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "discord.js": { + "version": "github:hydrabolt/discord.js#7d2744be89f90fa16b77b6fbad95902e26f4564a", + "from": "github:hydrabolt/discord.js", + "requires": { + "form-data": "^2.3.2", + "node-fetch": "^2.1.2", + "pako": "^1.0.0", + "prism-media": "github:hydrabolt/prism-media#ead016c69b1f341898cb264746c355b982502c62", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + }, + "dependencies": { + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + } + } + }, + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "extract-zip": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", + "requires": { + "concat-stream": "1.6.2", + "debug": "2.6.9", + "mkdirp": "0.5.1", + "yauzl": "2.4.1" + } + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "requires": { + "pend": "~1.2.0" + } + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "requires": { + "mime-db": "~1.33.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mongodb": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.1.tgz", + "integrity": "sha512-GU9oWK4pi8PC7NyGiwjFMwZyMqwGWoMEMvM0LZh7UKW/FFAqgmZKjjriD+5MEOCDUJE2dtHX93/K5UtDxO0otg==", + "requires": { + "mongodb-core": "3.1.0" + } + }, + "mongodb-core": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.0.tgz", + "integrity": "sha512-qRjG62Fu//CZhkgn0jA/k8jh5MhACIq8cOJUryH6sck87pgt+C222MSD02tsCq5zNo/B6ZFHtNodZ2qpf8E86g==", + "requires": { + "bson": "~1.0.4", + "require_optional": "^1.0.1", + "saslprep": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "packet-reader": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz", + "integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc=" + }, + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "pg": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.4.3.tgz", + "integrity": "sha1-97b5P1NA7MJZavu5ShPj1rYJg0s=", + "requires": { + "buffer-writer": "1.0.1", + "packet-reader": "0.3.1", + "pg-connection-string": "0.1.3", + "pg-pool": "~2.0.3", + "pg-types": "~1.12.1", + "pgpass": "1.x", + "semver": "4.3.2" + }, + "dependencies": { + "semver": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", + "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=" + } + } + }, + "pg-connection-string": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", + "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" + }, + "pg-pool": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.3.tgz", + "integrity": "sha1-wCIDLIlJ8xKk+R+2QJzgQHa+Mlc=" + }, + "pg-types": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.12.1.tgz", + "integrity": "sha1-1kCH45A7WP+q0nnnWVxSIIoUw9I=", + "requires": { + "postgres-array": "~1.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.0", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz", + "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=", + "requires": { + "split": "^1.0.0" + } + }, + "postgres-array": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz", + "integrity": "sha1-jgsy6wO/d6XAp4UeBEHBaaJWojg=" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.3.tgz", + "integrity": "sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g=" + }, + "postgres-interval": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.2.tgz", + "integrity": "sha512-fC3xNHeTskCxL1dC8KOtxXt7YeFmlbTYtn7ul8MkVERuTmf7pI4DrkAxcw3kh1fQ9uz4wQmd03a1mRiXUZChfQ==", + "requires": { + "xtend": "^4.0.0" + } + }, + "prism-media": { + "version": "github:hydrabolt/prism-media#ead016c69b1f341898cb264746c355b982502c62", + "from": "github:hydrabolt/prism-media" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=" + }, + "puppeteer": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-0.13.0.tgz", + "integrity": "sha512-M52SA/WmW54YMLzFtCLGslhr9tntzfTgJIZnx3QnaDXn9F5q2BlTosywSBEKj8aVVd6al0WNfiu14MUQW3wjaw==", + "requires": { + "debug": "^2.6.8", + "extract-zip": "^1.6.5", + "https-proxy-agent": "^2.1.0", + "mime": "^1.3.4", + "progress": "^2.0.0", + "proxy-from-env": "^1.0.0", + "rimraf": "^2.6.1", + "ws": "^3.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + } + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "saslprep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.0.tgz", + "integrity": "sha512-5lvKUEQ7lAN5/vPl5d3k8FQeDbEamu9kizfATfLLWV5h6Mkh1xcieR1FSsJkcSRUk49lF2tAW8gzXWVwtwZVhw==", + "optional": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "requires": { + "fd-slicer": "~1.0.1" + } + } + } +} diff --git a/src/colorroles.js b/src/colorroles.js index aba55b1..2574da8 100755 --- a/src/colorroles.js +++ b/src/colorroles.js @@ -7,7 +7,6 @@ global.colorRoles = { // TODO clean up this, adsfhaiusdhgaisuhg name:"[]", permissions:[], color:"RANDOM", - //position: member.guild.roles.get('346754988023873546').position }}); return role; }, diff --git a/src/commands.js b/src/commands.js index deb9778..75b36ba 100755 --- a/src/commands.js +++ b/src/commands.js @@ -38,11 +38,11 @@ global.commands = { usage: "", description: "Creates a generic text channel in this server and gives you full permissions for it.", exec: async function (msg) { - if (!msg.args[0]) return false; + if (!msg.args[0]) return "EBADUSG"; //var name = msg.txt(1).replace(/[^a-zA-Z0-9]/g, '-').substr(0,100).toLowerCase(); var name = msg.txt(1); msg.guild.channels.create(name, { - parent: '399735134061985792', + parent: config.channels.user_channels, overwrites: [ { id: msg, @@ -79,7 +79,7 @@ global.commands = { var channel = msg.channel; } if (!channel.permissionsFor(msg.member).has('MANAGE_CHANNELS')) return msg.react('🚫'); - await channel.setParent('425054198699261953'); + await channel.setParent(config.channels.deleted_channels); await channel.lockPermissions(); msg.react('🆗'); } @@ -106,6 +106,24 @@ global.commands = { } } }, + + "exec": { + op: true, + usage: "", + aliases: ["$"], + exec: async function (msg) { + require("child_process").exec(msg.txt(1), function(error, stdout, stderr){ + if (error) msg.channel.send(error, {split:{char:''}}); + else { + var str = "" + if (stdout) msg.channel.send(stdout, {split:{char:''}}); + if (stderr) msg.channel.send(stderr, {split:{char:''}}); + } + }) + } + + }, + "query": { description: "Queries the Heroku PostgreSQL database", usage: "", @@ -145,35 +163,26 @@ dClient.on('message', message => { if (!message.guild) message.guild = dClient.guilds.get(config.guildID); if (!message.member) message.member = dClient.guilds.get(config.guildID).members.get(message.author.id); - /*if (commands.hasOwnProperty(cmd)) { - var command = commands[cmd]; - if (command.op && message.author.id !== op) return message.react('🚫'); - try { - command.exec(message, args, txt); - } catch(e) { - message.reply(`:warning: An error occured while processing your command.`); - console.error(e.stack); - } - }*/ - Object.keys(commands).forEach(commandName => { var command = commands[commandName]; if (!(commandName === cmd || (command.aliases && command.aliases.includes(cmd)))) return; if (command.op && message.author.id !== config.opID) return message.react('🚫'); - /*try { - var d = command.exec(message, args, txt); - if (d === false) message.channel.send(`**Usage:** \`!${commandName} ${command.usage}\``); - } catch(e) { - message.reply(`:warning: An error occured while processing your command.`); - console.error(e.stack); - }*/ - command.exec(message, args, txt).then( (res) => { - if (res === false) message.channel.send(`**Usage:** \`!${commandName} ${command.usage}\``); + switch (res) { + case "ENOTBRIDGE": + message.channel.send([ + `This is not a bridged channel.`, + `You can only use this command in a bridged channel.` + ].random()); + break; + case "EBADUSG": + message.channel.send(`**Usage:** \`!${commandName} ${command.usage}\``); + break; + } }, (err) => { - message.reply(`:warning: An error occured: \`\`\`\n${err.stack}\n\`\`\``); + message.reply(`:warning: An error occured: \`\`\`\n${err.stack}\n\`\`\`<@281134216115257344>`); console.error(err.stack); } ) diff --git a/src/config.js b/src/config.js index 5d10bf2..0ac83cb 100644 --- a/src/config.js +++ b/src/config.js @@ -1,25 +1,42 @@ +global.testmode = process.env.TEST ? true : false; + module.exports = { - "testmode": false, - - "token": process.env.DISCORD_TOKEN, - + + "DISCORD_TOKEN": process.env.DISCORD_TOKEN, + "DATABASE_URL": testmode ? "postgres://localhost/k4t" : process.env.DATABASE_URL, + "MONGODB_URI": testmode ? "mongodb://localhost/k4t" : process.env.MONGODB_URI, + "webhooks": { - "console": process.env.TOKEN_WEBHOOK_CONSOLE, - "welcome": process.env.TOKEN_WEBHOOK_WELCOME, + "welcome": process.env.WEBHOOK_WELCOME.split("/"), }, "opID": "281134216115257344", - "guildID": "321819041348190249", - "channels": { - "main": "321819041348190249" + "guildID": testmode ? "467473467634089985" : "321819041348190249", + + "channels": { // includes voice channels & category channels + "main": testmode ? "467473467634089987" : "321819041348190249", + "voice": testmode ? "467473467634089989" : "425060452129701889", + "name_collection": testmode ? "467481952728121345" : '379738469511069698', + "mpp_bridges": testmode ? "467481904707534850" : '360557444952227851', + "user_channels": testmode ? "467482031157149709" : '399735134061985792', + "deleted_channels": testmode ? "467482085657935872" : '425054198699261953', + "deleted_bridges": testmode ? "467482121657778176" : '451838300068511745', + "mpp_screenshot": testmode ? "467482164611514388" : '383773548810076163', + "owop_screenshot": testmode ? "467482202217906226" : '399079481161023492' }, + "roles": { + "viewing_deleted_channels": testmode ? "467473718353068042" : "425060792455397376", + }, + + + "mppname": "[discord.gg/k44Eqha]", "disabledRooms": [ "RP Room", "Legends of Alorgon {RP Room}", "Legends of Alorgon", "Breastmilk ♥ 7:45 AM" - ] + ], } \ No newline at end of file diff --git a/src/lib/Client.js b/src/lib/Client.js index aa2d6cc..0aa1837 100755 --- a/src/lib/Client.js +++ b/src/lib/Client.js @@ -17,10 +17,9 @@ function mixin(obj1, obj2) { }; -function Client(uri, arrayBuffer) { +function Client(uri) { EventEmitter.call(this); this.uri = uri; - this.arrayBuffer = arrayBuffer; this.ws = undefined; this.serverTimeOffset = 0; this.user = undefined; @@ -85,7 +84,7 @@ Client.prototype.connect = function() { // browseroni this.ws = new WebSocket(this.uri); } - if (this.arrayBuffer) this.ws.binaryType = "arraybuffer"; + this.ws.binaryType = "arraybuffer"; this.emit("ws created"); var self = this; this.ws.addEventListener("close", function(evt) { diff --git a/src/main.js b/src/main.js index 3420dcf..8f4f2fb 100755 --- a/src/main.js +++ b/src/main.js @@ -1,51 +1,33 @@ +require('./util'); +global.config = require('./config'); +if (config.testmode) console.log('TEST MODE'); global.exitHook = require('async-exit-hook'); global.Discord = require('discord.js'); global.fs = require('fs'); -global.config = require('./config'); global.dClient = new Discord.Client({ disableEveryone: true }); -console._log = console.log; -console.log = function(){ - console._log.apply(console, arguments); - log2discord(arguments); -} -console._error = console.error; -console.error = function(){ - console._error.apply(console, arguments); - log2discord(arguments); -} -console.warn = console.error; -console.info = console.log; - -var webhook = new Discord.WebhookClient('405445543536623627', config.webhooks.console); -function log2discord(str){ - str = Array.from(str); - str = str.map(require('util').inspect); - str = str.join(' '); - webhook.send(str, {split:{char:''}}); -} - -process.on('unhandledRejection', (reason, promise) => { - console.error(promise); +global.dbClient = new (require('pg').Client)({ + connectionString: process.env.DATABASE_URL, + ssl: !testmode, }); -process.on('uncaughtException', error => { - console.error(error.stack); -}); - - -(require('mongodb').MongoClient).connect(process.env.MONGODB_URI).then(client=>{ - global.mdbClient = client; - dClient.login(config.token); +console.log("Connecting to Postgres…") +dbClient.connect().then(function(){ + console.log("Connecting to MongoDB…"); + (require('mongodb').MongoClient).connect(config.MONGODB_URI).then(client=>{ + global.mdbClient = client; + console.log("Connecting to Discord…"); + dClient.login(config.DISCORD_TOKEN); + }); }); dClient.once('ready', () => { console.log('Discord Client Ready'); - require('./commands.js'); - require('./colorroles.js'); - require('./mppbridger.js'); - require('./screenshotter.js'); - require('./misc.js'); + require('./commands'); + require('./colorroles'); + require('./mppbridger'); + require('./screenshotter'); + require('./misc'); }); dClient.on('error', console.error); diff --git a/src/misc.js b/src/misc.js index 0998bc3..747c1d2 100755 --- a/src/misc.js +++ b/src/misc.js @@ -1,22 +1,22 @@ // join/leave -(function(){ - var webhook = new Discord.WebhookClient('404736784354770958', config.webhooks.welcome); - dClient.on('guildMemberAdd', member => { +(async function(){ + var webhook = new Discord.WebhookClient(config.webhooks.welcome[0], config.webhooks.welcome[1]); + dClient.on('guildMemberAdd', async member => { webhook.send(`${member} joined.`, {username: member.user.username, avatarURL: member.user.displayAvatarURL(), disableEveryone:true}); }); - dClient.on('guildMemberRemove', member => { + dClient.on('guildMemberRemove', async member => { webhook.send(`${member.user.tag} left.`, {username: member.user.username, avatarURL: member.user.displayAvatarURL(), disableEveryone:true}); }); })(); // view deleted channels -(function(){ - var vcid = '425060452129701889'; - var rid = '425060792455397376'; - dClient.on('voiceStateUpdate', (oldMember, newMember) => { +(async function(){ + var vcid = config.channels.voice; + var rid = config.roles.viewing_deleted_channels; + dClient.on('voiceStateUpdate', async (oldMember, newMember) => { if (oldMember.voiceChannelID != vcid && newMember.voiceChannelID == vcid) { // member joined the channel newMember.roles.add(newMember.guild.roles.get(rid)); diff --git a/src/mppbridger.js b/src/mppbridger.js deleted file mode 100755 index 5458f24..0000000 --- a/src/mppbridger.js +++ /dev/null @@ -1,500 +0,0 @@ -var Client = require('./lib/Client.js'); -global.clients = {}; - - - - - - - - -/*function reconnectClients() { - for (let site in clients) { - site = clients[site]; - let i = 0; - for (let client in site) { - client = site[client]; - if (client.reconnectTimeout) clearTimeout(client.reconnectTimeout); - client.reconnectTimeout = setTimeout(()=>{ - client.connect(); - client.reconnectTimeout = undefined; - }, i += 2000); - } - } -} //TODO BETTAH*/ - - -global.clientConnector = { - queue: [], - enqueue: function(client) { - if (this.queue.includes(client)) return; - this.queue.push(client); - }, - interval: setInterval(function(){ - var client = clientConnector.queue.shift(); - if (client) client.connect(); - }, 2000) -} - - - -global.createMPPbridge = function (room, DiscordChannelID, site = 'MPP', webhookID, webhookToken) { - var DiscordChannel = dClient.channels.get(DiscordChannelID); - if (!DiscordChannel) return console.error(`Couldn't bridge ${site} ${room} because Discord Channel ${DiscordChannelID} is missing!`); - if (webhookID && webhookToken) var webhook = new Discord.WebhookClient(webhookID, webhookToken, {disableEveryone:true}); - - var msgBuffer = []; - function _dSend(msg, embed) { - if (webhook && !config.testmode) { - let username = gClient.channel && gClient.channel._id || room; - if (username.length > 32) username = username.substr(0,31) + '…'; - else if (username.length < 2) username = undefined; - webhook.send(msg, {username, embed, split:{char:''}}).catch(e => { - console.error(e); - DiscordChannel.send(msg, {embed, split:{char:''}}).catch(console.error); - }); - } - else DiscordChannel.send(msg, {embed, split:{char:''}}).catch(console.error); - } - function dSend(msg) { - msgBuffer.push(msg); - } - setInterval(()=>{ - if (msgBuffer.length == 0) return; - _dSend(msgBuffer.join('\n')); - msgBuffer = []; - }, 2000); //TODO make changeable - - const gClient = site == "MPP" ? new Client("ws://www.multiplayerpiano.com:443") : site == "WOPP" ? new Client("ws://ourworldofpixels.com:1234", true) : site == "MPT" ? new Client("ws://ts.terrium.net:8080", true) : site == "VFDP" ? new Client("ws://www.visualfiredev.com:8080") : undefined; - if (!gClient) return console.error(`Invalid site ${site}`); - gClient.setChannel(/*(site == "MPP" && room == "lobby") ? "lolwutsecretlobbybackdoor" : */room); - gClient.canConnect = true; - clientConnector.enqueue(gClient); - - - - var isConnected = false; - gClient.on('connect', () => { - console.log(`Connected to room ${room} of ${site} server`); - dSend(`**Connected**`); // TODO say what room it actually connected to ? - gClient.sendArray([{m: "userset", set: {name: config.mppname}}]) - isConnected = true; - }); - gClient.on('disconnect', () => { - if (isConnected) { - console.log(`Disconnected from room ${room} of ${site} server`); - dSend(`**Disconnected**`); - isConnected = false; - } - clientConnector.enqueue(gClient); - }); - /*gClient.on('status', status => { - console.log(`[${site}] [${room}] ${status}`); - });*/ - - let lastCh = room; - gClient.on('ch', msg => { - if (lastCh && msg.ch._id !== lastCh) { - dSend(`**Channel changed from \`${lastCh}\` to \`${msg.ch._id}\`**`); - console.log(`[${site}][${room}] Channel changed from ${lastCh} to ${msg.ch._id}`); - lastCh = msg.ch._id; - } - (async function(){ - // catch dropped crown - if (msg.ch.crown && !msg.ch.crown.hasOwnProperty('participantId')) { - gClient.sendArray([{m:'chown', id: gClient.getOwnParticipant().id}]); // if possible - var avail_time = msg.ch.crown.time + 15000 - gClient.serverTimeOffset; - var ms = avail_time - Date.now(); - setTimeout(()=> gClient.sendArray([{m:'chown', id: gClient.getOwnParticipant().id}]) , ms); - } - // transfer crown to owner - if (msg.ppl && msg.ch.crown && msg.ch.crown.participantId == gClient.getOwnParticipant().id) { - var res = await dbClient.query("SELECT owner_mpp__id FROM bridges WHERE mpp_room = $1 AND site = $2;", [room, site]); - if (res.rows.length == 0) return; - var owner = res.rows[0].owner_mpp__id; - if (!owner) return; - msg.ppl.some(part => { - if (part._id == owner) { - gClient.sendArray([{m:'chown', id: part.id}]); - return true; - } else return false; - }); - } - })(); - }); - - // MPP to Discord - gClient.on('a', msg => { - if (msg.p._id == gClient.getOwnParticipant()._id) return; - var id = msg.p._id.substr(0,6); - var name = msg.p.name.replace(/discord.gg\//g, 'discord.gg\\/'); - var str = `\`${id}\` **${name}:** ${msg.a}`; - str = str.replace(/<@/g, "<\\@"); - dSend(str); - }); - - // Discord to MPP - dClient.on('message', message => { - if (message.channel.id !== DiscordChannelID || message.author.bot || message.content.startsWith('!')) return; - var str = message.cleanContent; - var arr = []; - if (str.startsWith('/') || str.startsWith('\\')) { - arr.push({m:"a", message: - `⤹ ${message.member.displayName}` - }); - } else str = message.member.displayName + ': ' + str; - if (str.startsWith('\\')) str = str.slice(1); - if (message.attachments.first()) str += ' '+message.attachments.first().url; - if (str.length > 512) str = str.substr(0,511) + '…'; - arr.push({m:"a", message:str}); - gClient.sendArray(arr); - }); - - // announce join/leave - gClient.on('participant added', participant => { //TODO universal way of filtering names - dSend(`**\`${participant._id.substr(0,6)}\` ${participant.name.replace(/<@/g, "<\\@")} entered the room.**`); - }); - gClient.on('participant removed', participant => { - dSend(`**\`${participant._id.substr(0,6)}\` ${participant.name.replace(/<@/g, "<\\@")} left the room.**`); - }); - - - /*// autoban banned participants - gClient.on('participant added', part => { - if (PS.banned_ppl.hasOwnProperty(part._id) && gClient.isOwner()) - gClient.sendArray([{m: "kickban", _id: part._id, ms: 60*60*1000}]); - });*/ - - - gClient.on('notification', async msg => { - - // show notification - _dSend(undefined, { - title: msg.title, - description: msg.text || msg.html - }); - - // ban handling - if (msg.text && (msg.text.startsWith('Banned from') || msg.text.startsWith('Currently banned from'))) { - // Banned from "{room}" for {n} minutes. - // Currently banned from "{room}" for {n} minutes. - let arr = msg.text.split(' '); - arr.pop(); - let minutes = arr.pop(); - - gClient.stop(); - setTimeout(()=>{ - gClient.setChannel(room); - gClient.start(); - }, minutes*60*1000+3000); - dSend(`**Attempting to rejoin in ${minutes} minutes.**`); - } - }); - - gClient.on("ch", function(msg){ - if (gClient.isOwner()) { - if (gClient.countParticipants() <= 1) { - gClient.sendArray([{m:'chset', set: { visible: false }}]) - } else { - gClient.sendArray([{m:'chset', set: { visible: true }}]) - } - } - }); - - - - // addons - gClient.on('participant update', function(participant){ - nameCollector.collect(participant); - }); - //if (site == 'MPP' && room == 'lobby') MPPrecorder.start(gClient);//TODO too much memory - - // collect data - (async function(){ - var filename = `${site} ${room} .txt`.replace(/\//g, ':'); - var size = 0; - var startDate = new Date(); - gClient.on('ws created', function(){ - gClient.ws.addEventListener('message', msg => { - var data = msg.data; - if (data instanceof ArrayBuffer) data = Buffer.from(data).toString('base64'); - var line = `${Date.now()} ${data}\n`; - size += line.length; - fs.appendFile(filename, line, ()=>{}); - if (size > 8000000) {save(); size = 0;} - }); - }); - async function save(callback){ - console.log(`saving data recording`, filename) - fs.readFile(filename, (err, file) => { - if (err) return console.error(err); - require('zlib').gzip(file, async function(err, gzip){ - if (err) return console.error(err); - var attachmentName = `${site} ${room} raw data recording from ${startDate.toISOString()} to ${new Date().toISOString()} .txt.gz`; - await DiscordChannel.send(new Discord.MessageAttachment(gzip, attachmentName)); - fs.writeFileSync(filename, ''); - size = 0; - startDate = new Date(); - console.log(`saved raw data recording`, attachmentName); - if (callback) callback(); - }); - }); - } - exitHook(callback => { - save(()=>callback()); - }); - gClient.dataCollectorSave = function(){save()}; // test - })(); - - if (!clients[site]) clients[site] = {}; - clients[site][room] = gClient; - - - - /*// EXPERIMENTAL - gClient.on('ls', msg => { - msg.u.forEach(async r => { - if (clients[site][r._id]) return; - for (let client of clientConnector.queue) {if (client.desiredChannelId == r._id) return} // ugg - var discordChannelName = r._id.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase(); - var categoryID = '409079939501916160'; - var channel = await dClient.guilds.get(config.guildID).createChannel(discordChannelName, {parent: categoryID}); - channel.setTopic(`Bridged to http://www.multiplayerpiano.com/${encodeURIComponent(r._id)}`); - var webhook = await channel.createWebhook('Webhook'); - createMPPbridge(r._id, channel.id, site, webhook.id, webhook.token); - }) - })*/ -} - - - - - - - - - - - -global.nameCollector = { - collection: mdbClient.db('heroku_jrtfvpd9').collection('ppl'), - collect: async function (participant) { - if (config.testmode) return; - if (participant.name == "Anonymous" || participant.name == "Anonymoose") return; - - var newMsg = function(continued){ - var str = `__**${participant._id}**__${continued ? ' (continued)' : ''}\n${participant.name}`; - return dClient.channels.get('379738469511069698').send(str); - } - - var document = await this.collection.findOne({_id: participant._id}); - - if (document) { - // update person - if (document.names.includes(participant.name)) return; - document.names.push(participant.name); - this.collection.updateOne({_id: participant._id}, {$set:{names: document.names}}); - - let message = await dClient.channels.get('379738469511069698').messages.fetch(document.discord_msg_id); - try { - await message.edit(message.content + ', ' + participant.name); - } catch(e) { - let message = await newMsg(true); - this.collection.updateOne({_id: participant._id}, {$set:{discord_msg_id: message.id}}); - } - } else { - // add new person - let message = await newMsg(); - nameCollector.collection.insertOne({ - _id: participant._id, - discord_msg_id: message.id, - names: [participant.name] - }); - } - } -}; - - - -global.MPPrecorder = { - start: function(client) { - var recorder = (require('./lib/mpprecorder-module.js'))(undefined, client); - this.save = async function () { - var startDate = new Date(recorder.startTime), endDate = new Date(); - var filename = `www.multiplayerpiano.com lobby recording from ${startDate.toISOString()} to ${endDate.toISOString()} .mid.gz`; - var file = recorder.save(); - file = Buffer.from(file, 'binary'); - file = require('zlib').gzipSync(file); - var attachment = new Discord.MessageAttachment(file, filename); - await dClient.channels.get('394967426133000193').send(attachment); - } - this.interval = setInterval(() => { - this.save(); - }, 10*60*1000); - exitHook(callback => { - this.save().then(callback); - }); - } -}; - - - - - - - -// start -(async function () { - var res = await dbClient.query('SELECT * FROM bridges;'); - - var sites = {}; - res.rows.forEach(row => { - if (row.disabled) return; - if (!sites[row.site]) sites[row.site] = []; - sites[row.site].push(row); - }); - - for (let site in sites) { - let arr = sites[site]; - arr.sort((a, b) => {return a.position - b.position}); - let i = 0; - arr.forEach(bridge => { - setTimeout(function(){ - createMPPbridge(bridge.mpp_room, bridge.discord_channel_id, bridge.site, bridge.webhook_id, bridge.webhook_token, bridge.owner_mpp__id); - }, i); - i = i + 2000; - }); - } -})(); - - - - - - - -// commands - -commands.bridge = { - usage: "", - description: "Creates a bridge to the specified MPP room.", - exec: async function (msg) { - var site = 'MPP'; - var room = msg.txt(1); - if (!room) return false; - var existingBridge = (await dbClient.query('SELECT * FROM bridges WHERE mpp_room = $1;', [room])).rows[0]; - if (existingBridge) { - if (!existingBridge.disabled) { - return msg.reply(`${site} room ${room} is already bridged.`); - } else { - if (config.disabledRooms.includes(room)) { - return msg.reply(`You cannot bridge this room.`); - } else /* rebridge */ { - let channel = dClient.guilds.get(config.guildID).channels.get(existingBridge.discord_channel_id); - await dbClient.query("UPDATE bridges SET disabled = false WHERE mpp_room = $1", [room]); - await channel.setParent('360557444952227851'); - await channel.lockPermissions(); - createMPPbridge(room, existingBridge.mpp_room, existingBridge.site, existingBridge.webhook_id, existingBridge.webhook_token); - await msg.reply(`${site} room ${room} has been re-bridged.`); - return; - } - } - } - /* new bridge */ - var discordChannelName = room.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase(); - var categoryID = '360557444952227851'; - var channel = await dClient.guilds.get(config.guildID).channels.create(discordChannelName, {parent: categoryID}); - channel.setTopic(`http://www.multiplayerpiano.com/${encodeURIComponent(room)}`); - var webhook = await channel.createWebhook('Webhook'); - createMPPbridge(room, channel.id, site, webhook.id, webhook.token); - dbClient.query('INSERT INTO bridges (site, mpp_room, discord_channel_id, webhook_id, webhook_token, owner_discord_user_id) VALUES ($1, $2, $3, $4, $5, $6)', [ - site, room, channel.id, webhook.id, webhook.token, msg.author.id, - ]); - msg.reply(`${site} room ${room} is now bridged to ${channel}.`); - } -}; - -commands.unbridge = { - usage: "[MPP Room]", - description: "Deletes a bridge to the specified MPP room.", - exec: async function (msg) { - var bridge = (await dbClient.query("SELECT * FROM bridges WHERE mpp_room = $1 OR discord_channel_id = $2", [msg.txt(1), msg.channel.id])).rows[0]; - if (!bridge) { - //msg.react('⚠️'); - msg.reply(`That room is not bridged. Make sure you type the MPP room name correctly.`); - return; - } - if (bridge.disabled) { - msg.reply(`That room has already been unbridged.`); - return; - } - if (!(bridge.owner_discord_user_id == msg.author.id || msg.author.id == config.opID)) { - //msg.react('🚫'); - msg.reply(`You do not own that bridge.`); - return; - } - await dbClient.query("UPDATE bridges SET disabled = 'true' WHERE mpp_room = $1", [bridge.mpp_room]); - clients.MPP[bridge.mpp_room].stop(); - var channel = dClient.channels.get(bridge.discord_channel_id) - await channel.setParent('451838300068511745'); - await channel.lockPermissions(); - msg.reply(`${bridge.mpp_room} has been unbridged.`); - } -} - -commands.chown = { - usage: "<'mpp'/'discord'> ", - description: "Changes the MPP or Discord owner of a private bridge. The first argument must be either `mpp` or `discord`.", - aliases: ['changeowner', 'setowner'], - exec: async function (msg) { - if (msg.args.length < 3 || !['mpp','discord'].includes(msg.args[1])) return false; - var res = await dbClient.query('SELECT * FROM bridges WHERE discord_channel_id = $1;', [msg.channel.id]); - if (res.rows.length == 0) return msg.react('🚫'); - var bridge = res.rows[0]; - if (!(bridge.owner_discord_user_id == msg.author.id || msg.author.id == config.opID)) return msg.react('🚫'); - - if (msg.args[1] == 'discord') { - let selectedUser = dClient.users.get(msg.args[2]) || msg.mentions.users.first(); - if (!selectedUser) return msg.react('⚠️'); - msg.channel.overwritePermissions(selectedUser, { - MANAGE_CHANNELS: true, - MANAGE_ROLES: true, - MANAGE_WEBHOOKS: true, - MANAGE_MESSAGES: true - }); - let po = msg.channel.permissionOverwrites.find(x => x.id == msg.author.id); - if (po) po.delete(); - await dbClient.query('UPDATE bridges SET owner_discord_user_id = $1 WHERE discord_channel_id = $2;', [selectedUser.id, msg.channel.id]); - msg.channel.send(`Ownership of ${msg.channel} has been transferred to ${selectedUser}`); - } else if (msg.args[1] == 'mpp') { - let _id = msg.args[2]; - await dbClient.query('UPDATE bridges SET owner_mpp__id = $1 WHERE discord_channel_id = $2;', [_id, msg.channel.id]); - msg.channel.send(`MPP user \`${_id}\` has been assigned as owner of the MPP room, and the crown will be transferred to them whenever possible.`); - //todo give crown if owner there - } - } -}; - -commands.list = { - description: "Lists online participants", - aliases: ['ppl', 'online'], - exec: async function (message) { - var row = (await dbClient.query("SELECT mpp_room, site FROM bridges WHERE discord_channel_id = $1;", [message.channel.id])).rows[0]; - if (!row) { - //message.react('🚫'); - message.reply(`Use this in a bridged room to see who is at the other side.`); - return; - } - var ppl = clients[row.site][row.mpp_room].ppl; - - var numberOfPpl = Object.keys(ppl).length; - var str = `__**Participants Online (${numberOfPpl})**__\n`; - var names = []; - for (let person in ppl) { - person = ppl[person]; - names.push(`\`${person._id.substr(0,6)}\` ${person.name.replace(/<@/g, "<\\@")}`); - } - str += names.join(', '); - message.channel.send(str, {split:{char:''}}); - } -}; diff --git a/src/mppbridger/commands/ban.js b/src/mppbridger/commands/ban.js new file mode 100644 index 0000000..5aeebde --- /dev/null +++ b/src/mppbridger/commands/ban.js @@ -0,0 +1,25 @@ +module.exports = { + usage: "", + description: "Adds a perma-ban on the user", + aliases: ["permaban"], + exec: async function (msg) { + if (!msg.args[1]) return "EBADUSG"; + var res = await dbClient.query('SELECT * FROM bridges WHERE discord_channel_id = $1;', [msg.channel.id]); + if (!res.rows.length) return "ENOTBRIDGE" + var bridge = res.rows[0]; + if (bridge.owner_discord_user_id != msg.author.id) return msg.reply(`You are not the owner of this bridge.`); + var _id = msg.txt(1); + await dbClient.query("UPDATE bridges SET bans = array_append(bans, $1) WHERE discord_channel_id = $2", [_id, msg.channel.id]); + await msg.reply(`OK, I'll ban anyone whose user ID equals or starts with \`${_id}\` from this room, whenever possible.`); + + var client = clients.MPP[bridge.mpp_room] + for (let p in client.ppl) { + p = client.ppl[p] + if (p._id.startsWith(_id)) + client.sendArray([{m:'kickban', _id, ms: 60*60*1000}]) + } + + if (_id.length != 24) await msg.reply(":warning: The ID you gave me does not look like a full user ID (it is not 24 chars long). If it's a truncated ID it will still work, however it could possibly ban someone else whose user ID starts with those chars.") + + }, +} \ No newline at end of file diff --git a/src/mppbridger/commands/bridge.js b/src/mppbridger/commands/bridge.js new file mode 100644 index 0000000..d3678ec --- /dev/null +++ b/src/mppbridger/commands/bridge.js @@ -0,0 +1,38 @@ +module.exports = { + usage: "", + description: "Creates a bridge to the specified MPP room.", + exec: async function (msg) { + var site = 'MPP'; + var room = msg.txt(1); + if (!room) return "EBADUSG"; + var existingBridge = (await dbClient.query('SELECT * FROM bridges WHERE mpp_room = $1;', [room])).rows[0]; + if (existingBridge) { + if (!existingBridge.disabled) { + return msg.reply(`${site} room ${room} is already bridged.`); + } else { + if (config.disabledRooms.includes(room)) { + return msg.reply(`You cannot bridge this room.`); + } else /* rebridge */ { + let channel = dClient.guilds.get(config.guildID).channels.get(existingBridge.discord_channel_id); + await dbClient.query("UPDATE bridges SET disabled = false WHERE mpp_room = $1", [room]); + await channel.setParent(); + await channel.lockPermissions(); + createMPPbridge(room, existingBridge.mpp_room, existingBridge.site, existingBridge.webhook_id, existingBridge.webhook_token); + await msg.reply(`${site} room ${room} has been re-bridged.`); + return; + } + } + } + /* new bridge */ + var discordChannelName = room.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase(); + var categoryID = config.channels.mpp_bridges; + var channel = await dClient.guilds.get(config.guildID).channels.create(discordChannelName, {parent: categoryID}); + channel.setTopic(`http://www.multiplayerpiano.com/${encodeURIComponent(room)}`); + var webhook = await channel.createWebhook('Webhook'); + createMPPbridge(room, channel.id, site, webhook.id, webhook.token); + dbClient.query('INSERT INTO bridges (site, mpp_room, discord_channel_id, webhook_id, webhook_token, owner_discord_user_id) VALUES ($1, $2, $3, $4, $5, $6)', [ + site, room, channel.id, webhook.id, webhook.token, msg.author.id, + ]); + msg.reply(`${site} room ${room} is now bridged to ${channel}.`); + } +}; \ No newline at end of file diff --git a/src/mppbridger/commands/chown.js b/src/mppbridger/commands/chown.js new file mode 100644 index 0000000..236cc9e --- /dev/null +++ b/src/mppbridger/commands/chown.js @@ -0,0 +1,32 @@ +module.exports = { + usage: "<'mpp'/'discord'> ", + description: "Changes the MPP or Discord owner of a private bridge. The first argument must be either `mpp` or `discord`.", + aliases: ['changeowner', 'setowner'], + exec: async function (msg) { + if (msg.args.length < 3 || !['mpp','discord'].includes(msg.args[1])) return "EBADUSG"; + var res = await dbClient.query('SELECT * FROM bridges WHERE discord_channel_id = $1;', [msg.channel.id]); + if (res.rows.length == 0) return msg.react('🚫'); + var bridge = res.rows[0]; + if (!(bridge.owner_discord_user_id == msg.author.id || msg.author.id == config.opID)) return msg.react('🚫'); + + if (msg.args[1] == 'discord') { + let selectedUser = dClient.users.get(msg.args[2]) || msg.mentions.users.first(); + if (!selectedUser) return msg.react('⚠️'); + msg.channel.overwritePermissions(selectedUser, { + MANAGE_CHANNELS: true, + MANAGE_ROLES: true, + MANAGE_WEBHOOKS: true, + MANAGE_MESSAGES: true + }); + let po = msg.channel.permissionOverwrites.find(x => x.id == msg.author.id); + if (po) po.delete(); + await dbClient.query('UPDATE bridges SET owner_discord_user_id = $1 WHERE discord_channel_id = $2;', [selectedUser.id, msg.channel.id]); + msg.channel.send(`Ownership of ${msg.channel} has been transferred to ${selectedUser}`); + } else if (msg.args[1] == 'mpp') { + let _id = msg.args[2]; + await dbClient.query('UPDATE bridges SET owner_mpp__id = $1 WHERE discord_channel_id = $2;', [_id, msg.channel.id]); + msg.channel.send(`MPP user \`${_id}\` has been assigned as owner of the MPP room, and the crown will be transferred to them whenever possible.`); + //todo give crown if owner there + } + } +}; \ No newline at end of file diff --git a/src/mppbridger/commands/list.js b/src/mppbridger/commands/list.js new file mode 100644 index 0000000..1de2eb5 --- /dev/null +++ b/src/mppbridger/commands/list.js @@ -0,0 +1,23 @@ +module.exports = { + description: "Lists online participants", + aliases: ['ppl', 'online'], + exec: async function (message) { + var row = (await dbClient.query("SELECT mpp_room, site FROM bridges WHERE discord_channel_id = $1;", [message.channel.id])).rows[0]; + if (!row) { + //message.react('🚫'); + message.reply(`Use this in a bridged room to see who is at the other side.`); + return; + } + var ppl = clients[row.site][row.mpp_room].ppl; + + var numberOfPpl = Object.keys(ppl).length; + var str = `__**Participants Online (${numberOfPpl})**__\n`; + var names = []; + for (let person in ppl) { + person = ppl[person]; + names.push(`\`${person._id.substr(0,6)}\` ${person.name.replace(/<@/g, "<\\@")}`); + } + str += names.join(', '); + message.channel.send(str, {split:{char:''}}); + } +}; \ No newline at end of file diff --git a/src/mppbridger/commands/unbridge.js b/src/mppbridger/commands/unbridge.js new file mode 100644 index 0000000..a0fc5b0 --- /dev/null +++ b/src/mppbridger/commands/unbridge.js @@ -0,0 +1,27 @@ +module.exports = { + usage: "[MPP Room]", + description: "Deletes a bridge to the specified MPP room.", + exec: async function (msg) { + var bridge = (await dbClient.query("SELECT * FROM bridges WHERE mpp_room = $1 OR discord_channel_id = $2", [msg.txt(1), msg.channel.id])).rows[0]; + if (!bridge) { + //msg.react('⚠️'); + msg.reply(`That room is not bridged. Make sure you type the MPP room name correctly.`); + return; + } + if (bridge.disabled) { + msg.reply(`That room has already been unbridged.`); + return; + } + if (!(bridge.owner_discord_user_id == msg.author.id || msg.author.id == config.opID)) { + //msg.react('🚫'); + msg.reply(`You do not own that bridge.`); + return; + } + await dbClient.query("UPDATE bridges SET disabled = 'true' WHERE mpp_room = $1", [bridge.mpp_room]); + clients.MPP[bridge.mpp_room].stop(); + var channel = dClient.channels.get(bridge.discord_channel_id) + await channel.setParent(config.channels.deleted_bridges); + await channel.lockPermissions(); + msg.reply(`${bridge.mpp_room} has been unbridged.`); + } +}; \ No newline at end of file diff --git a/src/mppbridger/datacollector.js b/src/mppbridger/datacollector.js new file mode 100644 index 0000000..f6ee822 --- /dev/null +++ b/src/mppbridger/datacollector.js @@ -0,0 +1,37 @@ +module.exports = async function(gClient, site, room, DiscordChannel) { + var path = require('os').tmpdir(); + var filename = `${site} ${room} .txt`.replace(/\//g, ':'); + var filepath = path + "/" + filename; + var size = 0; + var startDate = new Date(); + gClient.on('ws created', function(){ + gClient.ws.addEventListener('message', msg => { + var data = msg.data; + if (data instanceof ArrayBuffer) data = Buffer.from(data).toString('base64'); + var line = `${Date.now()} ${data}\n`; + size += line.length; + fs.appendFile(filepath, line, ()=>{}); + if (size > 8000000) {save(); size = 0;} + }); + }); + async function save(callback){ + console.log(`saving data recording`, filename) + fs.readFile(filepath, (err, file) => { + if (err) return console.error(err); + require('zlib').gzip(file, async function(err, gzip){ + if (err) return console.error(err); + var attachmentName = `${site} ${room} raw data recording from ${startDate.toISOString()} to ${new Date().toISOString()} .txt.gz`; + await DiscordChannel.send(new Discord.MessageAttachment(gzip, attachmentName)); + fs.writeFileSync(filepath, ''); + size = 0; + startDate = new Date(); + console.log(`saved raw data recording`, attachmentName); + if (callback) callback(); + }); + }); + } + exitHook(callback => { + save(()=>callback()); + }); + gClient.dataCollectorSave = function(){save()}; // test +} \ No newline at end of file diff --git a/src/mppbridger/index.js b/src/mppbridger/index.js new file mode 100755 index 0000000..5b04aec --- /dev/null +++ b/src/mppbridger/index.js @@ -0,0 +1,283 @@ +var Client = require('../lib/Client.js'); +global.clients = {}; + + + +global.clientConnector = { + queue: [], + enqueue: function(client) { + if (this.queue.includes(client)) return; + this.queue.push(client); + }, + interval: setInterval(function(){ + var client = clientConnector.queue.shift(); + if (client) client.connect(); + }, 2000) +} + + + +global.createMPPbridge = function createMPPbridge(room, DiscordChannelID, site = 'MPP', webhookID, webhookToken) { + var DiscordChannel = dClient.channels.get(DiscordChannelID); + if (!DiscordChannel) return console.error(`Couldn't bridge ${site} ${room} because Discord Channel ${DiscordChannelID} is missing!`); + if (webhookID && webhookToken) var webhook = new Discord.WebhookClient(webhookID, webhookToken, {disableEveryone:true}); + + + // discord message sending + var msgBuffer = []; + function _dSend(msg, embed) { + if (webhook && !config.testmode) { + let username = gClient.channel && gClient.channel._id || room; + if (username.length > 32) username = username.substr(0,31) + '…'; + else if (username.length < 2) username = undefined; + webhook.send(msg, {username, embed, split:{char:''}}).catch(e => { + console.error(e); + DiscordChannel.send(msg, {embed, split:{char:''}}).catch(console.error); + }); + } + else DiscordChannel.send(msg, {embed, split:{char:''}}).catch(console.error); + } + function dSend(msg) { + msgBuffer.push(msg); + } + setInterval(()=>{ + if (msgBuffer.length == 0) return; + _dSend(msgBuffer.join('\n')); + msgBuffer = []; + }, 2000); //TODO make changeable + + + + + const gClient = + site == "MPP" ? new Client("ws://www.multiplayerpiano.com:443") : + site == "WOPP" ? new Client("ws://ourworldofpixels.com:1234") : + site == "MPT" ? new Client("ws://ts.terrium.net:8080") : + site == "VFDP" ? new Client("ws://www.visualfiredev.com:8080") : + undefined; + if (!gClient) return console.error(`Invalid site ${site}`); + gClient.setChannel(/*(site == "MPP" && room == "lobby") ? "lolwutsecretlobbybackdoor" : */room); + gClient.canConnect = true; + clientConnector.enqueue(gClient); + + + + + var isConnected = false; + gClient.on('connect', () => { + console.log(`Connected to room ${room} of ${site} server`); + dSend(`**Connected**`); // TODO say what room it actually connected to ? + isConnected = true; + }); + gClient.on('hi', ()=>{ + if (!testmode) gClient.sendArray([{m: "userset", set: {name: config.mppname}}]) + }); + gClient.on('disconnect', () => { + if (isConnected) { + console.log(`Disconnected from room ${room} of ${site} server`); + dSend(`**Disconnected**`); + isConnected = false; + } + clientConnector.enqueue(gClient); + }); + /*gClient.on('status', status => { + console.log(`[${site}] [${room}] ${status}`); + });*/ + + + + + let lastCh = room; + gClient.on('ch', msg => { + // announce channel change + if (lastCh && msg.ch._id !== lastCh) { + dSend(`**Channel changed from \`${lastCh}\` to \`${msg.ch._id}\`**`); + console.log(`[${site}][${room}] Channel changed from ${lastCh} to ${msg.ch._id}`); + lastCh = msg.ch._id; + } + (async function(){ + // catch dropped crown + if (msg.ch.crown && !msg.ch.crown.hasOwnProperty('participantId')) { + gClient.sendArray([{m:'chown', id: gClient.getOwnParticipant().id}]); // if possible + var avail_time = msg.ch.crown.time + 15000 - gClient.serverTimeOffset; + var ms = avail_time - Date.now(); + setTimeout(()=> gClient.sendArray([{m:'chown', id: gClient.getOwnParticipant().id}]) , ms); + } + // transfer crown to owner + if (msg.ppl && msg.ch.crown && msg.ch.crown.participantId == gClient.getOwnParticipant().id) { + var res = await dbClient.query("SELECT owner_mpp__id FROM bridges WHERE mpp_room = $1 AND site = $2;", [room, site]); + if (res.rows.length == 0) return; + var owner = res.rows[0].owner_mpp__id; + if (!owner) return; + msg.ppl.some(part => { + if (part._id == owner) { + gClient.sendArray([{m:'chown', id: part.id}]); + return true; + } else return false; + }); + } + })(); + }); + + + + + // MPP to Discord + gClient.on('a', msg => { + if (msg.p._id == gClient.getOwnParticipant()._id) return; + var id = msg.p._id.substr(0,6); + var name = msg.p.name.replace(/discord.gg\//g, 'discord.gg\\/'); + var str = `\`${id}\` **${name}:** ${msg.a}`; + str = str.replace(/<@/g, "<\\@"); + dSend(str); + }); + + // Discord to MPP + dClient.on('message', message => { + if (message.channel.id !== DiscordChannelID || message.author.bot || message.content.startsWith('!')) return; + var str = message.cleanContent; + var arr = []; + if (str.startsWith('/') || str.startsWith('\\')) { + arr.push({m:"a", message: + `⤹ ${message.member.displayName}` + }); + } else str = message.member.displayName + ': ' + str; + if (str.startsWith('\\')) str = str.slice(1); + if (message.attachments.first()) str += ' '+message.attachments.first().url; + if (str.length > 512) str = str.substr(0,511) + '…'; + arr.push({m:"a", message:str}); + gClient.sendArray(arr); + }); + + + + + // announce join/leave + gClient.on('participant added', participant => { + dSend(`**\`${participant._id.substr(0,6)}\` ${participant.name.replace(/<@/g, "<\\@")} entered the room.**`); + }); + gClient.on('participant removed', participant => { + dSend(`**\`${participant._id.substr(0,6)}\` ${participant.name.replace(/<@/g, "<\\@")} left the room.**`); + }); + + + + + gClient.on('notification', async msg => { + // show notification + _dSend(undefined, { + title: msg.title, + description: msg.text || msg.html + }); + + // handle bans + if (msg.text && (msg.text.startsWith('Banned from') || msg.text.startsWith('Currently banned from'))) { + // Banned from "{room}" for {n} minutes. + // Currently banned from "{room}" for {n} minutes. + let arr = msg.text.split(' '); + arr.pop(); + let minutes = arr.pop(); + + gClient.stop(); + setTimeout(()=>{ + gClient.setChannel(room); + gClient.start(); + }, minutes*60*1000+3000); + dSend(`**Attempting to rejoin in ${minutes} minutes.**`); + } + }); + + + // autoban perma-banned users + gClient.on("participant added", async part => { + var bans = (await dbClient.query("SELECT bans FROM bridges WHERE discord_channel_id = $1", [DiscordChannelID])).rows[0].bans; + if (!bans) return; + for (let b of bans) + if (part._id.startsWith(b)) + gClient.sendArray([{m: "kickban", _id: part._id, ms: 60*60*1000}]); + }) + + + + // make room invisible when nobody else is in it + gClient.on("ch", function(msg){ + if (gClient.isOwner()) { + if (gClient.countParticipants() <= 1) { + gClient.sendArray([{m:'chset', set: { visible: false }}]) + } else { + gClient.sendArray([{m:'chset', set: { visible: true }}]) + } + } + }); + + + + // addons + { + // collect names + gClient.on('participant update', function(participant){ + require('./namecollector').collect(participant); + }); + // record raw data + require('./datacollector')(gClient, site, room, DiscordChannel); + } + + if (!clients[site]) clients[site] = {}; + clients[site][room] = gClient; +}; + + + + + + + + + + + + + + + + + +// start +(async function () { + var res = await dbClient.query('SELECT * FROM bridges;'); + + var sites = {}; + res.rows.forEach(row => { + if (row.disabled) return; + if (!sites[row.site]) sites[row.site] = []; + sites[row.site].push(row); + }); + + for (let site in sites) { + let arr = sites[site]; + arr.sort((a, b) => {return a.position - b.position}); + let i = 0; + arr.forEach(bridge => { + setTimeout(function(){ + createMPPbridge(bridge.mpp_room, bridge.discord_channel_id, bridge.site, bridge.webhook_id, bridge.webhook_token, bridge.owner_mpp__id); + }, i); + i = i + 2000; + }); + } +})(); + + + + + + + + + + +// commands +commands.bridge = require('./commands/bridge'); +commands.unbridge = require('./commands/unbridge'); +commands.chown = require('./commands/chown'); +commands.list = require('./commands/list'); +commands.ban = require('./commands/ban'); diff --git a/src/mppbridger/namecollector.js b/src/mppbridger/namecollector.js new file mode 100644 index 0000000..68632bd --- /dev/null +++ b/src/mppbridger/namecollector.js @@ -0,0 +1,37 @@ +var nameCollector = module.exports = { + collection: mdbClient.db('heroku_jrtfvpd9').collection('ppl'), + collect: async function (participant) { + if (config.testmode) return; + if (participant.name == "Anonymous" || participant.name == "Anonymoose") return; + + var newMsg = function(continued){ + var str = `__**${participant._id}**__${continued ? ' (continued)' : ''}\n${participant.name}`; + return dClient.channels.get(config.channels.name_collection).send(str); + } + + var document = await this.collection.findOne({_id: participant._id}); + + if (document) { + // update person + if (document.names.includes(participant.name)) return; + document.names.push(participant.name); + this.collection.updateOne({_id: participant._id}, {$set:{names: document.names}}); + + let message = await dClient.channels.get(config.channels.name_collection).messages.fetch(document.discord_msg_id); + try { + await message.edit(message.content + ', ' + participant.name); + } catch(e) { + let message = await newMsg(true); + this.collection.updateOne({_id: participant._id}, {$set:{discord_msg_id: message.id}}); + } + } else { + // add new person + let message = await newMsg(); + nameCollector.collection.insertOne({ + _id: participant._id, + discord_msg_id: message.id, + names: [participant.name] + }); + } + } +} \ No newline at end of file diff --git a/src/screenshotter.js b/src/screenshotter.js index 0598e34..9682289 100755 --- a/src/screenshotter.js +++ b/src/screenshotter.js @@ -11,14 +11,14 @@ global.screenshotter = { var screenshot = await page.screenshot({type: 'png'}); var filename = `Screenshot of www.multiplayerpiano.com/lobby @ ${new Date().toISOString()}.png`; var attachment = new Discord.MessageAttachment(screenshot, filename); - await dClient.channels.get('383773548810076163').send(attachment); + await dClient.channels.get(config.channels.mpp_screenshot).send(attachment); await page.goto('http://ourworldofpixels.com'); await page.evaluate(function(){OWOP.camera.zoom = 1;}); await new Promise(resolve => setTimeout(resolve, 5000)); var screenshot = await page.screenshot({type: 'png'}); var filename = `Screenshot of ourworldofpixels.com/main @ ${new Date().toISOString()}.png`; var attachment = new Discord.MessageAttachment(screenshot, filename); - await dClient.channels.get('399079481161023492').send(attachment); + await dClient.channels.get(config.channels.owop_screenshot).send(attachment); await browser.close(); console.log('Finished screen captures'); }, diff --git a/src/util.js b/src/util.js new file mode 100644 index 0000000..4c41fc1 --- /dev/null +++ b/src/util.js @@ -0,0 +1,10 @@ +process.on('unhandledRejection', error => { + console.error(error.stack); +}); +process.on('uncaughtException', error => { + console.error(error.stack); +}); + +Array.prototype.random = function () { + return this[Math.floor(Math.random() * this.length)] +} \ No newline at end of file