diff --git a/package-lock.json b/package-lock.json index 56b8360..39b4c1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,14 +12,15 @@ "dependencies": { "canvas": "^2.7.0", "chalk": "^4.1.0", - "discord.js": "^13.2.0", + "discord.js": "^12.5.1", + "discord.js-lavalink-lib": "^0.1.8", "figlet": "^1.5.0", "glob": "^7.1.6", "inquirer": "^7.3.3", "mathjs": "^9.3.0", "moment": "^2.29.1", "ms": "^2.1.3", - "onion-lasers": "npm:onion-lasers-v13@^2.0.0", + "onion-lasers": "^1.1.2", "pet-pet-gif": "^1.0.8", "relevant-urban": "^2.0.0", "translate-google": "^1.4.3", @@ -40,7 +41,7 @@ "rimraf": "^3.0.2", "ts-jest": "^26.4.4", "tsc-watch": "^4.2.9", - "typescript": "^4.4.4" + "typescript": "^3.9.7" }, "optionalDependencies": { "fsevents": "^2.1.2" @@ -571,43 +572,10 @@ "node": ">=0.1.95" } }, - "node_modules/@discordjs/builders": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.6.0.tgz", - "integrity": "sha512-mH3Gx61LKk2CD05laCI9K5wp+a3NyASHDUGx83DGJFkqJlRlSV5WMJNY6RS37A5SjqDtGMF4wVR9jzFaqShe6Q==", - "dependencies": { - "@sindresorhus/is": "^4.0.1", - "discord-api-types": "^0.22.0", - "ow": "^0.27.0", - "ts-mixer": "^6.0.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@discordjs/builders/node_modules/discord-api-types": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", - "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==", - "engines": { - "node": ">=12" - } - }, - "node_modules/@discordjs/builders/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, "node_modules/@discordjs/collection": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.4.tgz", - "integrity": "sha512-PVrEJH+V6Ob0OwfagYQ/57kwt/HNEJxt5jqY4P+S3st9y29t9iokdnGMQoJXG5VEMAQIPbzu9Snw1F6yE8PdLA==", - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", + "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" }, "node_modules/@discordjs/form-data": { "version": "3.0.1", @@ -874,6 +842,21 @@ "node": ">= 10.14.2" } }, + "node_modules/@lavacord/discord.js": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@lavacord/discord.js/-/discord.js-0.0.5.tgz", + "integrity": "sha512-qc2lw0zB48fq4SrSlpMJOmogUXIeM5YvufQfPg0ubjp7jqm20JnOXF9fliy1MPdcKPnZ8LwIZ222H0+ghGzP/Q==", + "dependencies": { + "lavacord": "latest" + }, + "engines": { + "node": ">=10", + "npm": ">=5" + }, + "peerDependencies": { + "discord.js": "^12.1.1" + } + }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", @@ -893,19 +876,10 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, - "node_modules/@sapphire/async-queue": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.8.tgz", - "integrity": "sha512-Oi4EEi8vOne8RM1tCdQ3kYAtl/J6ztak3Th6wwGFqA2SVNJtedw196LjsLX0bK8Li8cwaljbFf08N+0zeqhkWQ==", - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/@sindresorhus/is": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", - "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", + "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", "engines": { "node": ">=10" }, @@ -1172,6 +1146,17 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.2.4", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz", @@ -1534,6 +1519,14 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, "node_modules/babel-jest": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", @@ -1856,6 +1849,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "engines": { "node": ">=6" } @@ -2353,59 +2347,33 @@ "node": ">= 10.14.2" } }, - "node_modules/discord-api-types": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.23.1.tgz", - "integrity": "sha512-igWmn+45mzXRWNEPU25I/pr8MwxHb767wAr51oy3VRLRcTlp5ADBbrBR0lq3SA1Rfw3MtM4TQu1xo3kxscfVdQ==", - "engines": { - "node": ">=12" - } - }, "node_modules/discord.js": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.2.0.tgz", - "integrity": "sha512-nyxUvL8wuQG38zx13wUMkpcA8koFszyiXdkSLwwM9opKW2LC2H5gD0cTZxImeJ6GtEnKPWT8xBiE8lLBmbNIhw==", + "version": "12.5.3", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz", + "integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==", "dependencies": { - "@discordjs/builders": "^0.6.0", - "@discordjs/collection": "^0.2.1", + "@discordjs/collection": "^0.1.6", "@discordjs/form-data": "^3.0.1", - "@sapphire/async-queue": "^1.1.5", - "@types/ws": "^8.2.0", - "discord-api-types": "^0.23.1", + "abort-controller": "^3.0.0", "node-fetch": "^2.6.1", - "ws": "^8.2.3" + "prism-media": "^1.2.9", + "setimmediate": "^1.0.5", + "tweetnacl": "^1.0.3", + "ws": "^7.4.4" }, "engines": { - "node": ">=16.6.0", - "npm": ">=7.0.0" + "node": ">=12.0.0" } }, - "node_modules/discord.js/node_modules/@types/ws": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz", - "integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==", + "node_modules/discord.js-lavalink-lib": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/discord.js-lavalink-lib/-/discord.js-lavalink-lib-0.1.8.tgz", + "integrity": "sha512-Kv4ps5AW4xYxMuJypHJrPL1occlV817CjHiIL7J09EdgzNRcKRIif0U6XMxWxi45Pg3DOl41Lw1V+J2GRsMgcw==", "dependencies": { - "@types/node": "*" - } - }, - "node_modules/discord.js/node_modules/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "@lavacord/discord.js": "0.0.5", + "axios": ">=0.21.1", + "discord.js": "^12.2.0", + "lavacord": "^1.1.7" } }, "node_modules/docopt": { @@ -2606,6 +2574,14 @@ "through": "~2.3.1" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/exec-sh": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", @@ -2885,125 +2861,23 @@ "node": ">=8" } }, - "node_modules/findup-sync/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "extraneous": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "node_modules/follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "extraneous": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "extraneous": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "extraneous": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "extraneous": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "extraneous": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "extraneous": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "extraneous": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/findup-sync/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "extraneous": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, "node_modules/for-in": { @@ -4784,6 +4658,19 @@ "node": ">=6" } }, + "node_modules/lavacord": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/lavacord/-/lavacord-1.1.9.tgz", + "integrity": "sha512-haZghbblO1w3Hodc9q63ZWgV5zA/jB6xFKS17fImK5aIdn0PkKuZ6AsJBxMFpR275v8GNYOxg6cTQBYBQ+batQ==", + "dependencies": { + "node-fetch": "^2.6.0", + "ws": "^7.3.0" + }, + "engines": { + "node": ">=10", + "npm": ">=5" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -4834,11 +4721,6 @@ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" - }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -5524,12 +5406,11 @@ } }, "node_modules/onion-lasers": { - "name": "onion-lasers-v13", - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/onion-lasers-v13/-/onion-lasers-v13-2.0.0.tgz", - "integrity": "sha512-HtMNLvFqSVt9mFkUJX7rwnH4d0894YmQ7167lLdtE8Wi/U2HYRSHHpB4xcLXrOPMMzcWZ4l+1knYN1OL0nL9mA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/onion-lasers/-/onion-lasers-1.1.2.tgz", + "integrity": "sha512-gQHQCdcfDSLeWFFXMTBCy2PZR/n603B+Q2L3vTj+9T1CmJS7OfO7zoFM5QrTkOY4N5hESboOdJ8eRvPXQgdxDg==", "dependencies": { - "discord.js": "^13.2.0", + "discord.js": "^12.5.3", "glob": "^7.1.6" } }, @@ -5558,50 +5439,6 @@ "node": ">=0.10.0" } }, - "node_modules/ow": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", - "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", - "dependencies": { - "@sindresorhus/is": "^4.0.1", - "callsites": "^3.1.0", - "dot-prop": "^6.0.1", - "lodash.isequal": "^4.5.0", - "type-fest": "^1.2.1", - "vali-date": "^1.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ow/node_modules/dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ow/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -5836,6 +5673,31 @@ "node": ">= 10" } }, + "node_modules/prism-media": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.9.tgz", + "integrity": "sha512-UHCYuqHipbTR1ZsXr5eg4JUmHER8Ss4YEb9Azn+9zzJ7/jlTtD1h0lc4g6tNx3eMlB8Mp6bfll0LPMAV4R6r3Q==", + "peerDependencies": { + "@discordjs/opus": "^0.5.0", + "ffmpeg-static": "^4.2.7 || ^3.0.0 || ^2.4.0", + "node-opus": "^0.3.3", + "opusscript": "^0.0.8" + }, + "peerDependenciesMeta": { + "@discordjs/opus": { + "optional": true + }, + "ffmpeg-static": { + "optional": true + }, + "node-opus": { + "optional": true + }, + "opusscript": { + "optional": true + } + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -6644,6 +6506,11 @@ "node": ">=0.10.0" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7507,11 +7374,6 @@ "typescript": ">=3.8 <5.0" } }, - "node_modules/ts-mixer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", - "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" - }, "node_modules/tsc-watch": { "version": "4.2.9", "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.2.9.tgz", @@ -7550,6 +7412,11 @@ "node": "*" } }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -7599,9 +7466,9 @@ } }, "node_modules/typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", + "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -7778,14 +7645,6 @@ "node": ">= 8" } }, - "node_modules/vali-date": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", - "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -7977,7 +7836,6 @@ "version": "7.4.5", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", - "dev": true, "engines": { "node": ">=8.3.0" }, @@ -8501,34 +8359,10 @@ "minimist": "^1.2.0" } }, - "@discordjs/builders": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.6.0.tgz", - "integrity": "sha512-mH3Gx61LKk2CD05laCI9K5wp+a3NyASHDUGx83DGJFkqJlRlSV5WMJNY6RS37A5SjqDtGMF4wVR9jzFaqShe6Q==", - "requires": { - "@sindresorhus/is": "^4.0.1", - "discord-api-types": "^0.22.0", - "ow": "^0.27.0", - "ts-mixer": "^6.0.0", - "tslib": "^2.3.1" - }, - "dependencies": { - "discord-api-types": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", - "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==" - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - } - } - }, "@discordjs/collection": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.4.tgz", - "integrity": "sha512-PVrEJH+V6Ob0OwfagYQ/57kwt/HNEJxt5jqY4P+S3st9y29t9iokdnGMQoJXG5VEMAQIPbzu9Snw1F6yE8PdLA==" + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", + "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" }, "@discordjs/form-data": { "version": "3.0.1", @@ -8751,6 +8585,14 @@ "chalk": "^4.0.0" } }, + "@lavacord/discord.js": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@lavacord/discord.js/-/discord.js-0.0.5.tgz", + "integrity": "sha512-qc2lw0zB48fq4SrSlpMJOmogUXIeM5YvufQfPg0ubjp7jqm20JnOXF9fliy1MPdcKPnZ8LwIZ222H0+ghGzP/Q==", + "requires": { + "lavacord": "latest" + } + }, "@mapbox/node-pre-gyp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", @@ -8767,15 +8609,10 @@ "tar": "^6.1.0" } }, - "@sapphire/async-queue": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.8.tgz", - "integrity": "sha512-Oi4EEi8vOne8RM1tCdQ3kYAtl/J6ztak3Th6wwGFqA2SVNJtedw196LjsLX0bK8Li8cwaljbFf08N+0zeqhkWQ==" - }, "@sindresorhus/is": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", - "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", + "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==" }, "@sinonjs/commons": { "version": "1.8.3", @@ -9033,6 +8870,14 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, "acorn": { "version": "8.2.4", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz", @@ -9305,6 +9150,14 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "babel-jest": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", @@ -9566,7 +9419,8 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true }, "camelcase": { "version": "5.3.1", @@ -9945,40 +9799,30 @@ "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true }, - "discord-api-types": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.23.1.tgz", - "integrity": "sha512-igWmn+45mzXRWNEPU25I/pr8MwxHb767wAr51oy3VRLRcTlp5ADBbrBR0lq3SA1Rfw3MtM4TQu1xo3kxscfVdQ==" - }, "discord.js": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.2.0.tgz", - "integrity": "sha512-nyxUvL8wuQG38zx13wUMkpcA8koFszyiXdkSLwwM9opKW2LC2H5gD0cTZxImeJ6GtEnKPWT8xBiE8lLBmbNIhw==", + "version": "12.5.3", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz", + "integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==", "requires": { - "@discordjs/builders": "^0.6.0", - "@discordjs/collection": "^0.2.1", + "@discordjs/collection": "^0.1.6", "@discordjs/form-data": "^3.0.1", - "@sapphire/async-queue": "^1.1.5", - "@types/ws": "^8.2.0", - "discord-api-types": "^0.23.1", + "abort-controller": "^3.0.0", "node-fetch": "^2.6.1", - "ws": "^8.2.3" - }, - "dependencies": { - "@types/ws": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz", - "integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==", - "requires": { - "@types/node": "*" - } - }, - "ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "requires": {} - } + "prism-media": "^1.2.9", + "setimmediate": "^1.0.5", + "tweetnacl": "^1.0.3", + "ws": "^7.4.4" + } + }, + "discord.js-lavalink-lib": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/discord.js-lavalink-lib/-/discord.js-lavalink-lib-0.1.8.tgz", + "integrity": "sha512-Kv4ps5AW4xYxMuJypHJrPL1occlV817CjHiIL7J09EdgzNRcKRIif0U6XMxWxi45Pg3DOl41Lw1V+J2GRsMgcw==", + "requires": { + "@lavacord/discord.js": "0.0.5", + "axios": ">=0.21.1", + "discord.js": "^12.2.0", + "lavacord": "^1.1.7" } }, "docopt": { @@ -10132,6 +9976,11 @@ "through": "~2.3.1" } }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, "exec-sh": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", @@ -10358,6 +10207,11 @@ "path-exists": "^4.0.0" } }, + "follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -11751,6 +11605,15 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "lavacord": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/lavacord/-/lavacord-1.1.9.tgz", + "integrity": "sha512-haZghbblO1w3Hodc9q63ZWgV5zA/jB6xFKS17fImK5aIdn0PkKuZ6AsJBxMFpR275v8GNYOxg6cTQBYBQ+batQ==", + "requires": { + "node-fetch": "^2.6.0", + "ws": "^7.3.0" + } + }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -11792,11 +11655,6 @@ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" - }, "lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -12332,11 +12190,11 @@ } }, "onion-lasers": { - "version": "npm:onion-lasers-v13@2.0.0", - "resolved": "https://registry.npmjs.org/onion-lasers-v13/-/onion-lasers-v13-2.0.0.tgz", - "integrity": "sha512-HtMNLvFqSVt9mFkUJX7rwnH4d0894YmQ7167lLdtE8Wi/U2HYRSHHpB4xcLXrOPMMzcWZ4l+1knYN1OL0nL9mA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/onion-lasers/-/onion-lasers-1.1.2.tgz", + "integrity": "sha512-gQHQCdcfDSLeWFFXMTBCy2PZR/n603B+Q2L3vTj+9T1CmJS7OfO7zoFM5QrTkOY4N5hESboOdJ8eRvPXQgdxDg==", "requires": { - "discord.js": "^13.2.0", + "discord.js": "^12.5.3", "glob": "^7.1.6" } }, @@ -12359,34 +12217,6 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, - "ow": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", - "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", - "requires": { - "@sindresorhus/is": "^4.0.1", - "callsites": "^3.1.0", - "dot-prop": "^6.0.1", - "lodash.isequal": "^4.5.0", - "type-fest": "^1.2.1", - "vali-date": "^1.0.0" - }, - "dependencies": { - "dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", - "requires": { - "is-obj": "^2.0.0" - } - }, - "type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==" - } - } - }, "p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -12552,6 +12382,12 @@ "react-is": "^17.0.1" } }, + "prism-media": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.9.tgz", + "integrity": "sha512-UHCYuqHipbTR1ZsXr5eg4JUmHER8Ss4YEb9Azn+9zzJ7/jlTtD1h0lc4g6tNx3eMlB8Mp6bfll0LPMAV4R6r3Q==", + "requires": {} + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -13182,6 +13018,11 @@ } } }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -13872,11 +13713,6 @@ "yargs-parser": "20.x" } }, - "ts-mixer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", - "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" - }, "tsc-watch": { "version": "4.2.9", "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.2.9.tgz", @@ -13903,6 +13739,11 @@ "safe-buffer": "^5.0.1" } }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -13937,9 +13778,9 @@ } }, "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", + "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", "dev": true }, "underscore": { @@ -14081,11 +13922,6 @@ } } }, - "vali-date": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", - "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=" - }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -14246,7 +14082,6 @@ "version": "7.4.5", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", - "dev": true, "requires": {} }, "xdg-basedir": { diff --git a/package.json b/package.json index a6721c6..7347513 100644 --- a/package.json +++ b/package.json @@ -17,14 +17,15 @@ "dependencies": { "canvas": "^2.7.0", "chalk": "^4.1.0", - "discord.js": "^13.2.0", + "discord.js": "^12.5.1", + "discord.js-lavalink-lib": "^0.1.8", "figlet": "^1.5.0", "glob": "^7.1.6", "inquirer": "^7.3.3", "mathjs": "^9.3.0", "moment": "^2.29.1", "ms": "^2.1.3", - "onion-lasers": "npm:onion-lasers-v13@^2.0.0", + "onion-lasers": "^1.1.2", "pet-pet-gif": "^1.0.8", "relevant-urban": "^2.0.0", "translate-google": "^1.4.3", @@ -45,7 +46,7 @@ "rimraf": "^3.0.2", "ts-jest": "^26.4.4", "tsc-watch": "^4.2.9", - "typescript": "^4.4.4" + "typescript": "^3.9.7" }, "optionalDependencies": { "fsevents": "^2.1.2" diff --git a/src/commands/fun/figlet.ts b/src/commands/fun/figlet.ts index ae97069..8764ff4 100644 --- a/src/commands/fun/figlet.ts +++ b/src/commands/fun/figlet.ts @@ -1,6 +1,5 @@ import {NamedCommand, RestCommand} from "onion-lasers"; import figlet from "figlet"; -import {Util} from "discord.js"; export default new NamedCommand({ description: "Generates a figlet of your input.", @@ -8,11 +7,12 @@ export default new NamedCommand({ any: new RestCommand({ async run({send, combined}) { return send( - `\`\`\`\n${Util.cleanCodeBlockContent( - figlet.textSync(combined, { - horizontalLayout: "full" - }) - )}\n\`\`\`` + figlet.textSync(combined, { + horizontalLayout: "full" + }), + { + code: true + } ); } }) diff --git a/src/commands/fun/insult.ts b/src/commands/fun/insult.ts index 05603d9..76491b3 100644 --- a/src/commands/fun/insult.ts +++ b/src/commands/fun/insult.ts @@ -3,12 +3,12 @@ import {NamedCommand} from "onion-lasers"; export default new NamedCommand({ description: "Insult TravBot! >:D", async run({send, channel, author}) { - channel.sendTyping(); + channel.startTyping(); setTimeout(() => { send( `${author} What the fuck did you just fucking say about me, you little bitch? I'll have you know I graduated top of my class in the Navy Seals, and I've been involved in numerous secret raids on Al-Quaeda, and I have over 300 confirmed kills. I am trained in gorilla warfare and I'm the top sniper in the entire US armed forces. You are nothing to me but just another target. I will wipe you the fuck out with precision the likes of which has never been seen before on this Earth, mark my fucking words. You think you can get away with saying that shit to me over the Internet? Think again, fucker. As we speak I am contacting my secret network of spies across the USA and your IP is being traced right now so you better prepare for the storm, maggot. The storm that wipes out the pathetic little thing you call your life. You're fucking dead, kid. I can be anywhere, anytime, and I can kill you in over seven hundred ways, and that's just with my bare hands. Not only am I extensively trained in unarmed combat, but I have access to the entire arsenal of the United States Marine Corps and I will use it to its full extent to wipe your miserable ass off the face of the continent, you little shit. If only you could have known what unholy retribution your little "clever" comment was about to bring down upon you, maybe you would have held your fucking tongue. But you couldn't, you didn't, and now you're paying the price, you goddamn idiot. I will shit fury all over you and you will drown in it. You're fucking dead, kiddo.` ); - channel.sendTyping(); + channel.stopTyping(); }, 60000); } }); diff --git a/src/commands/fun/modules/eco-bet.ts b/src/commands/fun/modules/eco-bet.ts index 9852f6a..0fb6096 100644 --- a/src/commands/fun/modules/eco-bet.ts +++ b/src/commands/fun/modules/eco-bet.ts @@ -39,12 +39,9 @@ export const BetCommand = new NamedCommand({ // handle invalid amount if (amount <= 0) return send("You must bet at least one Mon!"); else if (sender.money < amount) - return send({content: "You don't have enough Mons for that.", embeds: [getMoneyEmbed(author)]}); + return send("You don't have enough Mons for that.", getMoneyEmbed(author)); else if (receiver.money < amount) - return send({ - content: "They don't have enough Mons for that.", - embeds: [getMoneyEmbed(target)] - }); + return send("They don't have enough Mons for that.", getMoneyEmbed(target)); return send("How long until the bet ends?"); } else return; @@ -70,15 +67,9 @@ export const BetCommand = new NamedCommand({ // handle invalid amount if (amount <= 0) return send("You must bet at least one Mon!"); else if (sender.money < amount) - return send({ - content: "You don't have enough Mons for that.", - embeds: [getMoneyEmbed(author)] - }); + return send("You don't have enough Mons for that.", getMoneyEmbed(author)); else if (receiver.money < amount) - return send({ - content: "They don't have enough Mons for that.", - embeds: [getMoneyEmbed(target)] - }); + return send("They don't have enough Mons for that.", getMoneyEmbed(target)); // handle invalid duration if (duration <= 0) return send("Invalid bet duration"); @@ -116,7 +107,7 @@ export const BetCommand = new NamedCommand({ ); // Wait for the duration of the bet. - return setTimeout(async () => { + return client.setTimeout(async () => { // In debug mode, saving the storage will break the references, so you have to redeclare sender and receiver for it to actually save. const sender = Storage.getUser(author.id); const receiver = Storage.getUser(target.id); diff --git a/src/commands/fun/modules/eco-core.ts b/src/commands/fun/modules/eco-core.ts index 841b736..388f576 100644 --- a/src/commands/fun/modules/eco-core.ts +++ b/src/commands/fun/modules/eco-core.ts @@ -16,26 +16,27 @@ export const DailyCommand = new NamedCommand({ user.lastReceived = now; Storage.save(); send({ - embeds: [ - { - title: "Daily Reward", - description: "You received 1 Mon!", - color: ECO_EMBED_COLOR - } - ] + embed: { + title: "Daily Reward", + description: "You received 1 Mon!", + color: ECO_EMBED_COLOR, + fields: [ + { + name: "New balance:", + value: pluralise(user.money, "Mon", "s") + } + ] + } }); } else send({ - embeds: [ - { - title: "Daily Reward", - description: `It's too soon to pick up your daily Mons. You have about ${( - (user.lastReceived + 79200000 - now) / - 3600000 - ).toFixed(1)} hours to go.`, - color: ECO_EMBED_COLOR - } - ] + embed: { + title: "Daily Reward", + description: `It's too soon to pick up your daily Mons. Try again at .`, + color: ECO_EMBED_COLOR + } }); } } @@ -54,27 +55,25 @@ export const GuildCommand = new NamedCommand({ } send({ - embeds: [ - { - title: `The Bank of ${guild!.name}`, - color: ECO_EMBED_COLOR, - fields: [ - { - name: "Accounts", - value: Object.keys(users).length.toString(), - inline: true - }, - { - name: "Total Mons", - value: totalAmount.toString(), - inline: true - } - ], - thumbnail: { - url: guild?.iconURL() ?? "" + embed: { + title: `The Bank of ${guild!.name}`, + color: ECO_EMBED_COLOR, + fields: [ + { + name: "Accounts", + value: Object.keys(users).length, + inline: true + }, + { + name: "Total Mons", + value: totalAmount, + inline: true } + ], + thumbnail: { + url: guild?.iconURL() ?? "" } - ] + } }); } } @@ -101,16 +100,14 @@ export const LeaderboardCommand = new NamedCommand({ } send({ - embeds: [ - { - title: "Top 10 Richest Players", - color: ECO_EMBED_COLOR, - fields: fields, - thumbnail: { - url: guild?.iconURL() ?? "" - } + embed: { + title: "Top 10 Richest Players", + color: ECO_EMBED_COLOR, + fields: fields, + thumbnail: { + url: guild?.iconURL() ?? "" } - ] + } }); } } @@ -133,7 +130,7 @@ export const PayCommand = new NamedCommand({ if (amount <= 0) return send("You must send at least one Mon!"); else if (sender.money < amount) - return send({content: "You don't have enough Mons for that.", embeds: [getMoneyEmbed(author)]}); + return send("You don't have enough Mons for that.", getMoneyEmbed(author)); else if (target.id === author.id) return send("You can't send Mons to yourself!"); else if (target.bot && !IS_DEV_MODE) return send("You can't send Mons to a bot!"); @@ -160,7 +157,7 @@ export const PayCommand = new NamedCommand({ if (amount <= 0) return send("You must send at least one Mon!"); else if (sender.money < amount) - return send({content: "You don't have enough Mons to do that!", embeds: [getMoneyEmbed(author)]}); + return send("You don't have enough Mons to do that!", getMoneyEmbed(author)); else if (!guild) return send("You have to use this in a server if you want to send Mons with a username!"); @@ -171,20 +168,17 @@ export const PayCommand = new NamedCommand({ else if (user.bot && !IS_DEV_MODE) return send("You can't send Mons to a bot!"); const confirmed = await confirm( - await send({ - content: `Are you sure you want to send ${pluralise(amount, "Mon", "s")} to this person?`, - embeds: [ - { - color: ECO_EMBED_COLOR, - author: { - name: user.tag, - icon_url: user.displayAvatarURL({ - format: "png", - dynamic: true - }) - } + await send(`Are you sure you want to send ${pluralise(amount, "Mon", "s")} to this person?`, { + embed: { + color: ECO_EMBED_COLOR, + author: { + name: user.tag, + icon_url: user.displayAvatarURL({ + format: "png", + dynamic: true + }) } - ] + } }), author.id ); diff --git a/src/commands/fun/modules/eco-extras.ts b/src/commands/fun/modules/eco-extras.ts index 35a46b4..d3a3519 100644 --- a/src/commands/fun/modules/eco-extras.ts +++ b/src/commands/fun/modules/eco-extras.ts @@ -21,7 +21,7 @@ export const MondayCommand = new NamedCommand({ user.money++; user.lastMonday = now.getTime(); Storage.save(); - send({content: "It is **Mon**day, my dudes.", embeds: [getMoneyEmbed(author)]}); + send("It is **Mon**day, my dudes.", getMoneyEmbed(author)); } else send("You've already claimed your **Mon**day reward for this week."); } else { const weekdayName = WEEKDAY[weekday]; @@ -47,7 +47,7 @@ export const AwardCommand = new NamedCommand({ const user = Storage.getUser(target.id); user.money++; Storage.save(); - send({content: `1 Mon given to ${target.username}.`, embeds: [getMoneyEmbed(target)]}); + send(`1 Mon given to ${target.username}.`, getMoneyEmbed(target)); } else { send("This command is restricted to the bean."); } @@ -62,10 +62,7 @@ export const AwardCommand = new NamedCommand({ const user = Storage.getUser(target.id); user.money += amount; Storage.save(); - send({ - content: `${pluralise(amount, "Mon", "s")} given to ${target.username}.`, - embeds: [getMoneyEmbed(target)] - }); + send(`${pluralise(amount, "Mon", "s")} given to ${target.username}.`, getMoneyEmbed(target)); } else { send("You need to enter a number greater than 0."); } diff --git a/src/commands/fun/modules/eco-shop-items.ts b/src/commands/fun/modules/eco-shop-items.ts index bc5d58c..f3cf143 100644 --- a/src/commands/fun/modules/eco-shop-items.ts +++ b/src/commands/fun/modules/eco-shop-items.ts @@ -52,8 +52,7 @@ export const ShopItems: ShopItem[] = [ description: "Buys what is technically a laser bridge.", usage: "laser bridge", run(message) { - message.channel.send({ - content: random(lines), + message.channel.send(random(lines), { files: [ { attachment: diff --git a/src/commands/fun/modules/eco-shop.ts b/src/commands/fun/modules/eco-shop.ts index ec36820..8092854 100644 --- a/src/commands/fun/modules/eco-shop.ts +++ b/src/commands/fun/modules/eco-shop.ts @@ -3,13 +3,13 @@ import {pluralise, split} from "../../../lib"; import {Storage, getPrefix} from "../../../structures"; import {isAuthorized, ECO_EMBED_COLOR} from "./eco-utils"; import {ShopItems, ShopItem} from "./eco-shop-items"; -import {EmbedField, MessageEmbedOptions} from "discord.js"; +import {EmbedField} from "discord.js"; export const ShopCommand = new NamedCommand({ description: "Displays the list of items you can buy in the shop.", async run({send, guild, channel, author}) { if (isAuthorized(guild, channel)) { - function getShopEmbed(selection: ShopItem[], title: string): MessageEmbedOptions { + function getShopEmbed(selection: ShopItem[], title: string) { const fields: EmbedField[] = []; for (const item of selection) @@ -20,11 +20,13 @@ export const ShopCommand = new NamedCommand({ }); return { - color: ECO_EMBED_COLOR, - title: title, - fields: fields, - footer: { - text: "Mon Shop | TravBot Services" + embed: { + color: ECO_EMBED_COLOR, + title: title, + fields: fields, + footer: { + text: "Mon Shop | TravBot Services" + } } }; } @@ -33,14 +35,10 @@ export const ShopCommand = new NamedCommand({ const pageAmount = shopPages.length; paginate(send, author.id, pageAmount, (page, hasMultiplePages) => { - return { - embeds: [ - getShopEmbed( - shopPages[page], - hasMultiplePages ? `Shop (Page ${page + 1} of ${pageAmount})` : "Shop" - ) - ] - }; + return getShopEmbed( + shopPages[page], + hasMultiplePages ? `Shop (Page ${page + 1} of ${pageAmount})` : "Shop" + ); }); } } diff --git a/src/commands/fun/modules/eco-utils.ts b/src/commands/fun/modules/eco-utils.ts index 53bc7f4..08ef031 100644 --- a/src/commands/fun/modules/eco-utils.ts +++ b/src/commands/fun/modules/eco-utils.ts @@ -1,6 +1,6 @@ import {pluralise} from "../../../lib"; import {Storage} from "../../../structures"; -import {User, Guild, TextChannel, DMChannel, NewsChannel, Channel, TextBasedChannels} from "discord.js"; +import {User, Guild, TextChannel, DMChannel, NewsChannel} from "discord.js"; export const ECO_EMBED_COLOR = 0xf1c40f; @@ -61,10 +61,18 @@ export function getSendEmbed(sender: User, receiver: User, amount: number): obje }; } -export function isAuthorized(guild: Guild | null, channel: TextBasedChannels): boolean { - if ((guild?.id === "637512823676600330" && channel?.id === "669464416420364288") || IS_DEV_MODE) return true; - else { - channel.send("Sorry, this command can only be used in Monika's emote server. (#mon-stocks)"); +export function isAuthorized(guild: Guild | null, channel: TextChannel | DMChannel | NewsChannel): boolean { + if (IS_DEV_MODE) { + return true; + } + + if (guild?.id !== "637512823676600330") { + channel.send("Sorry, this command can only be used in Monika's emote server."); return false; + } else if (channel?.id !== "669464416420364288") { + channel.send("Sorry, this command can only be used in <#669464416420364288>."); + return false; + } else { + return true; } } diff --git a/src/commands/fun/pat.ts b/src/commands/fun/pat.ts index a1e91fb..f60b41b 100644 --- a/src/commands/fun/pat.ts +++ b/src/commands/fun/pat.ts @@ -10,11 +10,11 @@ export default new NamedCommand({ const attachment = message.attachments.first()!; const gif = await petPetGif(attachment.url); const file = new MessageAttachment(gif, "pat.gif"); - send({attachments: [file]}); + send(file); } else { const gif = await petPetGif(author.displayAvatarURL({format: "png"})); const file = new MessageAttachment(gif, "pat.gif"); - send({attachments: [file]}); + send(file); } }, id: "user", @@ -24,7 +24,7 @@ export default new NamedCommand({ const user: User = args[0]; const gif = await petPetGif(user.displayAvatarURL({format: "png"})); const file = new MessageAttachment(gif, "pat.gif"); - send({attachments: [file]}); + send(file); } }), any: new RestCommand({ @@ -36,7 +36,7 @@ export default new NamedCommand({ else { const gif = await petPetGif(user.displayAvatarURL({format: "png"})); const file = new MessageAttachment(gif, "pat.gif"); - send({attachments: [file]}); + send(file); } } }) diff --git a/src/commands/fun/poll.ts b/src/commands/fun/poll.ts index 40f9287..5cfd446 100644 --- a/src/commands/fun/poll.ts +++ b/src/commands/fun/poll.ts @@ -33,35 +33,26 @@ async function execPoll(send: SendFunction, message: Message, user: User, questi dynamic: true, size: 2048 }) || user.defaultAvatarURL; - const msg = await send({ - embeds: [ - new MessageEmbed() - .setAuthor(`Poll created by ${message.author.username}`, icon) - .setColor(0xffffff) - .setFooter("React to vote.") - .setDescription(question) - ] - }); + const msg = await send( + new MessageEmbed() + .setAuthor(`Poll created by ${message.author.username}`, icon) + .setColor(0xffffff) + .setFooter("React to vote.") + .setDescription(question) + ); const results = await poll(msg, [AGREE, DISAGREE], duration); - send({ - embeds: [ - new MessageEmbed() - .setAuthor(`The results of ${message.author.username}'s poll:`, icon) - .setTitle(question) - .setDescription( - `${AGREE} - ${pluralise( - results[AGREE], - "", - "people who agree", - "person who agrees" - )}\n${DISAGREE} - ${pluralise( - results[DISAGREE], - "", - "people who disagree", - "person who disagrees" - )}` - ) - ] - }); + send( + new MessageEmbed() + .setAuthor(`The results of ${message.author.username}'s poll:`, icon) + .setTitle(question) + .setDescription( + `${AGREE} - ${pluralise( + results[AGREE], + "", + "people who agree", + "person who agrees" + )}\n${DISAGREE} - ${pluralise(results[DISAGREE], "", "people who disagree", "person who disagrees")}` + ) + ); msg.delete(); } diff --git a/src/commands/fun/ravi.ts b/src/commands/fun/ravi.ts index d5ef2ef..b1b0b4c 100644 --- a/src/commands/fun/ravi.ts +++ b/src/commands/fun/ravi.ts @@ -6,17 +6,15 @@ export default new NamedCommand({ usage: "[number from 1 to 9]", async run({send}) { send({ - embeds: [ - { - title: "Ravioli ravioli...", - image: { - url: `https://raw.githubusercontent.com/keanuplayz/TravBot/master/assets/ravi${Random.int( - 1, - 10 - )}.png` - } + embed: { + title: "Ravioli ravioli...", + image: { + url: `https://raw.githubusercontent.com/keanuplayz/TravBot/master/assets/ravi${Random.int( + 1, + 10 + )}.png` } - ] + } }); }, number: new Command({ @@ -25,14 +23,12 @@ export default new NamedCommand({ if (arg >= 1 && arg <= 9) { send({ - embeds: [ - { - title: "Ravioli ravioli...", - image: { - url: `https://raw.githubusercontent.com/keanuplayz/TravBot/master/assets/ravi${arg}.png` - } + embed: { + title: "Ravioli ravioli...", + image: { + url: `https://raw.githubusercontent.com/keanuplayz/TravBot/master/assets/ravi${arg}.png` } - ] + } }); } else { send("Please provide a number between 1 and 9."); diff --git a/src/commands/fun/thonk.ts b/src/commands/fun/thonk.ts index 2dc420c..76e3d17 100644 --- a/src/commands/fun/thonk.ts +++ b/src/commands/fun/thonk.ts @@ -36,25 +36,25 @@ export default new NamedCommand({ usage: "([text])", async run({send, author}) { const msg = await send(transform(phrase)); - msg.createReactionCollector({ - filter: (reaction, user) => { + msg.createReactionCollector( + (reaction, user) => { if (user.id === author.id && reaction.emoji.name === "❌") msg.delete(); return false; }, - time: 60000 - }); + {time: 60000} + ); }, any: new RestCommand({ async run({send, author, combined}) { phrase = combined; const msg = await send(transform(phrase)); - msg.createReactionCollector({ - filter: (reaction, user) => { + msg.createReactionCollector( + (reaction, user) => { if (user.id === author.id && reaction.emoji.name === "❌") msg.delete(); return false; }, - time: 60000 - }); + {time: 60000} + ); } }) }); diff --git a/src/commands/fun/urban.ts b/src/commands/fun/urban.ts index e5d1efe..94aca51 100644 --- a/src/commands/fun/urban.ts +++ b/src/commands/fun/urban.ts @@ -21,7 +21,7 @@ export default new NamedCommand({ if (res.tags && res.tags.length > 0 && res.tags.join(" ").length < 1024) embed.addField("Tags", res.tags.join(", "), true); - send({embeds: [embed]}); + send(embed); }) .catch(() => { send("Sorry, that word was not found."); diff --git a/src/commands/fun/weather.ts b/src/commands/fun/weather.ts index 9720256..9246dc1 100644 --- a/src/commands/fun/weather.ts +++ b/src/commands/fun/weather.ts @@ -29,7 +29,7 @@ export default new NamedCommand({ .addField("Winds", current.winddisplay, true) .addField("Humidity", `${current.humidity}%`, true); return send({ - embeds: [embed] + embed }); } ); diff --git a/src/commands/fun/whois.ts b/src/commands/fun/whois.ts index 08a7e59..9996e7b 100644 --- a/src/commands/fun/whois.ts +++ b/src/commands/fun/whois.ts @@ -57,7 +57,7 @@ export default new NamedCommand({ const id = author.id; if (id in registry) { - send({content: `${author} ${registry[id]}`, allowedMentions: {parse: []}}); + send(`${author} ${registry[id]}`, {allowedMentions: {parse: []}}); } else { send("You haven't been added to the registry yet!"); } @@ -69,9 +69,9 @@ export default new NamedCommand({ const id = user.id; if (id in registry) { - send({content: `${user} ${registry[id]}`, allowedMentions: {parse: []}}); + send(`${user} ${registry[id]}`, {allowedMentions: {parse: []}}); } else { - send({content: `${user} hasn't been added to the registry yet!`, allowedMentions: {parse: []}}); + send(`${user} hasn't been added to the registry yet!`, {allowedMentions: {parse: []}}); } } }), @@ -81,9 +81,9 @@ export default new NamedCommand({ if (typeof user !== "string") { if (user.id in registry) { - send({content: `${user} ${registry[user.id]}`, allowedMentions: {parse: []}}); + send(`${user} ${registry[user.id]}`, {allowedMentions: {parse: []}}); } else { - send({content: `${user} hasn't been added to the registry yet!`, allowedMentions: {parse: []}}); + send(`${user} hasn't been added to the registry yet!`, {allowedMentions: {parse: []}}); } } else { send(user); diff --git a/src/commands/system/admin.ts b/src/commands/system/admin.ts index 0809672..2e2d579 100644 --- a/src/commands/system/admin.ts +++ b/src/commands/system/admin.ts @@ -1,7 +1,9 @@ import {Command, NamedCommand, getPermissionLevel, getPermissionName, CHANNEL_TYPE, RestCommand} from "onion-lasers"; +import {clean} from "../../lib"; import {Config, Storage} from "../../structures"; -import {Permissions, TextChannel, User, Role, Channel, Util} from "discord.js"; +import {Permissions, TextChannel, User, Role, Channel} from "discord.js"; import {logs} from "../../modules/globals"; +import {inspect} from "util"; function getLogBuffer(type: string) { return { @@ -280,7 +282,7 @@ export default new NamedCommand({ const newName = combined; if (!voiceChannel) return send("You are not in a voice channel."); - if (!guild!.me?.permissions.has(Permissions.FLAGS.MANAGE_CHANNELS)) + if (!guild!.me?.hasPermission(Permissions.FLAGS.MANAGE_CHANNELS)) return send("I can't change channel names without the `Manage Channels` permission."); guildStorage.channelNames[voiceChannel.id] = newName; @@ -330,30 +332,6 @@ export default new NamedCommand({ } }) }), - purge: new NamedCommand({ - description: "Purges the bot's own messages.", - permission: PERMISSIONS.BOT_SUPPORT, - channelType: CHANNEL_TYPE.GUILD, - async run({send, message, channel, guild, client}) { - // It's probably better to go through the bot's own messages instead of calling bulkDelete which requires MANAGE_MESSAGES. - if (guild!.me?.permissions.has(Permissions.FLAGS.MANAGE_MESSAGES)) { - message.delete(); - const msgs = await channel.messages.fetch({ - limit: 100 - }); - const travMessages = msgs.filter((m) => m.author.id === client.user?.id); - - await send(`Found ${travMessages.size} messages to delete.`).then((m) => { - setTimeout(() => { - m.delete(); - }, 5000); - }); - await (channel as TextChannel).bulkDelete(travMessages); - } else { - send("This command must be executed in a guild where I have the `MANAGE_MESSAGES` permission."); - } - } - }), clear: new NamedCommand({ description: "Clears a given amount of messages.", usage: "", @@ -370,34 +348,28 @@ export default new NamedCommand({ } }) }), - // TODO: Reimplement this entire command, for `send` doesn't allow - // types like `unknown` to be sent anymore. Perhaps try to echo - // whatever `evaled` is into an empty buffer and send this. - // (see: `Buffer.alloc(...)`) This is unlikely to work though, since - // `Buffer.alloc(...)` requires a length, which we can't retrieve from - // an `unknown` variable. - // eval: new NamedCommand({ - // description: "Evaluate code.", - // usage: "", - // permission: PERMISSIONS.BOT_OWNER, - // run: "You have to enter some code to execute first.", - // any: new RestCommand({ - // // You have to bring everything into scope to use them. AFAIK, there isn't a more maintainable way to do this, but at least TS will let you know if anything gets removed. - // async run({send, message, channel, guild, author, member, client, args, combined}) { - // try { - // let evaled: unknown = eval(combined); - // // If promises like message.channel.send() are invoked, await them so unnecessary error reports don't leak into the command handler. - // // Also, it's more useful to see the value rather than Promise { }. - // if (evaled instanceof Promise) evaled = await evaled; - // if (typeof evaled !== "string") evaled = inspect(evaled); - // // Also await this send call so that if the message is empty, it doesn't leak into the command handler. - // await send(clean(evaled), {code: "js", split: true}); - // } catch (err) { - // send(clean(err), {code: "js", split: true}); - // } - // } - // }) - // }), + eval: new NamedCommand({ + description: "Evaluate code.", + usage: "", + permission: PERMISSIONS.BOT_OWNER, + run: "You have to enter some code to execute first.", + any: new RestCommand({ + // You have to bring everything into scope to use them. AFAIK, there isn't a more maintainable way to do this, but at least TS will let you know if anything gets removed. + async run({send, message, channel, guild, author, member, client, args, combined}) { + try { + let evaled: unknown = eval(combined); + // If promises like message.channel.send() are invoked, await them so unnecessary error reports don't leak into the command handler. + // Also, it's more useful to see the value rather than Promise { }. + if (evaled instanceof Promise) evaled = await evaled; + if (typeof evaled !== "string") evaled = inspect(evaled); + // Also await this send call so that if the message is empty, it doesn't leak into the command handler. + await send(clean(evaled), {code: "js", split: true}); + } catch (err) { + send(clean(err), {code: "js", split: true}); + } + } + }) + }), nick: new NamedCommand({ description: "Change the bot's nickname.", permission: PERMISSIONS.BOT_SUPPORT, @@ -414,12 +386,8 @@ export default new NamedCommand({ description: "Shows a list of all guilds the bot is a member of.", permission: PERMISSIONS.BOT_SUPPORT, async run({send, client}) { - const guildList = Util.splitMessage( - Array.from(client.guilds.cache.map((e) => e.name).values()).join("\n") - ); - for (let guildListPart of guildList) { - send(guildListPart); - } + const guildList = client.guilds.cache.array().map((e) => e.name); + send(guildList, {split: true}); } }), activity: new NamedCommand({ diff --git a/src/commands/system/help.ts b/src/commands/system/help.ts index 9079999..f1d9b51 100644 --- a/src/commands/system/help.ts +++ b/src/commands/system/help.ts @@ -22,7 +22,7 @@ export default new NamedCommand({ const helpMenuPages: [string, string][] = []; // An array of (category, description) tuples. // Prevent the description of one category from overflowing by splitting it into multiple pages if needed. - for (const category of commands.keys()) { + for (const category of commands.keyArray()) { const commandList = commands.get(category)!; let output = LEGEND; @@ -45,16 +45,10 @@ export default new NamedCommand({ paginate(send, author.id, helpMenuPages.length, (page, hasMultiplePages) => { const [category, output] = helpMenuPages[page]; - return { - embeds: [ - new MessageEmbed() - .setTitle( - hasMultiplePages ? `${category} (Page ${page + 1} of ${helpMenuPages.length})` : category - ) - .setDescription(output) - .setColor(EMBED_COLOR) - ] - }; + return new MessageEmbed() + .setTitle(hasMultiplePages ? `${category} (Page ${page + 1} of ${helpMenuPages.length})` : category) + .setDescription(output) + .setColor(EMBED_COLOR); }); }, any: new RestCommand({ @@ -93,45 +87,43 @@ export default new NamedCommand({ aliases = formattedAliases.join(", ") || "None"; } - return send({ - embeds: [ - new MessageEmbed() - .setTitle(header) - .setDescription(command.description) - .setColor(EMBED_COLOR) - .addFields( - { - name: "Aliases", - value: aliases, - inline: true - }, - { - name: "Category", - value: category, - inline: true - }, - { - name: "Permission Required", - value: `\`${getPermissionName(result.permission)}\` (Level ${result.permission})`, - inline: true - }, - { - name: "Channel Type", - value: getChannelTypeName(result.channelType), - inline: true - }, - { - name: "NSFW Only?", - value: result.nsfw ? "Yes" : "No", - inline: true - }, - { - name: "Usages", - value: append - } - ) - ] - }); + return send( + new MessageEmbed() + .setTitle(header) + .setDescription(command.description) + .setColor(EMBED_COLOR) + .addFields( + { + name: "Aliases", + value: aliases, + inline: true + }, + { + name: "Category", + value: category, + inline: true + }, + { + name: "Permission Required", + value: `\`${getPermissionName(result.permission)}\` (Level ${result.permission})`, + inline: true + }, + { + name: "Channel Type", + value: getChannelTypeName(result.channelType), + inline: true + }, + { + name: "NSFW Only?", + value: result.nsfw ? "Yes" : "No", + inline: true + }, + { + name: "Usages", + value: append + } + ) + ); } }) }); diff --git a/src/commands/utility/calc.ts b/src/commands/utility/calc.ts index 15fd85d..0e85165 100644 --- a/src/commands/utility/calc.ts +++ b/src/commands/utility/calc.ts @@ -18,7 +18,7 @@ export default new NamedCommand({ .setTitle("Math Calculation") .addField("Input", `\`\`\`js\n${combined}\`\`\``) .addField("Output", `\`\`\`js\n${resp}\`\`\``); - return send({embeds: [embed]}); + return send(embed); } }) }); diff --git a/src/commands/utility/desc.ts b/src/commands/utility/desc.ts index beb8595..68c5c17 100644 --- a/src/commands/utility/desc.ts +++ b/src/commands/utility/desc.ts @@ -9,7 +9,7 @@ export default new NamedCommand({ const voiceChannel = message.member?.voice.channel; if (!voiceChannel) return send("You are not in a voice channel."); - if (!voiceChannel.guild.me?.permissions.has("MANAGE_CHANNELS")) + if (!voiceChannel.guild.me?.hasPermission("MANAGE_CHANNELS")) return send("I am lacking the required permissions to perform this action."); const prevName = voiceChannel.name; diff --git a/src/commands/utility/docs.ts b/src/commands/utility/docs.ts index fa874cc..5f5b2be 100644 --- a/src/commands/utility/docs.ts +++ b/src/commands/utility/docs.ts @@ -11,16 +11,16 @@ export default new NamedCommand({ var queryString = args[0]; let url = new URL(`https://djsdocs.sorta.moe/v2/embed?src=master&q=${queryString}`); const content = await getContent(url.toString()); - const msg = await send({embeds: [content]}); + const msg = await send({embed: content}); const react = await msg.react("❌"); - const collector = msg.createReactionCollector({ - filter: (reaction, user) => { + const collector = msg.createReactionCollector( + (reaction, user) => { if (user.id === author.id && reaction.emoji.name === "❌") msg.delete(); return false; }, - time: 60000 - }); + {time: 60000} + ); collector.on("end", () => { if (!msg.deleted) react.users.remove(msg.author); diff --git a/src/commands/utility/info.ts b/src/commands/utility/info.ts index e480771..e5b00f6 100644 --- a/src/commands/utility/info.ts +++ b/src/commands/utility/info.ts @@ -1,15 +1,15 @@ -import {MessageEmbed, version as djsversion, Guild, User, GuildMember, TextChannel, VoiceChannel} from "discord.js"; +import {MessageEmbed, version as djsversion, Guild, User, GuildMember} from "discord.js"; import ms from "ms"; import os from "os"; import {Command, NamedCommand, getUserByNickname, CHANNEL_TYPE, getGuildByName, RestCommand} from "onion-lasers"; import {formatBytes, trimArray} from "../../lib"; -import {verificationLevels, filterLevels} from "../../defs/info"; +import {verificationLevels, filterLevels, regions} from "../../defs/info"; import moment, {utc} from "moment"; export default new NamedCommand({ description: "Command to provide all sorts of info about the current server, a user, etc.", async run({send, author, member}) { - send({embeds: [await getUserInfo(author, member)]}); + send(await getUserInfo(author, member)); }, subcommands: { avatar: new NamedCommand({ @@ -55,47 +55,39 @@ export default new NamedCommand({ const core = os.cpus()[0]; const embed = new MessageEmbed() .setColor(guild?.me?.displayHexColor || "BLUE") - .addField( - "General", - [ - `**❯ Client:** ${client.user?.tag} (${client.user?.id})`, - `**❯ Servers:** ${client.guilds.cache.size.toLocaleString()}`, - `**❯ Users:** ${client.guilds.cache - .reduce((a: any, b: {memberCount: any}) => a + b.memberCount, 0) - .toLocaleString()}`, - `**❯ Channels:** ${client.channels.cache.size.toLocaleString()}`, - `**❯ Creation Date:** ${utc(client.user?.createdTimestamp).format( - "Do MMMM YYYY HH:mm:ss" - )}`, - `**❯ Node.JS:** ${process.version}`, - `**❯ Version:** v${process.env.npm_package_version}`, - `**❯ Discord.JS:** v${djsversion}`, - "\u200b" - ].join("\n") - ) - .addField( - "System", - [ - `**❯ Platform:** ${process.platform}`, - `**❯ Uptime:** ${ms(os.uptime() * 1000, { - long: true - })}`, - `**❯ CPU:**`, - `\u3000 • Cores: ${os.cpus().length}`, - `\u3000 • Model: ${core.model}`, - `\u3000 • Speed: ${core.speed}MHz`, - `**❯ Memory:**`, - `\u3000 • Total: ${formatBytes(process.memoryUsage().heapTotal)}`, - `\u3000 • Used: ${formatBytes(process.memoryUsage().heapUsed)}` - ].join("\n") - ) + .addField("General", [ + `**❯ Client:** ${client.user?.tag} (${client.user?.id})`, + `**❯ Servers:** ${client.guilds.cache.size.toLocaleString()}`, + `**❯ Users:** ${client.guilds.cache + .reduce((a: any, b: {memberCount: any}) => a + b.memberCount, 0) + .toLocaleString()}`, + `**❯ Channels:** ${client.channels.cache.size.toLocaleString()}`, + `**❯ Creation Date:** ${utc(client.user?.createdTimestamp).format("Do MMMM YYYY HH:mm:ss")}`, + `**❯ Node.JS:** ${process.version}`, + `**❯ Version:** v${BOT_VERSION}`, + `**❯ Discord.JS:** v${djsversion}`, + "\u200b" + ]) + .addField("System", [ + `**❯ Platform:** ${process.platform}`, + `**❯ Uptime:** ${ms(os.uptime() * 1000, { + long: true + })}`, + `**❯ CPU:**`, + `\u3000 • Cores: ${os.cpus().length}`, + `\u3000 • Model: ${core.model}`, + `\u3000 • Speed: ${core.speed}MHz`, + `**❯ Memory:**`, + `\u3000 • Total: ${formatBytes(process.memoryUsage().heapTotal)}`, + `\u3000 • Used: ${formatBytes(process.memoryUsage().heapUsed)}` + ]) .setTimestamp(); const avatarURL = client.user?.displayAvatarURL({ dynamic: true, size: 2048 }); if (avatarURL) embed.setThumbnail(avatarURL); - send({embeds: [embed]}); + send(embed); } }), guild: new NamedCommand({ @@ -103,14 +95,14 @@ export default new NamedCommand({ usage: "(/)", channelType: CHANNEL_TYPE.GUILD, async run({send, guild}) { - send({embeds: [await getGuildInfo(guild!, guild)]}); + send(await getGuildInfo(guild!, guild)); }, id: "guild", guild: new Command({ description: "Display info about a guild by its ID.", async run({send, guild, args}) { const targetGuild = args[0] as Guild; - send({embeds: [await getGuildInfo(targetGuild, guild)]}); + send(await getGuildInfo(targetGuild, guild)); } }), any: new RestCommand({ @@ -119,7 +111,7 @@ export default new NamedCommand({ const targetGuild = getGuildByName(combined); if (typeof targetGuild !== "string") { - send({embeds: [await getGuildInfo(targetGuild, guild)]}); + send(await getGuildInfo(targetGuild, guild)); } else { send(targetGuild); } @@ -134,7 +126,7 @@ export default new NamedCommand({ const user = args[0] as User; // Transforms the User object into a GuildMember object of the current guild. const member = guild?.members.resolve(user); - send({embeds: [await getUserInfo(user, member)]}); + send(await getUserInfo(user, member)); } }), any: new RestCommand({ @@ -143,7 +135,7 @@ export default new NamedCommand({ const user = await getUserByNickname(combined, guild); // Transforms the User object into a GuildMember object of the current guild. const member = guild?.members.resolve(user); - if (typeof user !== "string") send({embeds: [await getUserInfo(user, member)]}); + if (typeof user !== "string") send(await getUserInfo(user, member)); else send(user); } }) @@ -155,21 +147,20 @@ async function getUserInfo(user: User, member: GuildMember | null | undefined): const embed = new MessageEmbed() .setThumbnail(user.displayAvatarURL({dynamic: true, size: 512})) .setColor("BLUE") - .addField( - "User", - [ - `**❯ Username:** ${user.username}`, - `**❯ Discriminator:** ${user.discriminator}`, - `**❯ ID:** ${user.id}`, - `**❯ Flags:** ${userFlags.length ? userFlags.join(", ") : "None"}`, - `**❯ Avatar:** [Link to avatar](${user.displayAvatarURL({ - dynamic: true - })})`, - `**❯ Time Created:** ${moment(user.createdTimestamp).format("LT")} ${moment( - user.createdTimestamp - ).format("LL")} ${moment(user.createdTimestamp).fromNow()}` - ].join("\n") - ); + .addField("User", [ + `**❯ Username:** ${user.username}`, + `**❯ Discriminator:** ${user.discriminator}`, + `**❯ ID:** ${user.id}`, + `**❯ Flags:** ${userFlags.length ? userFlags.join(", ") : "None"}`, + `**❯ Avatar:** [Link to avatar](${user.displayAvatarURL({ + dynamic: true + })})`, + `**❯ Time Created:** ${moment(user.createdTimestamp).format("LT")} ${moment(user.createdTimestamp).format( + "LL" + )} ${moment(user.createdTimestamp).fromNow()}`, + `**❯ Status:** ${user.presence.status}`, + `**❯ Game:** ${user.presence.activities || "Not playing a game."}` + ]); if (member) { const roles = member.roles.cache @@ -179,21 +170,16 @@ async function getUserInfo(user: User, member: GuildMember | null | undefined): embed .setColor(member.displayHexColor) - .addField( - "Member", - [ - `**❯ Status:** ${member.presence?.status}`, - `**❯ Game:** ${member.presence?.activities ?? "Not playing a game."}`, - `**❯ Highest Role:** ${ - member.roles.highest.id === member.guild.id ? "None" : member.roles.highest.name - }`, - `**❯ Server Join Date:** ${moment(member.joinedAt).format("LL LTS")}`, - `**❯ Hoist Role:** ${member.roles.hoist ? member.roles.hoist.name : "None"}`, - `**❯ Roles:** [${roles.length}]: ${ - roles.length == 0 ? "None" : roles.length <= 10 ? roles.join(", ") : trimArray(roles).join(", ") - }` - ].join("\n") - ); + .addField("Member", [ + `**❯ Highest Role:** ${ + member.roles.highest.id === member.guild.id ? "None" : member.roles.highest.name + }`, + `**❯ Server Join Date:** ${moment(member.joinedAt).format("LL LTS")}`, + `**❯ Hoist Role:** ${member.roles.hoist ? member.roles.hoist.name : "None"}`, + `**❯ Roles:** [${roles.length}]: ${ + roles.length == 0 ? "None" : roles.length <= 10 ? roles.join(", ") : trimArray(roles).join(", ") + }` + ]); } return embed; @@ -210,50 +196,41 @@ async function getGuildInfo(guild: Guild, currentGuild: Guild | null) { const iconURL = guild.iconURL({dynamic: true}); const embed = new MessageEmbed().setDescription(`**Guild information for __${guild.name}__**`).setColor("BLUE"); const displayRoles = !!(currentGuild && guild.id === currentGuild.id); - const owner = await guild.fetchOwner(); embed - .addField( - "General", - [ - `**❯ Name:** ${guild.name}`, - `**❯ ID:** ${guild.id}`, - `**❯ Owner:** ${owner.user.tag} (${guild.ownerId})`, - `**❯ Boost Tier:** ${guild.premiumTier ? `Tier ${guild.premiumTier}` : "None"}`, - `**❯ Explicit Filter:** ${filterLevels[guild.explicitContentFilter]}`, - `**❯ Verification Level:** ${verificationLevels[guild.verificationLevel]}`, - `**❯ Time Created:** ${moment(guild.createdTimestamp).format("LT")} ${moment( - guild.createdTimestamp - ).format("LL")} ${moment(guild.createdTimestamp).fromNow()}`, - "\u200b" - ].join("\n") - ) - .addField( - "Statistics", - [ - `**❯ Role Count:** ${roles.length}`, - `**❯ Emoji Count:** ${emojis.size}`, - `**❯ Regular Emoji Count:** ${emojis.filter((emoji) => !emoji.animated).size}`, - `**❯ Animated Emoji Count:** ${emojis.filter((emoji) => !!emoji.animated).size}`, - `**❯ Member Count:** ${guild.memberCount}`, - `**❯ Humans:** ${members.filter((member) => !member.user.bot).size}`, - `**❯ Bots:** ${members.filter((member) => member.user.bot).size}`, - `**❯ Text Channels:** ${channels.filter((channel) => channel instanceof TextChannel).size}`, - `**❯ Voice Channels:** ${channels.filter((channel) => channel instanceof VoiceChannel).size}`, - `**❯ Boost Count:** ${guild.premiumSubscriptionCount || "0"}`, - `\u200b` - ].join("\n") - ) - .addField( - "Presence", - [ - `**❯ Online:** ${members.filter((member) => member.presence?.status === "online").size}`, - `**❯ Idle:** ${members.filter((member) => member.presence?.status === "idle").size}`, - `**❯ Do Not Disturb:** ${members.filter((member) => member.presence?.status === "dnd").size}`, - `**❯ Offline:** ${members.filter((member) => member.presence?.status === "offline").size}`, - displayRoles ? "\u200b" : "" - ].join("\n") - ) + .addField("General", [ + `**❯ Name:** ${guild.name}`, + `**❯ ID:** ${guild.id}`, + `**❯ Owner:** ${guild.owner?.user.tag} (${guild.ownerID})`, + `**❯ Region:** ${regions[guild.region]}`, + `**❯ Boost Tier:** ${guild.premiumTier ? `Tier ${guild.premiumTier}` : "None"}`, + `**❯ Explicit Filter:** ${filterLevels[guild.explicitContentFilter]}`, + `**❯ Verification Level:** ${verificationLevels[guild.verificationLevel]}`, + `**❯ Time Created:** ${moment(guild.createdTimestamp).format("LT")} ${moment(guild.createdTimestamp).format( + "LL" + )} ${moment(guild.createdTimestamp).fromNow()}`, + "\u200b" + ]) + .addField("Statistics", [ + `**❯ Role Count:** ${roles.length}`, + `**❯ Emoji Count:** ${emojis.size}`, + `**❯ Regular Emoji Count:** ${emojis.filter((emoji) => !emoji.animated).size}`, + `**❯ Animated Emoji Count:** ${emojis.filter((emoji) => emoji.animated).size}`, + `**❯ Member Count:** ${guild.memberCount}`, + `**❯ Humans:** ${members.filter((member) => !member.user.bot).size}`, + `**❯ Bots:** ${members.filter((member) => member.user.bot).size}`, + `**❯ Text Channels:** ${channels.filter((channel) => channel.type === "text").size}`, + `**❯ Voice Channels:** ${channels.filter((channel) => channel.type === "voice").size}`, + `**❯ Boost Count:** ${guild.premiumSubscriptionCount || "0"}`, + `\u200b` + ]) + .addField("Presence", [ + `**❯ Online:** ${members.filter((member) => member.presence.status === "online").size}`, + `**❯ Idle:** ${members.filter((member) => member.presence.status === "idle").size}`, + `**❯ Do Not Disturb:** ${members.filter((member) => member.presence.status === "dnd").size}`, + `**❯ Offline:** ${members.filter((member) => member.presence.status === "offline").size}`, + displayRoles ? "\u200b" : "" + ]) .setTimestamp(); if (iconURL) embed.setThumbnail(iconURL); diff --git a/src/commands/utility/invite.ts b/src/commands/utility/invite.ts index b734f1f..b181583 100644 --- a/src/commands/utility/invite.ts +++ b/src/commands/utility/invite.ts @@ -3,11 +3,7 @@ import {Command, NamedCommand} from "onion-lasers"; export default new NamedCommand({ description: "Gives you the invite link.", async run({send, client}) { - send( - `https://discordapp.com/api/oauth2/authorize?client_id=${ - client.user!.id - }&permissions=138046467152&scope=bot` - ); + send(`https://discordapp.com/api/oauth2/authorize?client_id=${client.user!.id}&permissions=8&scope=bot`); }, number: new Command({ async run({send, client, args}) { diff --git a/src/commands/utility/lsemotes.ts b/src/commands/utility/lsemotes.ts index 933050b..921a573 100644 --- a/src/commands/utility/lsemotes.ts +++ b/src/commands/utility/lsemotes.ts @@ -9,7 +9,7 @@ export default new NamedCommand({ description: "Lists all emotes the bot has in it's registry,", usage: " (-flags)", async run({send, author, client}) { - displayEmoteList(Array.from(client.emojis.cache.values()), send, author); + displayEmoteList(client.emojis.cache.array(), send, author); }, any: new RestCommand({ description: @@ -20,7 +20,7 @@ export default new NamedCommand({ const guildID: string = args[0]; displayEmoteList( - Array.from(client.emojis.cache.filter((emote) => emote.guild.id === guildID).values()), + client.emojis.cache.filter((emote) => emote.guild.id === guildID).array(), send, author ); @@ -32,15 +32,13 @@ export default new NamedCommand({ flags = args.pop().substring(1); } - let emoteCollection = Array.from(client.emojis.cache.values()); + let emoteCollection = client.emojis.cache.array(); // Creates a sandbox to stop a regular expression if it takes too much time to search. // To avoid passing in a giant data structure, I'll just pass in the structure {[id: string]: [name: string]}. let emotes = new Map(); for (const emote of emoteCollection) { - if (emote.name) { - emotes.set(emote.id, emote.name); - } + emotes.set(emote.id, emote.name); } // The result will be sandbox.emotes because it'll be modified in-place. @@ -61,18 +59,12 @@ export default new NamedCommand({ emoteCollection = emoteCollection.filter((emote) => emotes.has(emote.id)); // Only allow emotes that haven't been deleted. displayEmoteList(emoteCollection, send, author); } catch (error) { - // FIXME: `error` is of type `unknown` here. - // Also: - let errorName = "???"; - if (error instanceof Error) { - errorName = error.name; - } - if (errorName === "ERR_SCRIPT_EXECUTION_TIMEOUT") { + if (error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") { send( `The regular expression you entered exceeded the time limit of ${REGEX_TIMEOUT_MS} milliseconds.` ); } else { - throw new Error(errorName); + throw new Error(error); } } } else { @@ -85,7 +77,6 @@ export default new NamedCommand({ async function displayEmoteList(emotes: GuildEmoji[], send: SendFunction, author: User) { emotes.sort((a, b) => { - if (!a.name || !b.name) return 0; const first = a.name.toLowerCase(); const second = b.name.toLowerCase(); @@ -108,7 +99,7 @@ async function displayEmoteList(emotes: GuildEmoji[], send: SendFunction, author } embed.setDescription(desc); - return {embeds: [embed]}; + return embed; }); } else { send("No valid emotes found by that query."); diff --git a/src/commands/utility/modules/emote-utils.ts b/src/commands/utility/modules/emote-utils.ts index 43b2bd6..009dddc 100644 --- a/src/commands/utility/modules/emote-utils.ts +++ b/src/commands/utility/modules/emote-utils.ts @@ -51,11 +51,9 @@ function searchSimilarEmotes(query: string): GuildEmoji[] { const emoteCandidates: {emote: GuildEmoji; dist: number}[] = []; for (const emote of client.emojis.cache.values()) { - if (emote.name) { - const dist = levenshtein(emote.name, query); - if (dist <= maxAcceptedDistance) { - emoteCandidates.push({emote, dist}); - } + const dist = levenshtein(emote.name, query); + if (dist <= maxAcceptedDistance) { + emoteCandidates.push({emote, dist}); } } diff --git a/src/commands/utility/purge.ts b/src/commands/utility/purge.ts index a513b5c..5c55551 100644 --- a/src/commands/utility/purge.ts +++ b/src/commands/utility/purge.ts @@ -16,14 +16,14 @@ export default new NamedCommand({ } } } else if (hasPermission(author, member, PERMISSIONS.BOT_SUPPORT)) { - if (guild!.me?.permissions.has(Permissions.FLAGS.MANAGE_MESSAGES)) message.delete(); + if (guild!.me?.hasPermission(Permissions.FLAGS.MANAGE_MESSAGES)) message.delete(); const messages = await channel.messages.fetch({ limit: 100 }); const travMessages = messages.filter((msg) => msg.author.id === client.user!.id); - send(`Found ${travMessages.size} messages to delete.`).then((msg) => setTimeout(() => msg.delete(), 5000)); + send(`Found ${travMessages.size} messages to delete.`).then((msg) => msg.delete({timeout: 5000})); // It's better to go through the bot's own messages instead of calling bulkDelete which requires MANAGE_MESSAGES. for (const message of messages.values()) { diff --git a/src/commands/utility/react.ts b/src/commands/utility/react.ts index bfc63e2..b11609c 100644 --- a/src/commands/utility/react.ts +++ b/src/commands/utility/react.ts @@ -1,5 +1,5 @@ import {NamedCommand, RestCommand} from "onion-lasers"; -import {Message, Channel, TextChannel, TextBasedChannels} from "discord.js"; +import {Message, Channel, TextChannel} from "discord.js"; import {processEmoteQuery} from "./modules/emote-utils"; export default new NamedCommand({ @@ -15,7 +15,7 @@ export default new NamedCommand({ if (message.reference) { // If the command message is a reply to another message, use that as the react target. - target = await channel.messages.fetch(message.reference.messageId!); + target = await channel.messages.fetch(message.reference.messageID!); } // handles reacts by message id/distance else if (args.length >= 2) { @@ -29,7 +29,7 @@ export default new NamedCommand({ const guildID = match[1]; const channelID = match[2]; const messageID = match[3]; - let tmpChannel: TextBasedChannels | undefined = channel; + let tmpChannel: Channel | undefined = channel; if (guild?.id !== guildID) { try { @@ -39,13 +39,12 @@ export default new NamedCommand({ } } - if (tmpChannel?.id !== channelID) - tmpChannel = guild.channels.cache.get(channelID) as TextBasedChannels; + if (tmpChannel.id !== channelID) tmpChannel = guild.channels.cache.get(channelID); if (!tmpChannel) return send(`\`${channelID}\` is an invalid channel ID!`); if (message.id !== messageID) { try { - target = await tmpChannel.messages.fetch(messageID); + target = await (tmpChannel as TextChannel).messages.fetch(messageID); } catch { return send(`\`${messageID}\` is an invalid message ID!`); } @@ -58,15 +57,14 @@ export default new NamedCommand({ const match = copyIDPattern.exec(last)!; const channelID = match[1]; const messageID = match[2]; - let tmpChannel: TextBasedChannels | undefined = channel; + let tmpChannel: Channel | undefined = channel; - if (tmpChannel?.id !== channelID) - tmpChannel = guild?.channels.cache.get(channelID) as TextBasedChannels; + if (tmpChannel.id !== channelID) tmpChannel = guild?.channels.cache.get(channelID); if (!tmpChannel) return send(`\`${channelID}\` is an invalid channel ID!`); if (message.id !== messageID) { try { - target = await tmpChannel.messages.fetch(messageID); + target = await (tmpChannel as TextChannel).messages.fetch(messageID); } catch { return send(`\`${messageID}\` is an invalid message ID!`); } diff --git a/src/commands/utility/say.ts b/src/commands/utility/say.ts index 6cb9d16..60b5a52 100644 --- a/src/commands/utility/say.ts +++ b/src/commands/utility/say.ts @@ -29,8 +29,7 @@ export default new NamedCommand({ const resolvedMessage = resolveMessageWithEmotes(combined); if (resolvedMessage) - webhook.send({ - content: resolvedMessage, + webhook.send(resolvedMessage, { username: member!.nickname ?? author.username, // Webhooks cannot have animated avatars, so requesting the animated version is a moot point. avatarURL: @@ -39,17 +38,16 @@ export default new NamedCommand({ }) || author.defaultAvatarURL, allowedMentions: {parse: []}, // avoids double pings // "embeds" will not be included because it messes with the default ones that generate - files: Array.from(message.attachments.values()) + files: message.attachments.array() }); else send("Cannot send an empty message."); } else { const resolvedMessage = resolveMessageWithEmotes(combined); - if (resolvedMessage) - send({content: `*${author} says:*\n${resolvedMessage}`, allowedMentions: {parse: []}}); + if (resolvedMessage) send(`*${author} says:*\n${resolvedMessage}`, {allowedMentions: {parse: []}}); else send("Cannot send an empty message."); } - if (guild!.me?.permissions.has(Permissions.FLAGS.MANAGE_MESSAGES)) message.delete(); + if (guild!.me?.hasPermission(Permissions.FLAGS.MANAGE_MESSAGES)) message.delete(); } }) }); diff --git a/src/commands/utility/scanemotes.ts b/src/commands/utility/scanemotes.ts index 0a70076..917f0bb 100644 --- a/src/commands/utility/scanemotes.ts +++ b/src/commands/utility/scanemotes.ts @@ -1,7 +1,7 @@ import {NamedCommand, CHANNEL_TYPE} from "onion-lasers"; import {pluralise} from "../../lib"; import moment from "moment"; -import {Collection, TextChannel, Util} from "discord.js"; +import {Collection, TextChannel} from "discord.js"; const lastUsedTimestamps = new Collection(); @@ -24,7 +24,7 @@ export default new NamedCommand({ const stats: { [id: string]: { - name: string | null; + name: string; formatted: string; users: number; bots: number; @@ -33,7 +33,7 @@ export default new NamedCommand({ let totalUserEmoteUsage = 0; // IMPORTANT: You MUST check if the bot actually has access to the channel in the first place. It will get the list of all channels, but that doesn't mean it has access to every channel. Without this, it'll require admin access and throw an annoying unhelpful DiscordAPIError: Missing Access otherwise. const allTextChannelsInCurrentGuild = guild!.channels.cache.filter( - (channel) => channel instanceof TextChannel && channel.viewable + (channel) => channel.type === "text" && channel.viewable ) as Collection; let messagesSearched = 0; let channelsSearched = 0; @@ -41,7 +41,7 @@ export default new NamedCommand({ const totalChannels = allTextChannelsInCurrentGuild.size; const statusMessage = await send("Gathering emotes..."); let warnings = 0; - channel.sendTyping(); + channel.startTyping(); // Initialize the emote stats object with every emote in the current guild. // The goal here is to cut the need to access guild.emojis.get() which'll make it faster and easier to work with. @@ -63,7 +63,7 @@ export default new NamedCommand({ for (const channel of allTextChannelsInCurrentGuild.values()) { currentChannelName = channel.name; - let selected = channel.lastMessageId ?? message.id; + let selected = channel.lastMessageID ?? message.id; let continueLoop = true; while (continueLoop) { @@ -161,6 +161,7 @@ export default new NamedCommand({ )}.` ); console.log("[scanemotes]", `Finished operation in ${finishTime - startTime} ms.`); + channel.stopTyping(); // Display stats on emote usage. // This can work outside the loop now that it's synchronous, and now it's clearer what code is meant to execute at the end. @@ -179,10 +180,7 @@ export default new NamedCommand({ ); } - let emoteList = Util.splitMessage(lines.join("\n")); - for (let emoteListPart of emoteList) { - return await send(emoteListPart); - } + return await send(lines, {split: true}); }, subcommands: { forcereset: new NamedCommand({ diff --git a/src/commands/utility/streaminfo.ts b/src/commands/utility/streaminfo.ts index 1cf44a0..a4ed019 100644 --- a/src/commands/utility/streaminfo.ts +++ b/src/commands/utility/streaminfo.ts @@ -34,14 +34,11 @@ export default new NamedCommand({ const stream = streamList.get(userID)!; stream.description = combined; stream.update(); - send({ - content: "Successfully set the stream description to:", - embeds: [ - { - description: stream.description, - color: member!.displayColor - } - ] + send("Successfully set the stream description to:", { + embed: { + description: stream.description, + color: member!.displayColor + } }); } else { send("You can only use this command when streaming."); @@ -73,15 +70,12 @@ export default new NamedCommand({ const stream = streamList.get(userID)!; stream.thumbnail = combined; stream.update(); - send({ - content: `Successfully set the stream thumbnail to: ${combined}`, - embeds: [ - { - description: stream.description, - thumbnail: {url: combined}, - color: member!.displayColor - } - ] + send(`Successfully set the stream thumbnail to: ${combined}`, { + embed: { + description: stream.description, + thumbnail: {url: combined}, + color: member!.displayColor + } }); } else { send("You can only use this command when streaming."); diff --git a/src/commands/utility/time.ts b/src/commands/utility/time.ts index b02a88b..d55e37d 100644 --- a/src/commands/utility/time.ts +++ b/src/commands/utility/time.ts @@ -124,40 +124,42 @@ function getTimeEmbed(user: User) { } const embed = { - color: TIME_EMBED_COLOR, - author: { - name: user.username, - icon_url: user.displayAvatarURL({ - format: "png", - dynamic: true - }) - }, - fields: [ - { - name: "Local Date", - value: localDate + embed: { + color: TIME_EMBED_COLOR, + author: { + name: user.username, + icon_url: user.displayAvatarURL({ + format: "png", + dynamic: true + }) }, - { - name: "Day of the Week", - value: dayOfWeek - }, - { - name: "Local Time", - value: localTime - }, - { - name: daylightSavingsRegion !== null ? "Current Timezone Offset" : "Timezone Offset", - value: timezoneOffset - }, - { - name: "Observes Daylight Savings?", - value: daylightSavingsRegion ? "Yes" : "No" - } - ] + fields: [ + { + name: "Local Date", + value: localDate + }, + { + name: "Day of the Week", + value: dayOfWeek + }, + { + name: "Local Time", + value: localTime + }, + { + name: daylightSavingsRegion !== null ? "Current Timezone Offset" : "Timezone Offset", + value: timezoneOffset + }, + { + name: "Observes Daylight Savings?", + value: daylightSavingsRegion ? "Yes" : "No" + } + ] + } }; if (daylightSavingsRegion) { - embed.fields.push( + embed.embed.fields.push( { name: "Daylight Savings Active?", value: hasDaylightSavings(daylightSavingsRegion) ? "Yes" : "No" @@ -176,7 +178,7 @@ export default new NamedCommand({ description: "Show others what time it is for you.", aliases: ["tz"], async run({send, author}) { - send({embeds: [getTimeEmbed(author)]}); + send(getTimeEmbed(author)); }, subcommands: { // Welcome to callback hell. We hope you enjoy your stay here! @@ -296,11 +298,10 @@ export default new NamedCommand({ const finalize = () => { Storage.save(); - send({ - content: - "You've finished setting up your timezone! Just check to see if this looks right, and if it doesn't, run this setup again.", - embeds: [getTimeEmbed(author)] - }); + send( + "You've finished setting up your timezone! Just check to see if this looks right, and if it doesn't, run this setup again.", + getTimeEmbed(author) + ); }; if (hasDST) { @@ -357,25 +358,23 @@ export default new NamedCommand({ const time = moment().utc(); send({ - embeds: [ - { - color: TIME_EMBED_COLOR, - fields: [ - { - name: "Local Date", - value: time.format(DATE_FORMAT) - }, - { - name: "Day of the Week", - value: time.format(DOW_FORMAT) - }, - { - name: "Local Time", - value: time.format(TIME_FORMAT) - } - ] - } - ] + embed: { + color: TIME_EMBED_COLOR, + fields: [ + { + name: "Local Date", + value: time.format(DATE_FORMAT) + }, + { + name: "Day of the Week", + value: time.format(DOW_FORMAT) + }, + { + name: "Local Time", + value: time.format(TIME_FORMAT) + } + ] + } }); } }), @@ -388,14 +387,14 @@ export default new NamedCommand({ user: new Command({ description: "See what time it is for someone else.", async run({send, args}) { - send({embeds: [getTimeEmbed(args[0])]}); + send(getTimeEmbed(args[0])); } }), any: new RestCommand({ description: "See what time it is for someone else (by their username).", async run({send, guild, combined}) { const user = await getUserByNickname(combined, guild); - if (typeof user !== "string") send({embeds: [getTimeEmbed(user)]}); + if (typeof user !== "string") send(getTimeEmbed(user)); else send(user); } }) diff --git a/src/commands/utility/todo.ts b/src/commands/utility/todo.ts index da73eaa..e88eefc 100644 --- a/src/commands/utility/todo.ts +++ b/src/commands/utility/todo.ts @@ -17,7 +17,7 @@ export default new NamedCommand({ ); } - send({embeds: [embed]}); + send(embed); }, subcommands: { add: new NamedCommand({ diff --git a/src/commands/utility/translate.ts b/src/commands/utility/translate.ts index d275f0f..eb4075c 100644 --- a/src/commands/utility/translate.ts +++ b/src/commands/utility/translate.ts @@ -16,21 +16,19 @@ export default new NamedCommand({ }) .then((res) => { send({ - embeds: [ - { - title: "Translation", - fields: [ - { - name: "Input", - value: `\`\`\`${input}\`\`\`` - }, - { - name: "Output", - value: `\`\`\`${res}\`\`\`` - } - ] - } - ] + embed: { + title: "Translation", + fields: [ + { + name: "Input", + value: `\`\`\`${input}\`\`\`` + }, + { + name: "Output", + value: `\`\`\`${res}\`\`\`` + } + ] + } }); }) .catch((error) => { diff --git a/src/index.ts b/src/index.ts index 18ab1dc..7a85389 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,21 +1,10 @@ import "./modules/globals"; -import {Client, Permissions, Intents} from "discord.js"; +import {Client, Permissions} from "discord.js"; import path from "path"; // This is here in order to make it much less of a headache to access the client from other files. // This of course won't actually do anything until the setup process is complete and it logs in. -export const client = new Client({ - intents: [ - Intents.FLAGS.GUILDS, - Intents.FLAGS.GUILD_MEMBERS, - Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS, - Intents.FLAGS.GUILD_VOICE_STATES, - Intents.FLAGS.GUILD_PRESENCES, - Intents.FLAGS.GUILD_MESSAGES, - Intents.FLAGS.GUILD_MESSAGE_REACTIONS, - Intents.FLAGS.DIRECT_MESSAGES - ] -}); +export const client = new Client(); import {launch} from "onion-lasers"; import setup from "./modules/setup"; @@ -42,20 +31,20 @@ launch(client, path.join(__dirname, "commands"), { name: "Moderator", check: (_user, member) => !!member && - (member.permissions.has(Permissions.FLAGS.MANAGE_ROLES) || - member.permissions.has(Permissions.FLAGS.MANAGE_MESSAGES) || - member.permissions.has(Permissions.FLAGS.KICK_MEMBERS) || - member.permissions.has(Permissions.FLAGS.BAN_MEMBERS)) + (member.hasPermission(Permissions.FLAGS.MANAGE_ROLES) || + member.hasPermission(Permissions.FLAGS.MANAGE_MESSAGES) || + member.hasPermission(Permissions.FLAGS.KICK_MEMBERS) || + member.hasPermission(Permissions.FLAGS.BAN_MEMBERS)) }, { // ADMIN // name: "Administrator", - check: (_user, member) => !!member && member.permissions.has(Permissions.FLAGS.ADMINISTRATOR) + check: (_user, member) => !!member && member.hasPermission(Permissions.FLAGS.ADMINISTRATOR) }, { // OWNER // name: "Server Owner", - check: (_user, member) => !!member && member.guild.ownerId === member.id + check: (_user, member) => !!member && member.guild.ownerID === member.id }, { // BOT_SUPPORT // @@ -78,8 +67,7 @@ launch(client, path.join(__dirname, "commands"), { // Initialize Modules // import "./modules/ready"; import "./modules/presence"; -// TODO: Reimplement entire music system, contact Sink -// import "./modules/lavalink"; +import "./modules/lavalink"; import "./modules/emoteRegistry"; import "./modules/systemInfo"; import "./modules/intercept"; diff --git a/src/lib.ts b/src/lib.ts index b999791..c4f4167 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -154,11 +154,7 @@ export function getContent(url: string): Promise<{url: string}> { const parsedData = JSON.parse(rawData); resolve(parsedData); } catch (e) { - let errorMessage = "Something went wrong! We don't know what, though..."; - if (e instanceof Error) { - errorMessage = e.message; - } - reject(`Error: ${errorMessage}`); + reject(`Error: ${e.message}`); } }); }).on("error", (err: {message: any}) => { diff --git a/src/modules/channelDefaults.ts b/src/modules/channelDefaults.ts index d43019b..b346f2f 100644 --- a/src/modules/channelDefaults.ts +++ b/src/modules/channelDefaults.ts @@ -10,7 +10,7 @@ client.on("voiceStateUpdate", async (before, after) => { channel && channel.members.size === 0 && channel.id in channelNames && - before.guild.me?.permissions.has(Permissions.FLAGS.MANAGE_CHANNELS) + before.guild.me?.hasPermission(Permissions.FLAGS.MANAGE_CHANNELS) ) { channel.setName(channelNames[channel.id]); } diff --git a/src/modules/emoteRegistry.ts b/src/modules/emoteRegistry.ts index 502c379..e261390 100644 --- a/src/modules/emoteRegistry.ts +++ b/src/modules/emoteRegistry.ts @@ -11,8 +11,8 @@ function updateGlobalEmoteRegistry(): void { ref: emote.name, id: emote.id, name: emote.name, - requires_colons: emote.requiresColons ?? false, - animated: emote.animated ?? false, + requires_colons: emote.requiresColons || false, + animated: emote.animated, url: emote.url, guild_id: emote.guild.name, guild_name: emote.guild.name diff --git a/src/modules/eventLogging.ts b/src/modules/eventLogging.ts index 1a7e1af..2e23bc6 100644 --- a/src/modules/eventLogging.ts +++ b/src/modules/eventLogging.ts @@ -2,49 +2,17 @@ // Like with logging each command invocation, it's not a good idea to pollute the logs with this kind of stuff when it works most of the time. // However, it's also a pain to debug when no context is provided for an error message. import {client} from ".."; -import {setExecuteCommandListener} from "onion-lasers"; -import {TextChannel, DMChannel, NewsChannel} from "discord.js"; let lastEvent = "N/A"; -let lastCommandInfo: { - header: string; - args: string[]; - channel: TextChannel | DMChannel | NewsChannel | null; -} = { - header: "N/A", - args: [], - channel: null -}; +// A generic process handler is set to catch unhandled rejections other than the ones from Lavalink and Discord. process.on("unhandledRejection", (reason: any) => { const isLavalinkError = reason?.code === "ECONNREFUSED"; const isDiscordError = reason?.name === "DiscordAPIError"; - if (!isLavalinkError) { - // If it's a DiscordAPIError on a message event, I'll make the assumption that it comes from the command handler. - // That's not always the case though, especially if you add your own message events. Just be wary of that. - if (isDiscordError && lastEvent === "message") { - console.error( - `Command Error: ${lastCommandInfo.header} (${lastCommandInfo.args.join(", ")})\n${reason.stack}` - ); - lastCommandInfo.channel?.send( - `There was an error while trying to execute that command!\`\`\`${reason.stack}\`\`\`` - ); - } else { - console.error( - `@${lastEvent} : /${lastCommandInfo.header} (${lastCommandInfo.args.join(", ")})\n${reason.stack}` - ); - } - } -}); - -// Store info on which command was executed last. -setExecuteCommandListener(({header, args, channel}) => { - lastCommandInfo = { - header, - args, - channel - }; + // If it's a DiscordAPIError on a message event, I'll make the assumption that it comes from the command handler. + if (!isLavalinkError && (!isDiscordError || lastEvent !== "message")) + console.error(`@${lastEvent}\n${reason.stack}`); }); // This will dynamically attach all known events instead of doing it manually. diff --git a/src/modules/guildMemberAdd.ts b/src/modules/guildMemberAdd.ts index 5297cca..8e41bf6 100644 --- a/src/modules/guildMemberAdd.ts +++ b/src/modules/guildMemberAdd.ts @@ -25,7 +25,7 @@ client.on("guildMemberAdd", async (member) => { if (welcomeChannel) { const channel = member.guild.channels.cache.get(welcomeChannel); - if (channel && channel instanceof TextChannel) { + if (channel && channel.type === "text") { if (welcomeType === "graphical") { const canvas = createCanvas(700, 250); const ctx = canvas.getContext("2d"); @@ -60,9 +60,9 @@ client.on("guildMemberAdd", async (member) => { ctx.drawImage(avatar, 25, 25, 200, 200); const attachment = new MessageAttachment(canvas.toBuffer("image/png"), "welcome-image.png"); - channel.send({content: `Welcome \`${member.user.tag}\`!`, attachments: [attachment]}); + (channel as TextChannel).send(`Welcome \`${member.user.tag}\`!`, attachment); } else if (welcomeType === "text") { - channel.send( + (channel as TextChannel).send( parseVars( welcomeMessage || "Say hello to `%user%`, everyone! We all need a warm welcome sometimes :D", { diff --git a/src/modules/lavalink.ts b/src/modules/lavalink.ts index fb43949..5eecaf3 100644 --- a/src/modules/lavalink.ts +++ b/src/modules/lavalink.ts @@ -1,49 +1,51 @@ -// import attachClientToLavalink from "discord.js-lavalink-lib"; -// import {Config} from "../structures"; -// import {client} from "../index"; -// -// // Although the example showed to do "client.music = LavaLink(...)" and "(client as any).music = Lavalink(...)" was done to match that, nowhere in the library is client.music ever actually used nor does the function return anything. In other words, client.music is undefined and is never used. -// attachClientToLavalink(client, { -// lavalink: { -// restnode: { -// host: "localhost", -// port: 2333, -// password: "youshallnotpass" -// }, -// nodes: [ -// { -// host: "localhost", -// port: 2333, -// password: "youshallnotpass" -// } -// ] -// }, -// prefix: Config.prefix, -// helpCmd: "mhelp", -// admins: ["717352467280691331"] -// }); -// -// // Disable the unhandledRejection listener by Lavalink because it captures every single unhandled -// // rejection and adds its message with it. Then replace it with a better, more selective error handler. -// for (const listener of process.listeners("unhandledRejection")) { -// if (listener.toString().includes("discord.js-lavalink-musicbot")) { -// process.off("unhandledRejection", listener); -// } -// } -// -// process.on("unhandledRejection", (reason: any) => { -// if (reason?.code === "ECONNREFUSED") { -// // This is console.warn instead of console.error because on development environments, unless Lavalink is being tested, it won't interfere with the bot's functionality. -// console.warn( -// `[discord.js-lavalink-musicbot] Caught unhandled rejection: ${reason.stack}\nIf this is causing issues, head to the support server at https://discord.gg/dNN4azK` -// ); -// } -// }); -// -// // It's unsafe to process uncaughtException because after an uncaught exception, the system -// // becomes corrupted. So disable Lavalink from adding a hook to it. -// for (const listener of process.listeners("uncaughtException")) { -// if (listener.toString().includes("discord.js-lavalink-musicbot")) { -// process.off("uncaughtException", listener); -// } -// } +import attachClientToLavalink from "discord.js-lavalink-lib"; +import {Config} from "../structures"; +import {client} from "../index"; + +if (Config.lavalink) { + // Although the example showed to do "client.music = LavaLink(...)" and "(client as any).music = Lavalink(...)" was done to match that, nowhere in the library is client.music ever actually used nor does the function return anything. In other words, client.music is undefined and is never used. + attachClientToLavalink(client, { + lavalink: { + restnode: { + host: "localhost", + port: 2333, + password: "youshallnotpass" + }, + nodes: [ + { + host: "localhost", + port: 2333, + password: "youshallnotpass" + } + ] + }, + prefix: Config.prefix, + helpCmd: "mhelp", + admins: ["717352467280691331"] + }); + + // Disable the unhandledRejection listener by Lavalink because it captures every single unhandled + // rejection and adds its message with it. Then replace it with a better, more selective error handler. + for (const listener of process.listeners("unhandledRejection")) { + if (listener.toString().includes("discord.js-lavalink-musicbot")) { + process.off("unhandledRejection", listener); + } + } + + process.on("unhandledRejection", (reason: any) => { + if (reason?.code === "ECONNREFUSED") { + // This is console.warn instead of console.error because on development environments, unless Lavalink is being tested, it won't interfere with the bot's functionality. + console.warn( + `[discord.js-lavalink-musicbot] Caught unhandled rejection: ${reason.stack}\nIf this is causing issues, head to the support server at https://discord.gg/dNN4azK` + ); + } + }); + + // It's unsafe to process uncaughtException because after an uncaught exception, the system + // becomes corrupted. So disable Lavalink from adding a hook to it. + for (const listener of process.listeners("uncaughtException")) { + if (listener.toString().includes("discord.js-lavalink-musicbot")) { + process.off("uncaughtException", listener); + } + } +} diff --git a/src/modules/messageEmbed.ts b/src/modules/messageEmbed.ts index 0c04c18..050edf6 100644 --- a/src/modules/messageEmbed.ts +++ b/src/modules/messageEmbed.ts @@ -2,9 +2,12 @@ import {client} from "../index"; import {MessageEmbed} from "discord.js"; import {getPrefix} from "../structures"; import {getMessageByID} from "onion-lasers"; +import {Storage} from "../structures"; -client.on("message", (message) => { - (async () => { +client.on("message", async (message) => { + const {messageEmbeds} = Storage.getGuild(message.guild!.id); + + if (messageEmbeds) { // Only execute if the message is from a user and isn't a command. if (message.content.startsWith(getPrefix(message.guild)) || message.author.bot) return; const messageLink = extractFirstMessageLink(message.content); @@ -24,7 +27,11 @@ client.on("message", (message) => { ]; if (!linkMessage.cleanContent && embeds.length === 0) { - return message.channel.send({embeds: [new MessageEmbed().setDescription("🚫 The message is empty.")]}); + return message.channel.send(new MessageEmbed().setDescription("🚫 The message is empty.")); + } + + if (linkMessage.cleanContent.length > 2048) { + return message.channel.send(new MessageEmbed().setDescription("🚫 This message is too long.")); } const infoEmbed = new MessageEmbed() @@ -42,8 +49,8 @@ client.on("message", (message) => { infoEmbed.setImage(image!.url); } - return await message.channel.send({embeds: [infoEmbed]}); - })(); + return await message.channel.send(infoEmbed); + } else return; }); export function extractFirstMessageLink(message: string): [string, string, string] | null { diff --git a/src/modules/streamNotifications.ts b/src/modules/streamNotifications.ts index f53630c..0577b46 100644 --- a/src/modules/streamNotifications.ts +++ b/src/modules/streamNotifications.ts @@ -1,10 +1,10 @@ -import {GuildMember, VoiceChannel, MessageEmbed, TextChannel, Message, Collection, StageChannel} from "discord.js"; +import {GuildMember, VoiceChannel, MessageEmbed, TextChannel, Message, Collection} from "discord.js"; import {client} from "../index"; import {Storage} from "../structures"; type Stream = { streamer: GuildMember; - channel: VoiceChannel | StageChannel; + channel: VoiceChannel; category: string; description?: string; thumbnail?: string; @@ -19,7 +19,7 @@ export const streamList = new Collection(); // Probably find a better, DRY way of doing this. function getStreamEmbed( streamer: GuildMember, - channel: VoiceChannel | StageChannel, + channel: VoiceChannel, streamStart: number, category: string, description?: string, @@ -38,7 +38,7 @@ function getStreamEmbed( // I decided to not include certain fields: // .addField("Activity", "CrossCode", true) - Probably too much presence data involved, increasing memory usage. // .addField("Viewers", 5, true) - There doesn't seem to currently be a way to track how many viewers there are. Presence data for "WATCHING" doesn't seem to affect it, and listening to raw client events doesn't seem to make it appear either. - .addField("Voice Channel", channel.toString(), true) + .addField("Voice Channel", channel, true) .addField("Category", category, true) .setColor(streamer.displayColor) .setFooter( @@ -90,23 +90,21 @@ client.on("voiceStateUpdate", async (before, after) => { streamer: member, channel: voiceChannel, category, - message: await textChannel.send({ - content: streamNotificationPing, - embeds: [getStreamEmbed(member, voiceChannel, streamStart, category)] - }), + message: await textChannel.send( + streamNotificationPing, + getStreamEmbed(member, voiceChannel, streamStart, category) + ), update(this: Stream) { - this.message.edit({ - embeds: [ - getStreamEmbed( - this.streamer, - this.channel, - streamStart, - this.category, - this.description, - this.thumbnail - ) - ] - }); + this.message.edit( + getStreamEmbed( + this.streamer, + this.channel, + streamStart, + this.category, + this.description, + this.thumbnail + ) + ); }, streamStart }); @@ -127,7 +125,7 @@ client.on("voiceStateUpdate", async (before, after) => { }); client.on("channelUpdate", (before, after) => { - if (before instanceof VoiceChannel && after instanceof VoiceChannel) { + if (before.type === "voice" && after.type === "voice") { for (const stream of streamList.values()) { if (after.id === stream.channel.id) { stream.update(); diff --git a/src/modules/systemInfo.ts b/src/modules/systemInfo.ts index f442a8a..afc64ca 100644 --- a/src/modules/systemInfo.ts +++ b/src/modules/systemInfo.ts @@ -5,17 +5,21 @@ import {Config} from "../structures"; // Logging which guilds the bot is added to and removed from makes sense. // However, logging the specific channels that are added/removed is a tad bit privacy-invading. -client.on("guildCreate", async (guild) => { - const owner = await guild.fetchOwner(); - - console.log(`[GUILD JOIN] ${guild.name} (${guild.id}) added the bot. Owner: ${owner.user.tag} (${owner.user.id}).`); +client.on("guildCreate", (guild) => { + console.log( + `[GUILD JOIN] ${guild.name} (${guild.id}) added the bot. Owner: ${guild.owner!.user.tag} (${ + guild.owner!.user.id + }).` + ); if (Config.systemLogsChannel) { const channel = client.channels.cache.get(Config.systemLogsChannel); - if (channel instanceof TextChannel) { - channel.send( - `TravBot joined: \`${guild.name}\`. The owner of this guild is: \`${owner.user.tag}\` (\`${owner.user.id}\`)` + if (channel && channel.type === "text") { + (channel as TextChannel).send( + `TravBot joined: \`${guild.name}\`. The owner of this guild is: \`${guild.owner!.user.tag}\` (\`${ + guild.owner!.user.id + }\`)` ); } else { console.warn(`${Config.systemLogsChannel} is not a valid text channel for system logs!`); @@ -29,8 +33,8 @@ client.on("guildDelete", (guild) => { if (Config.systemLogsChannel) { const channel = client.channels.cache.get(Config.systemLogsChannel); - if (channel instanceof TextChannel) { - channel.send(`\`${guild.name}\` (\`${guild.id}\`) removed the bot.`); + if (channel && channel.type === "text") { + (channel as TextChannel).send(`\`${guild.name}\` (\`${guild.id}\`) removed the bot.`); } else { console.warn( `${Config.systemLogsChannel} is not a valid text channel for system logs! Removing it from storage.` diff --git a/src/modules/webhookStorageManager.ts b/src/modules/webhookStorageManager.ts index ea6fb5f..245c958 100644 --- a/src/modules/webhookStorageManager.ts +++ b/src/modules/webhookStorageManager.ts @@ -8,7 +8,7 @@ const ID_PATTERN = /(\d{17,})/; // Resolve any available webhooks available for a selected channel. export async function resolveWebhook(channel: TextChannel | NewsChannel): Promise { - if (channel.guild.me?.permissions.has(Permissions.FLAGS.MANAGE_WEBHOOKS)) { + if (channel.guild.me?.hasPermission(Permissions.FLAGS.MANAGE_WEBHOOKS)) { const webhooksInChannel = await channel.fetchWebhooks(); if (webhooksInChannel.size > 0) return webhooksInChannel.first()!; @@ -61,7 +61,7 @@ export async function refreshWebhookCache(): Promise { // If there are stored webhook IDs/tokens that don't work, delete those webhooks from storage. try { const webhook = await client.fetchWebhook(id, token); - webhookStorage.set(webhook.channelId, webhook); + webhookStorage.set(webhook.channelID, webhook); } catch { delete Config.webhooks[id]; Config.save(); diff --git a/src/structures.ts b/src/structures.ts index 236e54f..233f462 100644 --- a/src/structures.ts +++ b/src/structures.ts @@ -243,9 +243,9 @@ export function getPrefix(guild: DiscordGuild | null): string { } export interface EmoteRegistryDumpEntry { - ref: string | null; + ref: string; id: Snowflake; - name: string | null; + name: string; requires_colons: boolean; animated: boolean; url: string; diff --git a/tsconfig.json b/tsconfig.json index 84b8702..2b1714b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ // Type Settings // "strict": true, // Enables all strict checks possible. - "noImplicitReturns": false, // Makes sure you don't accidentally return something + undefined. + "noImplicitReturns": true, // Makes sure you don't accidentally return something + undefined. "noFallthroughCasesInSwitch": true, // Prevents accidentally forgetting to break every switch case. Of course, if you know what you're doing, feel free to add a @ts-ignore, which also signals that it's not a mistake. "forceConsistentCasingInFileNames": true, // Make import paths case-sensitive. "./tEst" is no longer the same as "./test". "esModuleInterop": true, // Enables compatibility with Node.js' module system since the entire export can be whatever you want. allowSyntheticDefaultImports doesn't address runtime issues and is made redundant by this setting.