Compare commits

..

No commits in common. "45cb4828264d8a9b1fe42013f1e454926ec1c491" and "8ffbc367b10eca9650c92595a9f467940cf51c8d" have entirely different histories.

47 changed files with 791 additions and 1111 deletions

637
package-lock.json generated
View file

@ -12,14 +12,15 @@
"dependencies": { "dependencies": {
"canvas": "^2.7.0", "canvas": "^2.7.0",
"chalk": "^4.1.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", "figlet": "^1.5.0",
"glob": "^7.1.6", "glob": "^7.1.6",
"inquirer": "^7.3.3", "inquirer": "^7.3.3",
"mathjs": "^9.3.0", "mathjs": "^9.3.0",
"moment": "^2.29.1", "moment": "^2.29.1",
"ms": "^2.1.3", "ms": "^2.1.3",
"onion-lasers": "npm:onion-lasers-v13@^2.0.0", "onion-lasers": "^1.1.2",
"pet-pet-gif": "^1.0.8", "pet-pet-gif": "^1.0.8",
"relevant-urban": "^2.0.0", "relevant-urban": "^2.0.0",
"translate-google": "^1.4.3", "translate-google": "^1.4.3",
@ -40,7 +41,7 @@
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"ts-jest": "^26.4.4", "ts-jest": "^26.4.4",
"tsc-watch": "^4.2.9", "tsc-watch": "^4.2.9",
"typescript": "^4.4.4" "typescript": "^3.9.7"
}, },
"optionalDependencies": { "optionalDependencies": {
"fsevents": "^2.1.2" "fsevents": "^2.1.2"
@ -571,43 +572,10 @@
"node": ">=0.1.95" "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": { "node_modules/@discordjs/collection": {
"version": "0.2.4", "version": "0.1.6",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.4.tgz", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
"integrity": "sha512-PVrEJH+V6Ob0OwfagYQ/57kwt/HNEJxt5jqY4P+S3st9y29t9iokdnGMQoJXG5VEMAQIPbzu9Snw1F6yE8PdLA==", "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="
"engines": {
"node": ">=16.0.0",
"npm": ">=7.0.0"
}
}, },
"node_modules/@discordjs/form-data": { "node_modules/@discordjs/form-data": {
"version": "3.0.1", "version": "3.0.1",
@ -874,6 +842,21 @@
"node": ">= 10.14.2" "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": { "node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", "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-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": { "node_modules/@sindresorhus/is": {
"version": "4.2.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz",
"integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
@ -1172,6 +1146,17 @@
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" "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": { "node_modules/acorn": {
"version": "8.2.4", "version": "8.2.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz", "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", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" "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": { "node_modules/babel-jest": {
"version": "26.6.3", "version": "26.6.3",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
@ -1856,6 +1849,7 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
@ -2353,59 +2347,33 @@
"node": ">= 10.14.2" "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": { "node_modules/discord.js": {
"version": "13.2.0", "version": "12.5.3",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.2.0.tgz", "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
"integrity": "sha512-nyxUvL8wuQG38zx13wUMkpcA8koFszyiXdkSLwwM9opKW2LC2H5gD0cTZxImeJ6GtEnKPWT8xBiE8lLBmbNIhw==", "integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
"dependencies": { "dependencies": {
"@discordjs/builders": "^0.6.0", "@discordjs/collection": "^0.1.6",
"@discordjs/collection": "^0.2.1",
"@discordjs/form-data": "^3.0.1", "@discordjs/form-data": "^3.0.1",
"@sapphire/async-queue": "^1.1.5", "abort-controller": "^3.0.0",
"@types/ws": "^8.2.0",
"discord-api-types": "^0.23.1",
"node-fetch": "^2.6.1", "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": { "engines": {
"node": ">=16.6.0", "node": ">=12.0.0"
"npm": ">=7.0.0"
} }
}, },
"node_modules/discord.js/node_modules/@types/ws": { "node_modules/discord.js-lavalink-lib": {
"version": "8.2.0", "version": "0.1.8",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz", "resolved": "https://registry.npmjs.org/discord.js-lavalink-lib/-/discord.js-lavalink-lib-0.1.8.tgz",
"integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==", "integrity": "sha512-Kv4ps5AW4xYxMuJypHJrPL1occlV817CjHiIL7J09EdgzNRcKRIif0U6XMxWxi45Pg3DOl41Lw1V+J2GRsMgcw==",
"dependencies": { "dependencies": {
"@types/node": "*" "@lavacord/discord.js": "0.0.5",
} "axios": ">=0.21.1",
}, "discord.js": "^12.2.0",
"node_modules/discord.js/node_modules/ws": { "lavacord": "^1.1.7"
"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
}
} }
}, },
"node_modules/docopt": { "node_modules/docopt": {
@ -2606,6 +2574,14 @@
"through": "~2.3.1" "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": { "node_modules/exec-sh": {
"version": "0.3.6", "version": "0.3.6",
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
@ -2885,125 +2861,23 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/findup-sync/node_modules/define-property": { "node_modules/follow-redirects": {
"version": "2.0.2", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
"integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
"extraneous": true, "funding": [
"dependencies": { {
"is-descriptor": "^1.0.2", "type": "individual",
"isobject": "^3.0.1" "url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
}, },
"engines": { "peerDependenciesMeta": {
"node": ">=0.10.0" "debug": {
} "optional": true
}, }
"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"
} }
}, },
"node_modules/for-in": { "node_modules/for-in": {
@ -4784,6 +4658,19 @@
"node": ">=6" "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": { "node_modules/leven": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "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", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" "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": { "node_modules/lowercase-keys": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
@ -5524,12 +5406,11 @@
} }
}, },
"node_modules/onion-lasers": { "node_modules/onion-lasers": {
"name": "onion-lasers-v13", "version": "1.1.2",
"version": "2.0.0", "resolved": "https://registry.npmjs.org/onion-lasers/-/onion-lasers-1.1.2.tgz",
"resolved": "https://registry.npmjs.org/onion-lasers-v13/-/onion-lasers-v13-2.0.0.tgz", "integrity": "sha512-gQHQCdcfDSLeWFFXMTBCy2PZR/n603B+Q2L3vTj+9T1CmJS7OfO7zoFM5QrTkOY4N5hESboOdJ8eRvPXQgdxDg==",
"integrity": "sha512-HtMNLvFqSVt9mFkUJX7rwnH4d0894YmQ7167lLdtE8Wi/U2HYRSHHpB4xcLXrOPMMzcWZ4l+1knYN1OL0nL9mA==",
"dependencies": { "dependencies": {
"discord.js": "^13.2.0", "discord.js": "^12.5.3",
"glob": "^7.1.6" "glob": "^7.1.6"
} }
}, },
@ -5558,50 +5439,6 @@
"node": ">=0.10.0" "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": { "node_modules/p-cancelable": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
@ -5836,6 +5673,31 @@
"node": ">= 10" "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": { "node_modules/process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@ -6644,6 +6506,11 @@
"node": ">=0.10.0" "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": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -7507,11 +7374,6 @@
"typescript": ">=3.8 <5.0" "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": { "node_modules/tsc-watch": {
"version": "4.2.9", "version": "4.2.9",
"resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.2.9.tgz", "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.2.9.tgz",
@ -7550,6 +7412,11 @@
"node": "*" "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": { "node_modules/type-check": {
"version": "0.3.2", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@ -7599,9 +7466,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.4.4", "version": "3.9.9",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@ -7778,14 +7645,6 @@
"node": ">= 8" "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": { "node_modules/validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "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", "version": "7.4.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz",
"integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==",
"dev": true,
"engines": { "engines": {
"node": ">=8.3.0" "node": ">=8.3.0"
}, },
@ -8501,34 +8359,10 @@
"minimist": "^1.2.0" "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": { "@discordjs/collection": {
"version": "0.2.4", "version": "0.1.6",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.4.tgz", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
"integrity": "sha512-PVrEJH+V6Ob0OwfagYQ/57kwt/HNEJxt5jqY4P+S3st9y29t9iokdnGMQoJXG5VEMAQIPbzu9Snw1F6yE8PdLA==" "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="
}, },
"@discordjs/form-data": { "@discordjs/form-data": {
"version": "3.0.1", "version": "3.0.1",
@ -8751,6 +8585,14 @@
"chalk": "^4.0.0" "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": { "@mapbox/node-pre-gyp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz",
@ -8767,15 +8609,10 @@
"tar": "^6.1.0" "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": { "@sindresorhus/is": {
"version": "4.2.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz",
"integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==" "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g=="
}, },
"@sinonjs/commons": { "@sinonjs/commons": {
"version": "1.8.3", "version": "1.8.3",
@ -9033,6 +8870,14 @@
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" "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": { "acorn": {
"version": "8.2.4", "version": "8.2.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz", "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", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" "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": { "babel-jest": {
"version": "26.6.3", "version": "26.6.3",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
@ -9566,7 +9419,8 @@
"callsites": { "callsites": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true
}, },
"camelcase": { "camelcase": {
"version": "5.3.1", "version": "5.3.1",
@ -9945,40 +9799,30 @@
"integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==",
"dev": true "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": { "discord.js": {
"version": "13.2.0", "version": "12.5.3",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.2.0.tgz", "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
"integrity": "sha512-nyxUvL8wuQG38zx13wUMkpcA8koFszyiXdkSLwwM9opKW2LC2H5gD0cTZxImeJ6GtEnKPWT8xBiE8lLBmbNIhw==", "integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
"requires": { "requires": {
"@discordjs/builders": "^0.6.0", "@discordjs/collection": "^0.1.6",
"@discordjs/collection": "^0.2.1",
"@discordjs/form-data": "^3.0.1", "@discordjs/form-data": "^3.0.1",
"@sapphire/async-queue": "^1.1.5", "abort-controller": "^3.0.0",
"@types/ws": "^8.2.0",
"discord-api-types": "^0.23.1",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"ws": "^8.2.3" "prism-media": "^1.2.9",
}, "setimmediate": "^1.0.5",
"dependencies": { "tweetnacl": "^1.0.3",
"@types/ws": { "ws": "^7.4.4"
"version": "8.2.0", }
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz", },
"integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==", "discord.js-lavalink-lib": {
"requires": { "version": "0.1.8",
"@types/node": "*" "resolved": "https://registry.npmjs.org/discord.js-lavalink-lib/-/discord.js-lavalink-lib-0.1.8.tgz",
} "integrity": "sha512-Kv4ps5AW4xYxMuJypHJrPL1occlV817CjHiIL7J09EdgzNRcKRIif0U6XMxWxi45Pg3DOl41Lw1V+J2GRsMgcw==",
}, "requires": {
"ws": { "@lavacord/discord.js": "0.0.5",
"version": "8.2.3", "axios": ">=0.21.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", "discord.js": "^12.2.0",
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", "lavacord": "^1.1.7"
"requires": {}
}
} }
}, },
"docopt": { "docopt": {
@ -10132,6 +9976,11 @@
"through": "~2.3.1" "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": { "exec-sh": {
"version": "0.3.6", "version": "0.3.6",
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
@ -10358,6 +10207,11 @@
"path-exists": "^4.0.0" "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": { "for-in": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@ -11751,6 +11605,15 @@
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
"dev": true "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": { "leven": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "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", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" "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": { "lowercase-keys": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
@ -12332,11 +12190,11 @@
} }
}, },
"onion-lasers": { "onion-lasers": {
"version": "npm:onion-lasers-v13@2.0.0", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/onion-lasers-v13/-/onion-lasers-v13-2.0.0.tgz", "resolved": "https://registry.npmjs.org/onion-lasers/-/onion-lasers-1.1.2.tgz",
"integrity": "sha512-HtMNLvFqSVt9mFkUJX7rwnH4d0894YmQ7167lLdtE8Wi/U2HYRSHHpB4xcLXrOPMMzcWZ4l+1knYN1OL0nL9mA==", "integrity": "sha512-gQHQCdcfDSLeWFFXMTBCy2PZR/n603B+Q2L3vTj+9T1CmJS7OfO7zoFM5QrTkOY4N5hESboOdJ8eRvPXQgdxDg==",
"requires": { "requires": {
"discord.js": "^13.2.0", "discord.js": "^12.5.3",
"glob": "^7.1.6" "glob": "^7.1.6"
} }
}, },
@ -12359,34 +12217,6 @@
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" "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": { "p-cancelable": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
@ -12552,6 +12382,12 @@
"react-is": "^17.0.1" "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": { "process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "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": { "shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -13872,11 +13713,6 @@
"yargs-parser": "20.x" "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": { "tsc-watch": {
"version": "4.2.9", "version": "4.2.9",
"resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.2.9.tgz", "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-4.2.9.tgz",
@ -13903,6 +13739,11 @@
"safe-buffer": "^5.0.1" "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": { "type-check": {
"version": "0.3.2", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@ -13937,9 +13778,9 @@
} }
}, },
"typescript": { "typescript": {
"version": "4.4.4", "version": "3.9.9",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
"dev": true "dev": true
}, },
"underscore": { "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": { "validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "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", "version": "7.4.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz",
"integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==",
"dev": true,
"requires": {} "requires": {}
}, },
"xdg-basedir": { "xdg-basedir": {

View file

@ -17,14 +17,15 @@
"dependencies": { "dependencies": {
"canvas": "^2.7.0", "canvas": "^2.7.0",
"chalk": "^4.1.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", "figlet": "^1.5.0",
"glob": "^7.1.6", "glob": "^7.1.6",
"inquirer": "^7.3.3", "inquirer": "^7.3.3",
"mathjs": "^9.3.0", "mathjs": "^9.3.0",
"moment": "^2.29.1", "moment": "^2.29.1",
"ms": "^2.1.3", "ms": "^2.1.3",
"onion-lasers": "npm:onion-lasers-v13@^2.0.0", "onion-lasers": "^1.1.2",
"pet-pet-gif": "^1.0.8", "pet-pet-gif": "^1.0.8",
"relevant-urban": "^2.0.0", "relevant-urban": "^2.0.0",
"translate-google": "^1.4.3", "translate-google": "^1.4.3",
@ -45,7 +46,7 @@
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"ts-jest": "^26.4.4", "ts-jest": "^26.4.4",
"tsc-watch": "^4.2.9", "tsc-watch": "^4.2.9",
"typescript": "^4.4.4" "typescript": "^3.9.7"
}, },
"optionalDependencies": { "optionalDependencies": {
"fsevents": "^2.1.2" "fsevents": "^2.1.2"

View file

@ -1,6 +1,5 @@
import {NamedCommand, RestCommand} from "onion-lasers"; import {NamedCommand, RestCommand} from "onion-lasers";
import figlet from "figlet"; import figlet from "figlet";
import {Util} from "discord.js";
export default new NamedCommand({ export default new NamedCommand({
description: "Generates a figlet of your input.", description: "Generates a figlet of your input.",
@ -8,11 +7,12 @@ export default new NamedCommand({
any: new RestCommand({ any: new RestCommand({
async run({send, combined}) { async run({send, combined}) {
return send( return send(
`\`\`\`\n${Util.cleanCodeBlockContent( figlet.textSync(combined, {
figlet.textSync(combined, { horizontalLayout: "full"
horizontalLayout: "full" }),
}) {
)}\n\`\`\`` code: true
}
); );
} }
}) })

View file

@ -3,12 +3,12 @@ import {NamedCommand} from "onion-lasers";
export default new NamedCommand({ export default new NamedCommand({
description: "Insult TravBot! >:D", description: "Insult TravBot! >:D",
async run({send, channel, author}) { async run({send, channel, author}) {
channel.sendTyping(); channel.startTyping();
setTimeout(() => { setTimeout(() => {
send( 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.` `${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); }, 60000);
} }
}); });

View file

@ -39,12 +39,9 @@ export const BetCommand = new NamedCommand({
// handle invalid amount // handle invalid amount
if (amount <= 0) return send("You must bet at least one Mon!"); if (amount <= 0) return send("You must bet at least one Mon!");
else if (sender.money < amount) 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) else if (receiver.money < amount)
return send({ return send("They don't have enough Mons for that.", getMoneyEmbed(target));
content: "They don't have enough Mons for that.",
embeds: [getMoneyEmbed(target)]
});
return send("How long until the bet ends?"); return send("How long until the bet ends?");
} else return; } else return;
@ -70,15 +67,9 @@ export const BetCommand = new NamedCommand({
// handle invalid amount // handle invalid amount
if (amount <= 0) return send("You must bet at least one Mon!"); if (amount <= 0) return send("You must bet at least one Mon!");
else if (sender.money < amount) else if (sender.money < amount)
return send({ return send("You don't have enough Mons for that.", getMoneyEmbed(author));
content: "You don't have enough Mons for that.",
embeds: [getMoneyEmbed(author)]
});
else if (receiver.money < amount) else if (receiver.money < amount)
return send({ return send("They don't have enough Mons for that.", getMoneyEmbed(target));
content: "They don't have enough Mons for that.",
embeds: [getMoneyEmbed(target)]
});
// handle invalid duration // handle invalid duration
if (duration <= 0) return send("Invalid bet 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. // 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. // 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 sender = Storage.getUser(author.id);
const receiver = Storage.getUser(target.id); const receiver = Storage.getUser(target.id);

View file

@ -16,26 +16,27 @@ export const DailyCommand = new NamedCommand({
user.lastReceived = now; user.lastReceived = now;
Storage.save(); Storage.save();
send({ send({
embeds: [ embed: {
{ title: "Daily Reward",
title: "Daily Reward", description: "You received 1 Mon!",
description: "You received 1 Mon!", color: ECO_EMBED_COLOR,
color: ECO_EMBED_COLOR fields: [
} {
] name: "New balance:",
value: pluralise(user.money, "Mon", "s")
}
]
}
}); });
} else } else
send({ send({
embeds: [ embed: {
{ title: "Daily Reward",
title: "Daily Reward", description: `It's too soon to pick up your daily Mons. Try again at <t:${Math.floor(
description: `It's too soon to pick up your daily Mons. You have about ${( (user.lastReceived + 79200000) / 1000
(user.lastReceived + 79200000 - now) / )}:t>.`,
3600000 color: ECO_EMBED_COLOR
).toFixed(1)} hours to go.`, }
color: ECO_EMBED_COLOR
}
]
}); });
} }
} }
@ -54,27 +55,25 @@ export const GuildCommand = new NamedCommand({
} }
send({ send({
embeds: [ embed: {
{ title: `The Bank of ${guild!.name}`,
title: `The Bank of ${guild!.name}`, color: ECO_EMBED_COLOR,
color: ECO_EMBED_COLOR, fields: [
fields: [ {
{ name: "Accounts",
name: "Accounts", value: Object.keys(users).length,
value: Object.keys(users).length.toString(), inline: true
inline: true },
}, {
{ name: "Total Mons",
name: "Total Mons", value: totalAmount,
value: totalAmount.toString(), inline: true
inline: true
}
],
thumbnail: {
url: guild?.iconURL() ?? ""
} }
],
thumbnail: {
url: guild?.iconURL() ?? ""
} }
] }
}); });
} }
} }
@ -101,16 +100,14 @@ export const LeaderboardCommand = new NamedCommand({
} }
send({ send({
embeds: [ embed: {
{ title: "Top 10 Richest Players",
title: "Top 10 Richest Players", color: ECO_EMBED_COLOR,
color: ECO_EMBED_COLOR, fields: fields,
fields: fields, thumbnail: {
thumbnail: { url: guild?.iconURL() ?? ""
url: guild?.iconURL() ?? ""
}
} }
] }
}); });
} }
} }
@ -133,7 +130,7 @@ export const PayCommand = new NamedCommand({
if (amount <= 0) return send("You must send at least one Mon!"); if (amount <= 0) return send("You must send at least one Mon!");
else if (sender.money < amount) 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.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!"); 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!"); if (amount <= 0) return send("You must send at least one Mon!");
else if (sender.money < amount) 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) else if (!guild)
return send("You have to use this in a server if you want to send Mons with a username!"); 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!"); else if (user.bot && !IS_DEV_MODE) return send("You can't send Mons to a bot!");
const confirmed = await confirm( const confirmed = await confirm(
await send({ await send(`Are you sure you want to send ${pluralise(amount, "Mon", "s")} to this person?`, {
content: `Are you sure you want to send ${pluralise(amount, "Mon", "s")} to this person?`, embed: {
embeds: [ color: ECO_EMBED_COLOR,
{ author: {
color: ECO_EMBED_COLOR, name: user.tag,
author: { icon_url: user.displayAvatarURL({
name: user.tag, format: "png",
icon_url: user.displayAvatarURL({ dynamic: true
format: "png", })
dynamic: true
})
}
} }
] }
}), }),
author.id author.id
); );

View file

@ -21,7 +21,7 @@ export const MondayCommand = new NamedCommand({
user.money++; user.money++;
user.lastMonday = now.getTime(); user.lastMonday = now.getTime();
Storage.save(); 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 send("You've already claimed your **Mon**day reward for this week.");
} else { } else {
const weekdayName = WEEKDAY[weekday]; const weekdayName = WEEKDAY[weekday];
@ -47,7 +47,7 @@ export const AwardCommand = new NamedCommand({
const user = Storage.getUser(target.id); const user = Storage.getUser(target.id);
user.money++; user.money++;
Storage.save(); Storage.save();
send({content: `1 Mon given to ${target.username}.`, embeds: [getMoneyEmbed(target)]}); send(`1 Mon given to ${target.username}.`, getMoneyEmbed(target));
} else { } else {
send("This command is restricted to the bean."); send("This command is restricted to the bean.");
} }
@ -62,10 +62,7 @@ export const AwardCommand = new NamedCommand({
const user = Storage.getUser(target.id); const user = Storage.getUser(target.id);
user.money += amount; user.money += amount;
Storage.save(); Storage.save();
send({ send(`${pluralise(amount, "Mon", "s")} given to ${target.username}.`, getMoneyEmbed(target));
content: `${pluralise(amount, "Mon", "s")} given to ${target.username}.`,
embeds: [getMoneyEmbed(target)]
});
} else { } else {
send("You need to enter a number greater than 0."); send("You need to enter a number greater than 0.");
} }

View file

@ -52,8 +52,7 @@ export const ShopItems: ShopItem[] = [
description: "Buys what is technically a laser bridge.", description: "Buys what is technically a laser bridge.",
usage: "laser bridge", usage: "laser bridge",
run(message) { run(message) {
message.channel.send({ message.channel.send(random(lines), {
content: random(lines),
files: [ files: [
{ {
attachment: attachment:

View file

@ -3,13 +3,13 @@ import {pluralise, split} from "../../../lib";
import {Storage, getPrefix} from "../../../structures"; import {Storage, getPrefix} from "../../../structures";
import {isAuthorized, ECO_EMBED_COLOR} from "./eco-utils"; import {isAuthorized, ECO_EMBED_COLOR} from "./eco-utils";
import {ShopItems, ShopItem} from "./eco-shop-items"; import {ShopItems, ShopItem} from "./eco-shop-items";
import {EmbedField, MessageEmbedOptions} from "discord.js"; import {EmbedField} from "discord.js";
export const ShopCommand = new NamedCommand({ export const ShopCommand = new NamedCommand({
description: "Displays the list of items you can buy in the shop.", description: "Displays the list of items you can buy in the shop.",
async run({send, guild, channel, author}) { async run({send, guild, channel, author}) {
if (isAuthorized(guild, channel)) { if (isAuthorized(guild, channel)) {
function getShopEmbed(selection: ShopItem[], title: string): MessageEmbedOptions { function getShopEmbed(selection: ShopItem[], title: string) {
const fields: EmbedField[] = []; const fields: EmbedField[] = [];
for (const item of selection) for (const item of selection)
@ -20,11 +20,13 @@ export const ShopCommand = new NamedCommand({
}); });
return { return {
color: ECO_EMBED_COLOR, embed: {
title: title, color: ECO_EMBED_COLOR,
fields: fields, title: title,
footer: { fields: fields,
text: "Mon Shop | TravBot Services" footer: {
text: "Mon Shop | TravBot Services"
}
} }
}; };
} }
@ -33,14 +35,10 @@ export const ShopCommand = new NamedCommand({
const pageAmount = shopPages.length; const pageAmount = shopPages.length;
paginate(send, author.id, pageAmount, (page, hasMultiplePages) => { paginate(send, author.id, pageAmount, (page, hasMultiplePages) => {
return { return getShopEmbed(
embeds: [ shopPages[page],
getShopEmbed( hasMultiplePages ? `Shop (Page ${page + 1} of ${pageAmount})` : "Shop"
shopPages[page], );
hasMultiplePages ? `Shop (Page ${page + 1} of ${pageAmount})` : "Shop"
)
]
};
}); });
} }
} }

View file

@ -1,6 +1,6 @@
import {pluralise} from "../../../lib"; import {pluralise} from "../../../lib";
import {Storage} from "../../../structures"; 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; 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 { export function isAuthorized(guild: Guild | null, channel: TextChannel | DMChannel | NewsChannel): boolean {
if ((guild?.id === "637512823676600330" && channel?.id === "669464416420364288") || IS_DEV_MODE) return true; if (IS_DEV_MODE) {
else { return true;
channel.send("Sorry, this command can only be used in Monika's emote server. (#mon-stocks)"); }
if (guild?.id !== "637512823676600330") {
channel.send("Sorry, this command can only be used in Monika's emote server.");
return false; return false;
} else if (channel?.id !== "669464416420364288") {
channel.send("Sorry, this command can only be used in <#669464416420364288>.");
return false;
} else {
return true;
} }
} }

View file

@ -10,11 +10,11 @@ export default new NamedCommand({
const attachment = message.attachments.first()!; const attachment = message.attachments.first()!;
const gif = await petPetGif(attachment.url); const gif = await petPetGif(attachment.url);
const file = new MessageAttachment(gif, "pat.gif"); const file = new MessageAttachment(gif, "pat.gif");
send({attachments: [file]}); send(file);
} else { } else {
const gif = await petPetGif(author.displayAvatarURL({format: "png"})); const gif = await petPetGif(author.displayAvatarURL({format: "png"}));
const file = new MessageAttachment(gif, "pat.gif"); const file = new MessageAttachment(gif, "pat.gif");
send({attachments: [file]}); send(file);
} }
}, },
id: "user", id: "user",
@ -24,7 +24,7 @@ export default new NamedCommand({
const user: User = args[0]; const user: User = args[0];
const gif = await petPetGif(user.displayAvatarURL({format: "png"})); const gif = await petPetGif(user.displayAvatarURL({format: "png"}));
const file = new MessageAttachment(gif, "pat.gif"); const file = new MessageAttachment(gif, "pat.gif");
send({attachments: [file]}); send(file);
} }
}), }),
any: new RestCommand({ any: new RestCommand({
@ -36,7 +36,7 @@ export default new NamedCommand({
else { else {
const gif = await petPetGif(user.displayAvatarURL({format: "png"})); const gif = await petPetGif(user.displayAvatarURL({format: "png"}));
const file = new MessageAttachment(gif, "pat.gif"); const file = new MessageAttachment(gif, "pat.gif");
send({attachments: [file]}); send(file);
} }
} }
}) })

View file

@ -33,35 +33,26 @@ async function execPoll(send: SendFunction, message: Message, user: User, questi
dynamic: true, dynamic: true,
size: 2048 size: 2048
}) || user.defaultAvatarURL; }) || user.defaultAvatarURL;
const msg = await send({ const msg = await send(
embeds: [ new MessageEmbed()
new MessageEmbed() .setAuthor(`Poll created by ${message.author.username}`, icon)
.setAuthor(`Poll created by ${message.author.username}`, icon) .setColor(0xffffff)
.setColor(0xffffff) .setFooter("React to vote.")
.setFooter("React to vote.") .setDescription(question)
.setDescription(question) );
]
});
const results = await poll(msg, [AGREE, DISAGREE], duration); const results = await poll(msg, [AGREE, DISAGREE], duration);
send({ send(
embeds: [ new MessageEmbed()
new MessageEmbed() .setAuthor(`The results of ${message.author.username}'s poll:`, icon)
.setAuthor(`The results of ${message.author.username}'s poll:`, icon) .setTitle(question)
.setTitle(question) .setDescription(
.setDescription( `${AGREE} ${pluralise(
`${AGREE} ${pluralise( results[AGREE],
results[AGREE], "",
"", "people who agree",
"people who agree", "person who agrees"
"person who agrees" )}\n${DISAGREE} ${pluralise(results[DISAGREE], "", "people who disagree", "person who disagrees")}`
)}\n${DISAGREE} ${pluralise( )
results[DISAGREE], );
"",
"people who disagree",
"person who disagrees"
)}`
)
]
});
msg.delete(); msg.delete();
} }

View file

@ -6,17 +6,15 @@ export default new NamedCommand({
usage: "[number from 1 to 9]", usage: "[number from 1 to 9]",
async run({send}) { async run({send}) {
send({ send({
embeds: [ embed: {
{ title: "Ravioli ravioli...",
title: "Ravioli ravioli...", image: {
image: { url: `https://raw.githubusercontent.com/keanuplayz/TravBot/master/assets/ravi${Random.int(
url: `https://raw.githubusercontent.com/keanuplayz/TravBot/master/assets/ravi${Random.int( 1,
1, 10
10 )}.png`
)}.png`
}
} }
] }
}); });
}, },
number: new Command({ number: new Command({
@ -25,14 +23,12 @@ export default new NamedCommand({
if (arg >= 1 && arg <= 9) { if (arg >= 1 && arg <= 9) {
send({ send({
embeds: [ embed: {
{ title: "Ravioli ravioli...",
title: "Ravioli ravioli...", image: {
image: { url: `https://raw.githubusercontent.com/keanuplayz/TravBot/master/assets/ravi${arg}.png`
url: `https://raw.githubusercontent.com/keanuplayz/TravBot/master/assets/ravi${arg}.png`
}
} }
] }
}); });
} else { } else {
send("Please provide a number between 1 and 9."); send("Please provide a number between 1 and 9.");

View file

@ -36,25 +36,25 @@ export default new NamedCommand({
usage: "([text])", usage: "([text])",
async run({send, author}) { async run({send, author}) {
const msg = await send(transform(phrase)); const msg = await send(transform(phrase));
msg.createReactionCollector({ msg.createReactionCollector(
filter: (reaction, user) => { (reaction, user) => {
if (user.id === author.id && reaction.emoji.name === "❌") msg.delete(); if (user.id === author.id && reaction.emoji.name === "❌") msg.delete();
return false; return false;
}, },
time: 60000 {time: 60000}
}); );
}, },
any: new RestCommand({ any: new RestCommand({
async run({send, author, combined}) { async run({send, author, combined}) {
phrase = combined; phrase = combined;
const msg = await send(transform(phrase)); const msg = await send(transform(phrase));
msg.createReactionCollector({ msg.createReactionCollector(
filter: (reaction, user) => { (reaction, user) => {
if (user.id === author.id && reaction.emoji.name === "❌") msg.delete(); if (user.id === author.id && reaction.emoji.name === "❌") msg.delete();
return false; return false;
}, },
time: 60000 {time: 60000}
}); );
} }
}) })
}); });

View file

@ -21,7 +21,7 @@ export default new NamedCommand({
if (res.tags && res.tags.length > 0 && res.tags.join(" ").length < 1024) if (res.tags && res.tags.length > 0 && res.tags.join(" ").length < 1024)
embed.addField("Tags", res.tags.join(", "), true); embed.addField("Tags", res.tags.join(", "), true);
send({embeds: [embed]}); send(embed);
}) })
.catch(() => { .catch(() => {
send("Sorry, that word was not found."); send("Sorry, that word was not found.");

View file

@ -29,7 +29,7 @@ export default new NamedCommand({
.addField("Winds", current.winddisplay, true) .addField("Winds", current.winddisplay, true)
.addField("Humidity", `${current.humidity}%`, true); .addField("Humidity", `${current.humidity}%`, true);
return send({ return send({
embeds: [embed] embed
}); });
} }
); );

View file

@ -57,7 +57,7 @@ export default new NamedCommand({
const id = author.id; const id = author.id;
if (id in registry) { if (id in registry) {
send({content: `${author} ${registry[id]}`, allowedMentions: {parse: []}}); send(`${author} ${registry[id]}`, {allowedMentions: {parse: []}});
} else { } else {
send("You haven't been added to the registry yet!"); send("You haven't been added to the registry yet!");
} }
@ -69,9 +69,9 @@ export default new NamedCommand({
const id = user.id; const id = user.id;
if (id in registry) { if (id in registry) {
send({content: `${user} ${registry[id]}`, allowedMentions: {parse: []}}); send(`${user} ${registry[id]}`, {allowedMentions: {parse: []}});
} else { } 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 (typeof user !== "string") {
if (user.id in registry) { if (user.id in registry) {
send({content: `${user} ${registry[user.id]}`, allowedMentions: {parse: []}}); send(`${user} ${registry[user.id]}`, {allowedMentions: {parse: []}});
} else { } 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 { } else {
send(user); send(user);

View file

@ -1,7 +1,9 @@
import {Command, NamedCommand, getPermissionLevel, getPermissionName, CHANNEL_TYPE, RestCommand} from "onion-lasers"; import {Command, NamedCommand, getPermissionLevel, getPermissionName, CHANNEL_TYPE, RestCommand} from "onion-lasers";
import {clean} from "../../lib";
import {Config, Storage} from "../../structures"; 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 {logs} from "../../modules/globals";
import {inspect} from "util";
function getLogBuffer(type: string) { function getLogBuffer(type: string) {
return { return {
@ -280,7 +282,7 @@ export default new NamedCommand({
const newName = combined; const newName = combined;
if (!voiceChannel) return send("You are not in a voice channel."); 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."); return send("I can't change channel names without the `Manage Channels` permission.");
guildStorage.channelNames[voiceChannel.id] = newName; 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({ clear: new NamedCommand({
description: "Clears a given amount of messages.", description: "Clears a given amount of messages.",
usage: "<amount>", usage: "<amount>",
@ -370,34 +348,28 @@ export default new NamedCommand({
} }
}) })
}), }),
// TODO: Reimplement this entire command, for `send` doesn't allow eval: new NamedCommand({
// types like `unknown` to be sent anymore. Perhaps try to echo description: "Evaluate code.",
// whatever `evaled` is into an empty buffer and send this. usage: "<code>",
// (see: `Buffer.alloc(...)`) This is unlikely to work though, since permission: PERMISSIONS.BOT_OWNER,
// `Buffer.alloc(...)` requires a length, which we can't retrieve from run: "You have to enter some code to execute first.",
// an `unknown` variable. any: new RestCommand({
// eval: new NamedCommand({ // 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.
// description: "Evaluate code.", async run({send, message, channel, guild, author, member, client, args, combined}) {
// usage: "<code>", try {
// permission: PERMISSIONS.BOT_OWNER, let evaled: unknown = eval(combined);
// run: "You have to enter some code to execute first.", // If promises like message.channel.send() are invoked, await them so unnecessary error reports don't leak into the command handler.
// any: new RestCommand({ // Also, it's more useful to see the value rather than Promise { <pending> }.
// // 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. if (evaled instanceof Promise) evaled = await evaled;
// async run({send, message, channel, guild, author, member, client, args, combined}) { if (typeof evaled !== "string") evaled = inspect(evaled);
// try { // Also await this send call so that if the message is empty, it doesn't leak into the command handler.
// let evaled: unknown = eval(combined); await send(clean(evaled), {code: "js", split: true});
// // If promises like message.channel.send() are invoked, await them so unnecessary error reports don't leak into the command handler. } catch (err) {
// // Also, it's more useful to see the value rather than Promise { <pending> }. send(clean(err), {code: "js", split: true});
// 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({ nick: new NamedCommand({
description: "Change the bot's nickname.", description: "Change the bot's nickname.",
permission: PERMISSIONS.BOT_SUPPORT, 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.", description: "Shows a list of all guilds the bot is a member of.",
permission: PERMISSIONS.BOT_SUPPORT, permission: PERMISSIONS.BOT_SUPPORT,
async run({send, client}) { async run({send, client}) {
const guildList = Util.splitMessage( const guildList = client.guilds.cache.array().map((e) => e.name);
Array.from(client.guilds.cache.map((e) => e.name).values()).join("\n") send(guildList, {split: true});
);
for (let guildListPart of guildList) {
send(guildListPart);
}
} }
}), }),
activity: new NamedCommand({ activity: new NamedCommand({

View file

@ -22,7 +22,7 @@ export default new NamedCommand({
const helpMenuPages: [string, string][] = []; // An array of (category, description) tuples. 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. // 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)!; const commandList = commands.get(category)!;
let output = LEGEND; let output = LEGEND;
@ -45,16 +45,10 @@ export default new NamedCommand({
paginate(send, author.id, helpMenuPages.length, (page, hasMultiplePages) => { paginate(send, author.id, helpMenuPages.length, (page, hasMultiplePages) => {
const [category, output] = helpMenuPages[page]; const [category, output] = helpMenuPages[page];
return { return new MessageEmbed()
embeds: [ .setTitle(hasMultiplePages ? `${category} (Page ${page + 1} of ${helpMenuPages.length})` : category)
new MessageEmbed() .setDescription(output)
.setTitle( .setColor(EMBED_COLOR);
hasMultiplePages ? `${category} (Page ${page + 1} of ${helpMenuPages.length})` : category
)
.setDescription(output)
.setColor(EMBED_COLOR)
]
};
}); });
}, },
any: new RestCommand({ any: new RestCommand({
@ -93,45 +87,43 @@ export default new NamedCommand({
aliases = formattedAliases.join(", ") || "None"; aliases = formattedAliases.join(", ") || "None";
} }
return send({ return send(
embeds: [ new MessageEmbed()
new MessageEmbed() .setTitle(header)
.setTitle(header) .setDescription(command.description)
.setDescription(command.description) .setColor(EMBED_COLOR)
.setColor(EMBED_COLOR) .addFields(
.addFields( {
{ name: "Aliases",
name: "Aliases", value: aliases,
value: aliases, inline: true
inline: true },
}, {
{ name: "Category",
name: "Category", value: category,
value: category, inline: true
inline: true },
}, {
{ name: "Permission Required",
name: "Permission Required", value: `\`${getPermissionName(result.permission)}\` (Level ${result.permission})`,
value: `\`${getPermissionName(result.permission)}\` (Level ${result.permission})`, inline: true
inline: true },
}, {
{ name: "Channel Type",
name: "Channel Type", value: getChannelTypeName(result.channelType),
value: getChannelTypeName(result.channelType), inline: true
inline: true },
}, {
{ name: "NSFW Only?",
name: "NSFW Only?", value: result.nsfw ? "Yes" : "No",
value: result.nsfw ? "Yes" : "No", inline: true
inline: true },
}, {
{ name: "Usages",
name: "Usages", value: append
value: append }
} )
) );
]
});
} }
}) })
}); });

View file

@ -18,7 +18,7 @@ export default new NamedCommand({
.setTitle("Math Calculation") .setTitle("Math Calculation")
.addField("Input", `\`\`\`js\n${combined}\`\`\``) .addField("Input", `\`\`\`js\n${combined}\`\`\``)
.addField("Output", `\`\`\`js\n${resp}\`\`\``); .addField("Output", `\`\`\`js\n${resp}\`\`\``);
return send({embeds: [embed]}); return send(embed);
} }
}) })
}); });

View file

@ -9,7 +9,7 @@ export default new NamedCommand({
const voiceChannel = message.member?.voice.channel; const voiceChannel = message.member?.voice.channel;
if (!voiceChannel) return send("You are not in a 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."); return send("I am lacking the required permissions to perform this action.");
const prevName = voiceChannel.name; const prevName = voiceChannel.name;

View file

@ -11,16 +11,16 @@ export default new NamedCommand({
var queryString = args[0]; var queryString = args[0];
let url = new URL(`https://djsdocs.sorta.moe/v2/embed?src=master&q=${queryString}`); let url = new URL(`https://djsdocs.sorta.moe/v2/embed?src=master&q=${queryString}`);
const content = await getContent(url.toString()); const content = await getContent(url.toString());
const msg = await send({embeds: [content]}); const msg = await send({embed: content});
const react = await msg.react("❌"); const react = await msg.react("❌");
const collector = msg.createReactionCollector({ const collector = msg.createReactionCollector(
filter: (reaction, user) => { (reaction, user) => {
if (user.id === author.id && reaction.emoji.name === "❌") msg.delete(); if (user.id === author.id && reaction.emoji.name === "❌") msg.delete();
return false; return false;
}, },
time: 60000 {time: 60000}
}); );
collector.on("end", () => { collector.on("end", () => {
if (!msg.deleted) react.users.remove(msg.author); if (!msg.deleted) react.users.remove(msg.author);

View file

@ -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 ms from "ms";
import os from "os"; import os from "os";
import {Command, NamedCommand, getUserByNickname, CHANNEL_TYPE, getGuildByName, RestCommand} from "onion-lasers"; import {Command, NamedCommand, getUserByNickname, CHANNEL_TYPE, getGuildByName, RestCommand} from "onion-lasers";
import {formatBytes, trimArray} from "../../lib"; import {formatBytes, trimArray} from "../../lib";
import {verificationLevels, filterLevels} from "../../defs/info"; import {verificationLevels, filterLevels, regions} from "../../defs/info";
import moment, {utc} from "moment"; import moment, {utc} from "moment";
export default new NamedCommand({ export default new NamedCommand({
description: "Command to provide all sorts of info about the current server, a user, etc.", description: "Command to provide all sorts of info about the current server, a user, etc.",
async run({send, author, member}) { async run({send, author, member}) {
send({embeds: [await getUserInfo(author, member)]}); send(await getUserInfo(author, member));
}, },
subcommands: { subcommands: {
avatar: new NamedCommand({ avatar: new NamedCommand({
@ -55,47 +55,39 @@ export default new NamedCommand({
const core = os.cpus()[0]; const core = os.cpus()[0];
const embed = new MessageEmbed() const embed = new MessageEmbed()
.setColor(guild?.me?.displayHexColor || "BLUE") .setColor(guild?.me?.displayHexColor || "BLUE")
.addField( .addField("General", [
"General", `** Client:** ${client.user?.tag} (${client.user?.id})`,
[ `** Servers:** ${client.guilds.cache.size.toLocaleString()}`,
`** Client:** ${client.user?.tag} (${client.user?.id})`, `** Users:** ${client.guilds.cache
`** Servers:** ${client.guilds.cache.size.toLocaleString()}`, .reduce((a: any, b: {memberCount: any}) => a + b.memberCount, 0)
`** Users:** ${client.guilds.cache .toLocaleString()}`,
.reduce((a: any, b: {memberCount: any}) => a + b.memberCount, 0) `** Channels:** ${client.channels.cache.size.toLocaleString()}`,
.toLocaleString()}`, `** Creation Date:** ${utc(client.user?.createdTimestamp).format("Do MMMM YYYY HH:mm:ss")}`,
`** Channels:** ${client.channels.cache.size.toLocaleString()}`, `** Node.JS:** ${process.version}`,
`** Creation Date:** ${utc(client.user?.createdTimestamp).format( `** Version:** v${BOT_VERSION}`,
"Do MMMM YYYY HH:mm:ss" `** Discord.JS:** v${djsversion}`,
)}`, "\u200b"
`** Node.JS:** ${process.version}`, ])
`** Version:** v${process.env.npm_package_version}`, .addField("System", [
`** Discord.JS:** v${djsversion}`, `** Platform:** ${process.platform}`,
"\u200b" `** Uptime:** ${ms(os.uptime() * 1000, {
].join("\n") long: true
) })}`,
.addField( `** CPU:**`,
"System", `\u3000 • Cores: ${os.cpus().length}`,
[ `\u3000 • Model: ${core.model}`,
`** Platform:** ${process.platform}`, `\u3000 • Speed: ${core.speed}MHz`,
`** Uptime:** ${ms(os.uptime() * 1000, { `** Memory:**`,
long: true `\u3000 • Total: ${formatBytes(process.memoryUsage().heapTotal)}`,
})}`, `\u3000 • Used: ${formatBytes(process.memoryUsage().heapUsed)}`
`** 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")
)
.setTimestamp(); .setTimestamp();
const avatarURL = client.user?.displayAvatarURL({ const avatarURL = client.user?.displayAvatarURL({
dynamic: true, dynamic: true,
size: 2048 size: 2048
}); });
if (avatarURL) embed.setThumbnail(avatarURL); if (avatarURL) embed.setThumbnail(avatarURL);
send({embeds: [embed]}); send(embed);
} }
}), }),
guild: new NamedCommand({ guild: new NamedCommand({
@ -103,14 +95,14 @@ export default new NamedCommand({
usage: "(<guild name>/<guild ID>)", usage: "(<guild name>/<guild ID>)",
channelType: CHANNEL_TYPE.GUILD, channelType: CHANNEL_TYPE.GUILD,
async run({send, guild}) { async run({send, guild}) {
send({embeds: [await getGuildInfo(guild!, guild)]}); send(await getGuildInfo(guild!, guild));
}, },
id: "guild", id: "guild",
guild: new Command({ guild: new Command({
description: "Display info about a guild by its ID.", description: "Display info about a guild by its ID.",
async run({send, guild, args}) { async run({send, guild, args}) {
const targetGuild = args[0] as Guild; const targetGuild = args[0] as Guild;
send({embeds: [await getGuildInfo(targetGuild, guild)]}); send(await getGuildInfo(targetGuild, guild));
} }
}), }),
any: new RestCommand({ any: new RestCommand({
@ -119,7 +111,7 @@ export default new NamedCommand({
const targetGuild = getGuildByName(combined); const targetGuild = getGuildByName(combined);
if (typeof targetGuild !== "string") { if (typeof targetGuild !== "string") {
send({embeds: [await getGuildInfo(targetGuild, guild)]}); send(await getGuildInfo(targetGuild, guild));
} else { } else {
send(targetGuild); send(targetGuild);
} }
@ -134,7 +126,7 @@ export default new NamedCommand({
const user = args[0] as User; const user = args[0] as User;
// Transforms the User object into a GuildMember object of the current guild. // Transforms the User object into a GuildMember object of the current guild.
const member = guild?.members.resolve(user); const member = guild?.members.resolve(user);
send({embeds: [await getUserInfo(user, member)]}); send(await getUserInfo(user, member));
} }
}), }),
any: new RestCommand({ any: new RestCommand({
@ -143,7 +135,7 @@ export default new NamedCommand({
const user = await getUserByNickname(combined, guild); const user = await getUserByNickname(combined, guild);
// Transforms the User object into a GuildMember object of the current guild. // Transforms the User object into a GuildMember object of the current guild.
const member = guild?.members.resolve(user); 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); else send(user);
} }
}) })
@ -155,21 +147,20 @@ async function getUserInfo(user: User, member: GuildMember | null | undefined):
const embed = new MessageEmbed() const embed = new MessageEmbed()
.setThumbnail(user.displayAvatarURL({dynamic: true, size: 512})) .setThumbnail(user.displayAvatarURL({dynamic: true, size: 512}))
.setColor("BLUE") .setColor("BLUE")
.addField( .addField("User", [
"User", `** Username:** ${user.username}`,
[ `** Discriminator:** ${user.discriminator}`,
`** Username:** ${user.username}`, `** ID:** ${user.id}`,
`** Discriminator:** ${user.discriminator}`, `** Flags:** ${userFlags.length ? userFlags.join(", ") : "None"}`,
`** ID:** ${user.id}`, `** Avatar:** [Link to avatar](${user.displayAvatarURL({
`** Flags:** ${userFlags.length ? userFlags.join(", ") : "None"}`, dynamic: true
`** Avatar:** [Link to avatar](${user.displayAvatarURL({ })})`,
dynamic: true `** Time Created:** ${moment(user.createdTimestamp).format("LT")} ${moment(user.createdTimestamp).format(
})})`, "LL"
`** Time Created:** ${moment(user.createdTimestamp).format("LT")} ${moment( )} ${moment(user.createdTimestamp).fromNow()}`,
user.createdTimestamp `** Status:** ${user.presence.status}`,
).format("LL")} ${moment(user.createdTimestamp).fromNow()}` `** Game:** ${user.presence.activities || "Not playing a game."}`
].join("\n") ]);
);
if (member) { if (member) {
const roles = member.roles.cache const roles = member.roles.cache
@ -179,21 +170,16 @@ async function getUserInfo(user: User, member: GuildMember | null | undefined):
embed embed
.setColor(member.displayHexColor) .setColor(member.displayHexColor)
.addField( .addField("Member", [
"Member", `** Highest Role:** ${
[ member.roles.highest.id === member.guild.id ? "None" : member.roles.highest.name
`** Status:** ${member.presence?.status}`, }`,
`** Game:** ${member.presence?.activities ?? "Not playing a game."}`, `** Server Join Date:** ${moment(member.joinedAt).format("LL LTS")}`,
`** Highest Role:** ${ `** Hoist Role:** ${member.roles.hoist ? member.roles.hoist.name : "None"}`,
member.roles.highest.id === member.guild.id ? "None" : member.roles.highest.name `** Roles:** [${roles.length}]: ${
}`, roles.length == 0 ? "None" : roles.length <= 10 ? roles.join(", ") : trimArray(roles).join(", ")
`** 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")
);
} }
return embed; return embed;
@ -210,50 +196,41 @@ async function getGuildInfo(guild: Guild, currentGuild: Guild | null) {
const iconURL = guild.iconURL({dynamic: true}); const iconURL = guild.iconURL({dynamic: true});
const embed = new MessageEmbed().setDescription(`**Guild information for __${guild.name}__**`).setColor("BLUE"); const embed = new MessageEmbed().setDescription(`**Guild information for __${guild.name}__**`).setColor("BLUE");
const displayRoles = !!(currentGuild && guild.id === currentGuild.id); const displayRoles = !!(currentGuild && guild.id === currentGuild.id);
const owner = await guild.fetchOwner();
embed embed
.addField( .addField("General", [
"General", `** Name:** ${guild.name}`,
[ `** ID:** ${guild.id}`,
`** Name:** ${guild.name}`, `** Owner:** ${guild.owner?.user.tag} (${guild.ownerID})`,
`** ID:** ${guild.id}`, `** Region:** ${regions[guild.region]}`,
`** Owner:** ${owner.user.tag} (${guild.ownerId})`, `** Boost Tier:** ${guild.premiumTier ? `Tier ${guild.premiumTier}` : "None"}`,
`** Boost Tier:** ${guild.premiumTier ? `Tier ${guild.premiumTier}` : "None"}`, `** Explicit Filter:** ${filterLevels[guild.explicitContentFilter]}`,
`** Explicit Filter:** ${filterLevels[guild.explicitContentFilter]}`, `** Verification Level:** ${verificationLevels[guild.verificationLevel]}`,
`** Verification Level:** ${verificationLevels[guild.verificationLevel]}`, `** Time Created:** ${moment(guild.createdTimestamp).format("LT")} ${moment(guild.createdTimestamp).format(
`** Time Created:** ${moment(guild.createdTimestamp).format("LT")} ${moment( "LL"
guild.createdTimestamp )} ${moment(guild.createdTimestamp).fromNow()}`,
).format("LL")} ${moment(guild.createdTimestamp).fromNow()}`, "\u200b"
"\u200b" ])
].join("\n") .addField("Statistics", [
) `** Role Count:** ${roles.length}`,
.addField( `** Emoji Count:** ${emojis.size}`,
"Statistics", `** Regular Emoji Count:** ${emojis.filter((emoji) => !emoji.animated).size}`,
[ `** Animated Emoji Count:** ${emojis.filter((emoji) => emoji.animated).size}`,
`** Role Count:** ${roles.length}`, `** Member Count:** ${guild.memberCount}`,
`** Emoji Count:** ${emojis.size}`, `** Humans:** ${members.filter((member) => !member.user.bot).size}`,
`** Regular Emoji Count:** ${emojis.filter((emoji) => !emoji.animated).size}`, `** Bots:** ${members.filter((member) => member.user.bot).size}`,
`** Animated Emoji Count:** ${emojis.filter((emoji) => !!emoji.animated).size}`, `** Text Channels:** ${channels.filter((channel) => channel.type === "text").size}`,
`** Member Count:** ${guild.memberCount}`, `** Voice Channels:** ${channels.filter((channel) => channel.type === "voice").size}`,
`** Humans:** ${members.filter((member) => !member.user.bot).size}`, `** Boost Count:** ${guild.premiumSubscriptionCount || "0"}`,
`** Bots:** ${members.filter((member) => member.user.bot).size}`, `\u200b`
`** Text Channels:** ${channels.filter((channel) => channel instanceof TextChannel).size}`, ])
`** Voice Channels:** ${channels.filter((channel) => channel instanceof VoiceChannel).size}`, .addField("Presence", [
`** Boost Count:** ${guild.premiumSubscriptionCount || "0"}`, `** Online:** ${members.filter((member) => member.presence.status === "online").size}`,
`\u200b` `** Idle:** ${members.filter((member) => member.presence.status === "idle").size}`,
].join("\n") `** Do Not Disturb:** ${members.filter((member) => member.presence.status === "dnd").size}`,
) `** Offline:** ${members.filter((member) => member.presence.status === "offline").size}`,
.addField( displayRoles ? "\u200b" : ""
"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")
)
.setTimestamp(); .setTimestamp();
if (iconURL) embed.setThumbnail(iconURL); if (iconURL) embed.setThumbnail(iconURL);

View file

@ -3,11 +3,7 @@ import {Command, NamedCommand} from "onion-lasers";
export default new NamedCommand({ export default new NamedCommand({
description: "Gives you the invite link.", description: "Gives you the invite link.",
async run({send, client}) { async run({send, client}) {
send( send(`https://discordapp.com/api/oauth2/authorize?client_id=${client.user!.id}&permissions=8&scope=bot`);
`https://discordapp.com/api/oauth2/authorize?client_id=${
client.user!.id
}&permissions=138046467152&scope=bot`
);
}, },
number: new Command({ number: new Command({
async run({send, client, args}) { async run({send, client, args}) {

View file

@ -9,7 +9,7 @@ export default new NamedCommand({
description: "Lists all emotes the bot has in it's registry,", description: "Lists all emotes the bot has in it's registry,",
usage: "<regex pattern> (-flags)", usage: "<regex pattern> (-flags)",
async run({send, author, client}) { async run({send, author, client}) {
displayEmoteList(Array.from(client.emojis.cache.values()), send, author); displayEmoteList(client.emojis.cache.array(), send, author);
}, },
any: new RestCommand({ any: new RestCommand({
description: description:
@ -20,7 +20,7 @@ export default new NamedCommand({
const guildID: string = args[0]; const guildID: string = args[0];
displayEmoteList( displayEmoteList(
Array.from(client.emojis.cache.filter((emote) => emote.guild.id === guildID).values()), client.emojis.cache.filter((emote) => emote.guild.id === guildID).array(),
send, send,
author author
); );
@ -32,15 +32,13 @@ export default new NamedCommand({
flags = args.pop().substring(1); 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. // 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]}. // To avoid passing in a giant data structure, I'll just pass in the structure {[id: string]: [name: string]}.
let emotes = new Map<string, string>(); let emotes = new Map<string, string>();
for (const emote of emoteCollection) { 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. // 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. emoteCollection = emoteCollection.filter((emote) => emotes.has(emote.id)); // Only allow emotes that haven't been deleted.
displayEmoteList(emoteCollection, send, author); displayEmoteList(emoteCollection, send, author);
} catch (error) { } catch (error) {
// FIXME: `error` is of type `unknown` here. if (error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
// Also: <https://stackoverflow.com/questions/40141005/property-code-does-not-exist-on-type-error>
let errorName = "???";
if (error instanceof Error) {
errorName = error.name;
}
if (errorName === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
send( send(
`The regular expression you entered exceeded the time limit of ${REGEX_TIMEOUT_MS} milliseconds.` `The regular expression you entered exceeded the time limit of ${REGEX_TIMEOUT_MS} milliseconds.`
); );
} else { } else {
throw new Error(errorName); throw new Error(error);
} }
} }
} else { } else {
@ -85,7 +77,6 @@ export default new NamedCommand({
async function displayEmoteList(emotes: GuildEmoji[], send: SendFunction, author: User) { async function displayEmoteList(emotes: GuildEmoji[], send: SendFunction, author: User) {
emotes.sort((a, b) => { emotes.sort((a, b) => {
if (!a.name || !b.name) return 0;
const first = a.name.toLowerCase(); const first = a.name.toLowerCase();
const second = b.name.toLowerCase(); const second = b.name.toLowerCase();
@ -108,7 +99,7 @@ async function displayEmoteList(emotes: GuildEmoji[], send: SendFunction, author
} }
embed.setDescription(desc); embed.setDescription(desc);
return {embeds: [embed]}; return embed;
}); });
} else { } else {
send("No valid emotes found by that query."); send("No valid emotes found by that query.");

View file

@ -51,11 +51,9 @@ function searchSimilarEmotes(query: string): GuildEmoji[] {
const emoteCandidates: {emote: GuildEmoji; dist: number}[] = []; const emoteCandidates: {emote: GuildEmoji; dist: number}[] = [];
for (const emote of client.emojis.cache.values()) { for (const emote of client.emojis.cache.values()) {
if (emote.name) { const dist = levenshtein(emote.name, query);
const dist = levenshtein(emote.name, query); if (dist <= maxAcceptedDistance) {
if (dist <= maxAcceptedDistance) { emoteCandidates.push({emote, dist});
emoteCandidates.push({emote, dist});
}
} }
} }

View file

@ -16,14 +16,14 @@ export default new NamedCommand({
} }
} }
} else if (hasPermission(author, member, PERMISSIONS.BOT_SUPPORT)) { } 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({ const messages = await channel.messages.fetch({
limit: 100 limit: 100
}); });
const travMessages = messages.filter((msg) => msg.author.id === client.user!.id); 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. // 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()) { for (const message of messages.values()) {

View file

@ -1,5 +1,5 @@
import {NamedCommand, RestCommand} from "onion-lasers"; 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"; import {processEmoteQuery} from "./modules/emote-utils";
export default new NamedCommand({ export default new NamedCommand({
@ -15,7 +15,7 @@ export default new NamedCommand({
if (message.reference) { if (message.reference) {
// If the command message is a reply to another message, use that as the react target. // 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 // handles reacts by message id/distance
else if (args.length >= 2) { else if (args.length >= 2) {
@ -29,7 +29,7 @@ export default new NamedCommand({
const guildID = match[1]; const guildID = match[1];
const channelID = match[2]; const channelID = match[2];
const messageID = match[3]; const messageID = match[3];
let tmpChannel: TextBasedChannels | undefined = channel; let tmpChannel: Channel | undefined = channel;
if (guild?.id !== guildID) { if (guild?.id !== guildID) {
try { try {
@ -39,13 +39,12 @@ export default new NamedCommand({
} }
} }
if (tmpChannel?.id !== channelID) if (tmpChannel.id !== channelID) tmpChannel = guild.channels.cache.get(channelID);
tmpChannel = guild.channels.cache.get(channelID) as TextBasedChannels;
if (!tmpChannel) return send(`\`${channelID}\` is an invalid channel ID!`); if (!tmpChannel) return send(`\`${channelID}\` is an invalid channel ID!`);
if (message.id !== messageID) { if (message.id !== messageID) {
try { try {
target = await tmpChannel.messages.fetch(messageID); target = await (tmpChannel as TextChannel).messages.fetch(messageID);
} catch { } catch {
return send(`\`${messageID}\` is an invalid message ID!`); return send(`\`${messageID}\` is an invalid message ID!`);
} }
@ -58,15 +57,14 @@ export default new NamedCommand({
const match = copyIDPattern.exec(last)!; const match = copyIDPattern.exec(last)!;
const channelID = match[1]; const channelID = match[1];
const messageID = match[2]; const messageID = match[2];
let tmpChannel: TextBasedChannels | undefined = channel; let tmpChannel: Channel | undefined = channel;
if (tmpChannel?.id !== channelID) if (tmpChannel.id !== channelID) tmpChannel = guild?.channels.cache.get(channelID);
tmpChannel = guild?.channels.cache.get(channelID) as TextBasedChannels;
if (!tmpChannel) return send(`\`${channelID}\` is an invalid channel ID!`); if (!tmpChannel) return send(`\`${channelID}\` is an invalid channel ID!`);
if (message.id !== messageID) { if (message.id !== messageID) {
try { try {
target = await tmpChannel.messages.fetch(messageID); target = await (tmpChannel as TextChannel).messages.fetch(messageID);
} catch { } catch {
return send(`\`${messageID}\` is an invalid message ID!`); return send(`\`${messageID}\` is an invalid message ID!`);
} }

View file

@ -29,8 +29,7 @@ export default new NamedCommand({
const resolvedMessage = resolveMessageWithEmotes(combined); const resolvedMessage = resolveMessageWithEmotes(combined);
if (resolvedMessage) if (resolvedMessage)
webhook.send({ webhook.send(resolvedMessage, {
content: resolvedMessage,
username: member!.nickname ?? author.username, username: member!.nickname ?? author.username,
// Webhooks cannot have animated avatars, so requesting the animated version is a moot point. // Webhooks cannot have animated avatars, so requesting the animated version is a moot point.
avatarURL: avatarURL:
@ -39,17 +38,16 @@ export default new NamedCommand({
}) || author.defaultAvatarURL, }) || author.defaultAvatarURL,
allowedMentions: {parse: []}, // avoids double pings allowedMentions: {parse: []}, // avoids double pings
// "embeds" will not be included because it messes with the default ones that generate // "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 send("Cannot send an empty message.");
} else { } else {
const resolvedMessage = resolveMessageWithEmotes(combined); const resolvedMessage = resolveMessageWithEmotes(combined);
if (resolvedMessage) if (resolvedMessage) send(`*${author} says:*\n${resolvedMessage}`, {allowedMentions: {parse: []}});
send({content: `*${author} says:*\n${resolvedMessage}`, allowedMentions: {parse: []}});
else send("Cannot send an empty message."); 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();
} }
}) })
}); });

View file

@ -1,7 +1,7 @@
import {NamedCommand, CHANNEL_TYPE} from "onion-lasers"; import {NamedCommand, CHANNEL_TYPE} from "onion-lasers";
import {pluralise} from "../../lib"; import {pluralise} from "../../lib";
import moment from "moment"; import moment from "moment";
import {Collection, TextChannel, Util} from "discord.js"; import {Collection, TextChannel} from "discord.js";
const lastUsedTimestamps = new Collection<string, number>(); const lastUsedTimestamps = new Collection<string, number>();
@ -24,7 +24,7 @@ export default new NamedCommand({
const stats: { const stats: {
[id: string]: { [id: string]: {
name: string | null; name: string;
formatted: string; formatted: string;
users: number; users: number;
bots: number; bots: number;
@ -33,7 +33,7 @@ export default new NamedCommand({
let totalUserEmoteUsage = 0; 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. // 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( const allTextChannelsInCurrentGuild = guild!.channels.cache.filter(
(channel) => channel instanceof TextChannel && channel.viewable (channel) => channel.type === "text" && channel.viewable
) as Collection<string, TextChannel>; ) as Collection<string, TextChannel>;
let messagesSearched = 0; let messagesSearched = 0;
let channelsSearched = 0; let channelsSearched = 0;
@ -41,7 +41,7 @@ export default new NamedCommand({
const totalChannels = allTextChannelsInCurrentGuild.size; const totalChannels = allTextChannelsInCurrentGuild.size;
const statusMessage = await send("Gathering emotes..."); const statusMessage = await send("Gathering emotes...");
let warnings = 0; let warnings = 0;
channel.sendTyping(); channel.startTyping();
// Initialize the emote stats object with every emote in the current guild. // 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. // 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()) { for (const channel of allTextChannelsInCurrentGuild.values()) {
currentChannelName = channel.name; currentChannelName = channel.name;
let selected = channel.lastMessageId ?? message.id; let selected = channel.lastMessageID ?? message.id;
let continueLoop = true; let continueLoop = true;
while (continueLoop) { while (continueLoop) {
@ -161,6 +161,7 @@ export default new NamedCommand({
)}.` )}.`
); );
console.log("[scanemotes]", `Finished operation in ${finishTime - startTime} ms.`); console.log("[scanemotes]", `Finished operation in ${finishTime - startTime} ms.`);
channel.stopTyping();
// Display stats on emote usage. // 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. // 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")); return await send(lines, {split: true});
for (let emoteListPart of emoteList) {
return await send(emoteListPart);
}
}, },
subcommands: { subcommands: {
forcereset: new NamedCommand({ forcereset: new NamedCommand({

View file

@ -34,14 +34,11 @@ export default new NamedCommand({
const stream = streamList.get(userID)!; const stream = streamList.get(userID)!;
stream.description = combined; stream.description = combined;
stream.update(); stream.update();
send({ send("Successfully set the stream description to:", {
content: "Successfully set the stream description to:", embed: {
embeds: [ description: stream.description,
{ color: member!.displayColor
description: stream.description, }
color: member!.displayColor
}
]
}); });
} else { } else {
send("You can only use this command when streaming."); send("You can only use this command when streaming.");
@ -73,15 +70,12 @@ export default new NamedCommand({
const stream = streamList.get(userID)!; const stream = streamList.get(userID)!;
stream.thumbnail = combined; stream.thumbnail = combined;
stream.update(); stream.update();
send({ send(`Successfully set the stream thumbnail to: ${combined}`, {
content: `Successfully set the stream thumbnail to: ${combined}`, embed: {
embeds: [ description: stream.description,
{ thumbnail: {url: combined},
description: stream.description, color: member!.displayColor
thumbnail: {url: combined}, }
color: member!.displayColor
}
]
}); });
} else { } else {
send("You can only use this command when streaming."); send("You can only use this command when streaming.");

View file

@ -124,40 +124,42 @@ function getTimeEmbed(user: User) {
} }
const embed = { const embed = {
color: TIME_EMBED_COLOR, embed: {
author: { color: TIME_EMBED_COLOR,
name: user.username, author: {
icon_url: user.displayAvatarURL({ name: user.username,
format: "png", icon_url: user.displayAvatarURL({
dynamic: true format: "png",
}) dynamic: true
}, })
fields: [
{
name: "Local Date",
value: localDate
}, },
{ fields: [
name: "Day of the Week", {
value: dayOfWeek name: "Local Date",
}, value: localDate
{ },
name: "Local Time", {
value: localTime name: "Day of the Week",
}, value: dayOfWeek
{ },
name: daylightSavingsRegion !== null ? "Current Timezone Offset" : "Timezone Offset", {
value: timezoneOffset name: "Local Time",
}, value: localTime
{ },
name: "Observes Daylight Savings?", {
value: daylightSavingsRegion ? "Yes" : "No" name: daylightSavingsRegion !== null ? "Current Timezone Offset" : "Timezone Offset",
} value: timezoneOffset
] },
{
name: "Observes Daylight Savings?",
value: daylightSavingsRegion ? "Yes" : "No"
}
]
}
}; };
if (daylightSavingsRegion) { if (daylightSavingsRegion) {
embed.fields.push( embed.embed.fields.push(
{ {
name: "Daylight Savings Active?", name: "Daylight Savings Active?",
value: hasDaylightSavings(daylightSavingsRegion) ? "Yes" : "No" value: hasDaylightSavings(daylightSavingsRegion) ? "Yes" : "No"
@ -176,7 +178,7 @@ export default new NamedCommand({
description: "Show others what time it is for you.", description: "Show others what time it is for you.",
aliases: ["tz"], aliases: ["tz"],
async run({send, author}) { async run({send, author}) {
send({embeds: [getTimeEmbed(author)]}); send(getTimeEmbed(author));
}, },
subcommands: { subcommands: {
// Welcome to callback hell. We hope you enjoy your stay here! // Welcome to callback hell. We hope you enjoy your stay here!
@ -296,11 +298,10 @@ export default new NamedCommand({
const finalize = () => { const finalize = () => {
Storage.save(); Storage.save();
send({ 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.",
"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)
embeds: [getTimeEmbed(author)] );
});
}; };
if (hasDST) { if (hasDST) {
@ -357,25 +358,23 @@ export default new NamedCommand({
const time = moment().utc(); const time = moment().utc();
send({ send({
embeds: [ embed: {
{ color: TIME_EMBED_COLOR,
color: TIME_EMBED_COLOR, fields: [
fields: [ {
{ name: "Local Date",
name: "Local Date", value: time.format(DATE_FORMAT)
value: time.format(DATE_FORMAT) },
}, {
{ name: "Day of the Week",
name: "Day of the Week", value: time.format(DOW_FORMAT)
value: time.format(DOW_FORMAT) },
}, {
{ name: "Local Time",
name: "Local Time", value: time.format(TIME_FORMAT)
value: time.format(TIME_FORMAT) }
} ]
] }
}
]
}); });
} }
}), }),
@ -388,14 +387,14 @@ export default new NamedCommand({
user: new Command({ user: new Command({
description: "See what time it is for someone else.", description: "See what time it is for someone else.",
async run({send, args}) { async run({send, args}) {
send({embeds: [getTimeEmbed(args[0])]}); send(getTimeEmbed(args[0]));
} }
}), }),
any: new RestCommand({ any: new RestCommand({
description: "See what time it is for someone else (by their username).", description: "See what time it is for someone else (by their username).",
async run({send, guild, combined}) { async run({send, guild, combined}) {
const user = await getUserByNickname(combined, guild); const user = await getUserByNickname(combined, guild);
if (typeof user !== "string") send({embeds: [getTimeEmbed(user)]}); if (typeof user !== "string") send(getTimeEmbed(user));
else send(user); else send(user);
} }
}) })

View file

@ -17,7 +17,7 @@ export default new NamedCommand({
); );
} }
send({embeds: [embed]}); send(embed);
}, },
subcommands: { subcommands: {
add: new NamedCommand({ add: new NamedCommand({

View file

@ -16,21 +16,19 @@ export default new NamedCommand({
}) })
.then((res) => { .then((res) => {
send({ send({
embeds: [ embed: {
{ title: "Translation",
title: "Translation", fields: [
fields: [ {
{ name: "Input",
name: "Input", value: `\`\`\`${input}\`\`\``
value: `\`\`\`${input}\`\`\`` },
}, {
{ name: "Output",
name: "Output", value: `\`\`\`${res}\`\`\``
value: `\`\`\`${res}\`\`\`` }
} ]
] }
}
]
}); });
}) })
.catch((error) => { .catch((error) => {

View file

@ -1,21 +1,10 @@
import "./modules/globals"; import "./modules/globals";
import {Client, Permissions, Intents} from "discord.js"; import {Client, Permissions} from "discord.js";
import path from "path"; 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 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. // This of course won't actually do anything until the setup process is complete and it logs in.
export const client = new Client({ 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
]
});
import {launch} from "onion-lasers"; import {launch} from "onion-lasers";
import setup from "./modules/setup"; import setup from "./modules/setup";
@ -42,20 +31,20 @@ launch(client, path.join(__dirname, "commands"), {
name: "Moderator", name: "Moderator",
check: (_user, member) => check: (_user, member) =>
!!member && !!member &&
(member.permissions.has(Permissions.FLAGS.MANAGE_ROLES) || (member.hasPermission(Permissions.FLAGS.MANAGE_ROLES) ||
member.permissions.has(Permissions.FLAGS.MANAGE_MESSAGES) || member.hasPermission(Permissions.FLAGS.MANAGE_MESSAGES) ||
member.permissions.has(Permissions.FLAGS.KICK_MEMBERS) || member.hasPermission(Permissions.FLAGS.KICK_MEMBERS) ||
member.permissions.has(Permissions.FLAGS.BAN_MEMBERS)) member.hasPermission(Permissions.FLAGS.BAN_MEMBERS))
}, },
{ {
// ADMIN // // ADMIN //
name: "Administrator", name: "Administrator",
check: (_user, member) => !!member && member.permissions.has(Permissions.FLAGS.ADMINISTRATOR) check: (_user, member) => !!member && member.hasPermission(Permissions.FLAGS.ADMINISTRATOR)
}, },
{ {
// OWNER // // OWNER //
name: "Server Owner", name: "Server Owner",
check: (_user, member) => !!member && member.guild.ownerId === member.id check: (_user, member) => !!member && member.guild.ownerID === member.id
}, },
{ {
// BOT_SUPPORT // // BOT_SUPPORT //
@ -78,8 +67,7 @@ launch(client, path.join(__dirname, "commands"), {
// Initialize Modules // // Initialize Modules //
import "./modules/ready"; import "./modules/ready";
import "./modules/presence"; import "./modules/presence";
// TODO: Reimplement entire music system, contact Sink import "./modules/lavalink";
// import "./modules/lavalink";
import "./modules/emoteRegistry"; import "./modules/emoteRegistry";
import "./modules/systemInfo"; import "./modules/systemInfo";
import "./modules/intercept"; import "./modules/intercept";

View file

@ -154,11 +154,7 @@ export function getContent(url: string): Promise<{url: string}> {
const parsedData = JSON.parse(rawData); const parsedData = JSON.parse(rawData);
resolve(parsedData); resolve(parsedData);
} catch (e) { } catch (e) {
let errorMessage = "Something went wrong! We don't know what, though..."; reject(`Error: ${e.message}`);
if (e instanceof Error) {
errorMessage = e.message;
}
reject(`Error: ${errorMessage}`);
} }
}); });
}).on("error", (err: {message: any}) => { }).on("error", (err: {message: any}) => {

View file

@ -10,7 +10,7 @@ client.on("voiceStateUpdate", async (before, after) => {
channel && channel &&
channel.members.size === 0 && channel.members.size === 0 &&
channel.id in channelNames && 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]); channel.setName(channelNames[channel.id]);
} }

View file

@ -11,8 +11,8 @@ function updateGlobalEmoteRegistry(): void {
ref: emote.name, ref: emote.name,
id: emote.id, id: emote.id,
name: emote.name, name: emote.name,
requires_colons: emote.requiresColons ?? false, requires_colons: emote.requiresColons || false,
animated: emote.animated ?? false, animated: emote.animated,
url: emote.url, url: emote.url,
guild_id: emote.guild.name, guild_id: emote.guild.name,
guild_name: emote.guild.name guild_name: emote.guild.name

View file

@ -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. // 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. // However, it's also a pain to debug when no context is provided for an error message.
import {client} from ".."; import {client} from "..";
import {setExecuteCommandListener} from "onion-lasers";
import {TextChannel, DMChannel, NewsChannel} from "discord.js";
let lastEvent = "N/A"; 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) => { process.on("unhandledRejection", (reason: any) => {
const isLavalinkError = reason?.code === "ECONNREFUSED"; const isLavalinkError = reason?.code === "ECONNREFUSED";
const isDiscordError = reason?.name === "DiscordAPIError"; 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.
// 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"))
// That's not always the case though, especially if you add your own message events. Just be wary of that. console.error(`@${lastEvent}\n${reason.stack}`);
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
};
}); });
// This will dynamically attach all known events instead of doing it manually. // This will dynamically attach all known events instead of doing it manually.

View file

@ -25,7 +25,7 @@ client.on("guildMemberAdd", async (member) => {
if (welcomeChannel) { if (welcomeChannel) {
const channel = member.guild.channels.cache.get(welcomeChannel); const channel = member.guild.channels.cache.get(welcomeChannel);
if (channel && channel instanceof TextChannel) { if (channel && channel.type === "text") {
if (welcomeType === "graphical") { if (welcomeType === "graphical") {
const canvas = createCanvas(700, 250); const canvas = createCanvas(700, 250);
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
@ -60,9 +60,9 @@ client.on("guildMemberAdd", async (member) => {
ctx.drawImage(avatar, 25, 25, 200, 200); ctx.drawImage(avatar, 25, 25, 200, 200);
const attachment = new MessageAttachment(canvas.toBuffer("image/png"), "welcome-image.png"); 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") { } else if (welcomeType === "text") {
channel.send( (channel as TextChannel).send(
parseVars( parseVars(
welcomeMessage || "Say hello to `%user%`, everyone! We all need a warm welcome sometimes :D", welcomeMessage || "Say hello to `%user%`, everyone! We all need a warm welcome sometimes :D",
{ {

View file

@ -1,49 +1,51 @@
// import attachClientToLavalink from "discord.js-lavalink-lib"; import attachClientToLavalink from "discord.js-lavalink-lib";
// import {Config} from "../structures"; import {Config} from "../structures";
// import {client} from "../index"; 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. if (Config.lavalink) {
// attachClientToLavalink(client, { // 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.
// lavalink: { attachClientToLavalink(client, {
// restnode: { lavalink: {
// host: "localhost", restnode: {
// port: 2333, host: "localhost",
// password: "youshallnotpass" port: 2333,
// }, password: "youshallnotpass"
// nodes: [ },
// { nodes: [
// host: "localhost", {
// port: 2333, host: "localhost",
// password: "youshallnotpass" port: 2333,
// } password: "youshallnotpass"
// ] }
// }, ]
// prefix: Config.prefix, },
// helpCmd: "mhelp", prefix: Config.prefix,
// admins: ["717352467280691331"] 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. // Disable the unhandledRejection listener by Lavalink because it captures every single unhandled
// for (const listener of process.listeners("unhandledRejection")) { // rejection and adds its message with it. Then replace it with a better, more selective error handler.
// if (listener.toString().includes("discord.js-lavalink-musicbot")) { for (const listener of process.listeners("unhandledRejection")) {
// process.off("unhandledRejection", listener); if (listener.toString().includes("discord.js-lavalink-musicbot")) {
// } process.off("unhandledRejection", listener);
// } }
// }
// process.on("unhandledRejection", (reason: any) => {
// if (reason?.code === "ECONNREFUSED") { process.on("unhandledRejection", (reason: any) => {
// // 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. if (reason?.code === "ECONNREFUSED") {
// console.warn( // 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.
// `[discord.js-lavalink-musicbot] Caught unhandled rejection: ${reason.stack}\nIf this is causing issues, head to the support server at https://discord.gg/dNN4azK` 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. // It's unsafe to process uncaughtException because after an uncaught exception, the system
// for (const listener of process.listeners("uncaughtException")) { // becomes corrupted. So disable Lavalink from adding a hook to it.
// if (listener.toString().includes("discord.js-lavalink-musicbot")) { for (const listener of process.listeners("uncaughtException")) {
// process.off("uncaughtException", listener); if (listener.toString().includes("discord.js-lavalink-musicbot")) {
// } process.off("uncaughtException", listener);
// } }
}
}

View file

@ -2,9 +2,12 @@ import {client} from "../index";
import {MessageEmbed} from "discord.js"; import {MessageEmbed} from "discord.js";
import {getPrefix} from "../structures"; import {getPrefix} from "../structures";
import {getMessageByID} from "onion-lasers"; import {getMessageByID} from "onion-lasers";
import {Storage} from "../structures";
client.on("message", (message) => { client.on("message", async (message) => {
(async () => { const {messageEmbeds} = Storage.getGuild(message.guild!.id);
if (messageEmbeds) {
// Only execute if the message is from a user and isn't a command. // 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; if (message.content.startsWith(getPrefix(message.guild)) || message.author.bot) return;
const messageLink = extractFirstMessageLink(message.content); const messageLink = extractFirstMessageLink(message.content);
@ -24,7 +27,11 @@ client.on("message", (message) => {
]; ];
if (!linkMessage.cleanContent && embeds.length === 0) { 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() const infoEmbed = new MessageEmbed()
@ -42,8 +49,8 @@ client.on("message", (message) => {
infoEmbed.setImage(image!.url); 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 { export function extractFirstMessageLink(message: string): [string, string, string] | null {

View file

@ -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 {client} from "../index";
import {Storage} from "../structures"; import {Storage} from "../structures";
type Stream = { type Stream = {
streamer: GuildMember; streamer: GuildMember;
channel: VoiceChannel | StageChannel; channel: VoiceChannel;
category: string; category: string;
description?: string; description?: string;
thumbnail?: string; thumbnail?: string;
@ -19,7 +19,7 @@ export const streamList = new Collection<string, Stream>();
// Probably find a better, DRY way of doing this. // Probably find a better, DRY way of doing this.
function getStreamEmbed( function getStreamEmbed(
streamer: GuildMember, streamer: GuildMember,
channel: VoiceChannel | StageChannel, channel: VoiceChannel,
streamStart: number, streamStart: number,
category: string, category: string,
description?: string, description?: string,
@ -38,7 +38,7 @@ function getStreamEmbed(
// I decided to not include certain fields: // I decided to not include certain fields:
// .addField("Activity", "CrossCode", true) - Probably too much presence data involved, increasing memory usage. // .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("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) .addField("Category", category, true)
.setColor(streamer.displayColor) .setColor(streamer.displayColor)
.setFooter( .setFooter(
@ -90,23 +90,21 @@ client.on("voiceStateUpdate", async (before, after) => {
streamer: member, streamer: member,
channel: voiceChannel, channel: voiceChannel,
category, category,
message: await textChannel.send({ message: await textChannel.send(
content: streamNotificationPing, streamNotificationPing,
embeds: [getStreamEmbed(member, voiceChannel, streamStart, category)] getStreamEmbed(member, voiceChannel, streamStart, category)
}), ),
update(this: Stream) { update(this: Stream) {
this.message.edit({ this.message.edit(
embeds: [ getStreamEmbed(
getStreamEmbed( this.streamer,
this.streamer, this.channel,
this.channel, streamStart,
streamStart, this.category,
this.category, this.description,
this.description, this.thumbnail
this.thumbnail )
) );
]
});
}, },
streamStart streamStart
}); });
@ -127,7 +125,7 @@ client.on("voiceStateUpdate", async (before, after) => {
}); });
client.on("channelUpdate", (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()) { for (const stream of streamList.values()) {
if (after.id === stream.channel.id) { if (after.id === stream.channel.id) {
stream.update(); stream.update();

View file

@ -5,17 +5,21 @@ import {Config} from "../structures";
// Logging which guilds the bot is added to and removed from makes sense. // 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. // However, logging the specific channels that are added/removed is a tad bit privacy-invading.
client.on("guildCreate", async (guild) => { client.on("guildCreate", (guild) => {
const owner = await guild.fetchOwner(); console.log(
`[GUILD JOIN] ${guild.name} (${guild.id}) added the bot. Owner: ${guild.owner!.user.tag} (${
console.log(`[GUILD JOIN] ${guild.name} (${guild.id}) added the bot. Owner: ${owner.user.tag} (${owner.user.id}).`); guild.owner!.user.id
}).`
);
if (Config.systemLogsChannel) { if (Config.systemLogsChannel) {
const channel = client.channels.cache.get(Config.systemLogsChannel); const channel = client.channels.cache.get(Config.systemLogsChannel);
if (channel instanceof TextChannel) { if (channel && channel.type === "text") {
channel.send( (channel as TextChannel).send(
`TravBot joined: \`${guild.name}\`. The owner of this guild is: \`${owner.user.tag}\` (\`${owner.user.id}\`)` `TravBot joined: \`${guild.name}\`. The owner of this guild is: \`${guild.owner!.user.tag}\` (\`${
guild.owner!.user.id
}\`)`
); );
} else { } else {
console.warn(`${Config.systemLogsChannel} is not a valid text channel for system logs!`); console.warn(`${Config.systemLogsChannel} is not a valid text channel for system logs!`);
@ -29,8 +33,8 @@ client.on("guildDelete", (guild) => {
if (Config.systemLogsChannel) { if (Config.systemLogsChannel) {
const channel = client.channels.cache.get(Config.systemLogsChannel); const channel = client.channels.cache.get(Config.systemLogsChannel);
if (channel instanceof TextChannel) { if (channel && channel.type === "text") {
channel.send(`\`${guild.name}\` (\`${guild.id}\`) removed the bot.`); (channel as TextChannel).send(`\`${guild.name}\` (\`${guild.id}\`) removed the bot.`);
} else { } else {
console.warn( console.warn(
`${Config.systemLogsChannel} is not a valid text channel for system logs! Removing it from storage.` `${Config.systemLogsChannel} is not a valid text channel for system logs! Removing it from storage.`

View file

@ -8,7 +8,7 @@ const ID_PATTERN = /(\d{17,})/;
// Resolve any available webhooks available for a selected channel. // Resolve any available webhooks available for a selected channel.
export async function resolveWebhook(channel: TextChannel | NewsChannel): Promise<Webhook | null> { export async function resolveWebhook(channel: TextChannel | NewsChannel): Promise<Webhook | null> {
if (channel.guild.me?.permissions.has(Permissions.FLAGS.MANAGE_WEBHOOKS)) { if (channel.guild.me?.hasPermission(Permissions.FLAGS.MANAGE_WEBHOOKS)) {
const webhooksInChannel = await channel.fetchWebhooks(); const webhooksInChannel = await channel.fetchWebhooks();
if (webhooksInChannel.size > 0) return webhooksInChannel.first()!; if (webhooksInChannel.size > 0) return webhooksInChannel.first()!;
@ -61,7 +61,7 @@ export async function refreshWebhookCache(): Promise<void> {
// If there are stored webhook IDs/tokens that don't work, delete those webhooks from storage. // If there are stored webhook IDs/tokens that don't work, delete those webhooks from storage.
try { try {
const webhook = await client.fetchWebhook(id, token); const webhook = await client.fetchWebhook(id, token);
webhookStorage.set(webhook.channelId, webhook); webhookStorage.set(webhook.channelID, webhook);
} catch { } catch {
delete Config.webhooks[id]; delete Config.webhooks[id];
Config.save(); Config.save();

View file

@ -243,9 +243,9 @@ export function getPrefix(guild: DiscordGuild | null): string {
} }
export interface EmoteRegistryDumpEntry { export interface EmoteRegistryDumpEntry {
ref: string | null; ref: string;
id: Snowflake; id: Snowflake;
name: string | null; name: string;
requires_colons: boolean; requires_colons: boolean;
animated: boolean; animated: boolean;
url: string; url: string;

View file

@ -10,7 +10,7 @@
// Type Settings // // Type Settings //
"strict": true, // Enables all strict checks possible. "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. "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". "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. "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.