From d33a7804d770a8e5894f4380bd965d64eee26227 Mon Sep 17 00:00:00 2001 From: Essem Date: Wed, 31 Aug 2022 20:00:34 -0500 Subject: [PATCH] Added (hacky) message command support, lots of work to prepare for message content intent enforcement, improve broadcast, remove evalraw, update packages --- app.js | 18 +- classes/command.js | 1 + classes/imageCommand.js | 38 +---- commands/fun/ancient.js | 1 + commands/fun/bird.js | 1 + commands/fun/cat.js | 1 + commands/fun/dog.js | 1 + commands/fun/wikihow.js | 1 + commands/general/avatar.js | 10 +- commands/general/banner.js | 5 +- commands/general/base64.js | 2 + commands/general/broadcast.js | 7 +- commands/general/channel.js | 5 +- commands/general/command.js | 5 +- commands/general/count.js | 5 +- commands/general/emote.js | 4 +- commands/general/eval.js | 5 +- commands/general/evalraw.js | 31 ---- commands/general/exec.js | 5 +- commands/general/help.js | 5 +- commands/general/image.js | 2 + commands/general/imagereload.js | 5 +- commands/general/lengthen.js | 2 + commands/general/prefix.js | 5 +- commands/general/qrcreate.js | 5 +- commands/general/qrread.js | 2 + commands/general/raw.js | 5 +- commands/general/restart.js | 5 +- commands/general/serverinfo.js | 5 +- commands/general/snowflake.js | 2 + commands/general/soundreload.js | 5 +- commands/general/sticker.js | 4 + commands/general/youtube.js | 2 + commands/message/select-image.js | 23 +++ commands/music/host.js | 3 + commands/music/loop.js | 2 + commands/music/music.js | 8 +- commands/music/nowplaying.js | 2 + commands/music/play.js | 14 +- commands/music/queue.js | 2 + commands/music/remove.js | 2 + commands/music/seek.js | 4 +- commands/music/shuffle.js | 2 + commands/music/skip.js | 4 + commands/music/stop.js | 3 + commands/music/toggle.js | 2 + commands/soundboard/soundboard.js | 5 +- commands/tags/tags.js | 7 + events/interactionCreate.js | 38 +++-- package.json | 10 +- pnpm-lock.yaml | 268 ++++++++++++++---------------- shard.js | 13 +- utils/collections.js | 10 +- utils/handler.js | 91 ++++++---- utils/imagedetect.js | 25 +-- utils/soundplayer.js | 20 +-- 56 files changed, 443 insertions(+), 315 deletions(-) delete mode 100644 commands/general/evalraw.js create mode 100644 commands/message/select-image.js diff --git a/app.js b/app.js index 565bcd8..3c9d806 100644 --- a/app.js +++ b/app.js @@ -35,6 +35,8 @@ import database from "./utils/database.js"; import { Api } from "@top-gg/sdk"; const dbl = process.env.NODE_ENV === "production" && process.env.DBL ? new Api(process.env.DBL) : null; +const { types } = JSON.parse(readFileSync(new URL("./config/commands.json", import.meta.url))); + if (isMaster) { const esmBotVersion = JSON.parse(readFileSync(new URL("./package.json", import.meta.url))).version; const erisFleetVersion = JSON.parse(readFileSync(new URL("./node_modules/eris-fleet/package.json", import.meta.url))).version; // a bit of a hacky way to get the eris-fleet version @@ -66,9 +68,16 @@ esmBot ${esmBotVersion} (${(await exec("git rev-parse HEAD").then(output => outp const services = [ { name: "image", ServiceWorker: ImageWorker } ]; - if (process.env.METRICS && process.env.METRICS !== "") services.push({ name: "prometheus", ServiceWorker: PrometheusWorker }); +const intents = [ + "guilds", + "guildVoiceStates", + "guildMessages", + "directMessages" +]; +if (types.classic) intents.push("messageContent"); + const Admiral = new Fleet({ BotWorker: Shard, token: `Bot ${process.env.TOKEN}`, @@ -92,12 +101,7 @@ const Admiral = new Fleet({ }, restMode: true, messageLimit: 50, - intents: [ - "guilds", - "guildVoiceStates", - "guildMessages", - "directMessages" - ], + intents, stats: { requestTimeout: 30000 }, diff --git a/classes/command.js b/classes/command.js index 21698aa..773af54 100644 --- a/classes/command.js +++ b/classes/command.js @@ -1,4 +1,5 @@ class Command { + success = true; constructor(client, cluster, worker, ipc, options) { this.client = client; this.cluster = cluster; diff --git a/classes/imageCommand.js b/classes/imageCommand.js index e13f85a..d996039 100644 --- a/classes/imageCommand.js +++ b/classes/imageCommand.js @@ -4,40 +4,15 @@ import { runningCommands } from "../utils/collections.js"; import { readFileSync } from "fs"; const { emotes } = JSON.parse(readFileSync(new URL("../config/messages.json", import.meta.url))); import { random } from "../utils/misc.js"; +import { selectedImages } from "../utils/collections.js"; class ImageCommand extends Command { - /*this.embed = { - "title": "Your image is being generated! (PRELIMINARY EMBED)", - "description": "The current progress is outlined below:", - "color": 16711680, - "footer": { - "text": "Step 2/3" - }, - "author": { - "name": "Processing...", - "icon_url": "https://cdn.discordapp.com/avatars/429305856241172480/a20f739886ae47cfb10fa069416e8ed3.jpg" - }, - "fields": [ - { - "name": "Downloading...", - "value": "✅ Done!" - }, - { - "name": "Processing...", - "value": " In progress" - }, - { - "name": "Uploading...", - "value": " Waiting for previous steps to complete" - } - ] - };*/ - async criteria() { return true; } async run() { + this.success = false; const timestamp = this.type === "classic" ? this.message.createdAt : Math.floor((this.interaction.id / 4194304) + 1420070400000); // check if this command has already been run in this channel with the same arguments, and we are awaiting its result // if so, don't re-run it @@ -58,7 +33,9 @@ class ImageCommand extends Command { if (this.constructor.requiresImage) { try { - const image = await imageDetect(this.client, this.message, this.interaction, this.options, true); + const selection = selectedImages.get(this.author.id); + const image = selection ?? await imageDetect(this.client, this.message, this.interaction, this.options, true); + if (selection) selectedImages.delete(this.author.id); if (image === undefined) { runningCommands.delete(this.author.id); return this.constructor.noImage; @@ -101,7 +78,10 @@ class ImageCommand extends Command { try { const { buffer, type } = await this.ipc.serviceCommand("image", { type: "run", obj: magickParams }, true, 9000000); - if (type === "nogif" && this.constructor.requiresGIF) return "That isn't a GIF!"; + if (type === "nogif" && this.constructor.requiresGIF) { + return "That isn't a GIF!"; + } + this.success = true; return { file: Buffer.from(buffer.data), name: `${this.constructor.command}.${type}` diff --git a/commands/fun/ancient.js b/commands/fun/ancient.js index a80c632..9f0f4e5 100644 --- a/commands/fun/ancient.js +++ b/commands/fun/ancient.js @@ -14,6 +14,7 @@ class AncientCommand extends Command { return data.headers.location; } catch (e) { if (e.name === "AbortError") { + this.success = false; return "I couldn't get a meme in time. Maybe try again?"; } } diff --git a/commands/fun/bird.js b/commands/fun/bird.js index b22e067..5df6996 100644 --- a/commands/fun/bird.js +++ b/commands/fun/bird.js @@ -15,6 +15,7 @@ class BirdCommand extends Command { return json[0]; } catch (e) { if (e.name === "AbortError") { + this.success = false; return "I couldn't get a bird image in time. Maybe try again?"; } } diff --git a/commands/fun/cat.js b/commands/fun/cat.js index 7110f02..bfd05a9 100644 --- a/commands/fun/cat.js +++ b/commands/fun/cat.js @@ -14,6 +14,7 @@ class CatCommand extends Command { return data.headers.location; } catch (e) { if (e.name === "AbortError") { + this.success = false; return "I couldn't get a cat image in time. Maybe try again?"; } } diff --git a/commands/fun/dog.js b/commands/fun/dog.js index 4b5fa44..49fd58a 100644 --- a/commands/fun/dog.js +++ b/commands/fun/dog.js @@ -15,6 +15,7 @@ class DogCommand extends Command { return json.message; } catch (e) { if (e.name === "AbortError") { + this.success = false; return "I couldn't get a dog image in time. Maybe try again?"; } } diff --git a/commands/fun/wikihow.js b/commands/fun/wikihow.js index c6722a6..47b9e7f 100644 --- a/commands/fun/wikihow.js +++ b/commands/fun/wikihow.js @@ -21,6 +21,7 @@ class WikihowCommand extends Command { } } catch (e) { if (e.name === "AbortError") { + this.success = false; return "I couldn't get a WikiHow image in time. Maybe try again?"; } } diff --git a/commands/general/avatar.js b/commands/general/avatar.js index ccd389d..06b8b9d 100644 --- a/commands/general/avatar.js +++ b/commands/general/avatar.js @@ -8,11 +8,15 @@ class AvatarCommand extends Command { if (this.type === "classic" && this.message.mentions[0]) { return this.message.mentions[0].dynamicAvatarURL(null, 512); } else if (await this.ipc.fetchUser(member)) { - const user = await this.ipc.fetchUser(member); - return user.avatar ? this.client._formatImage(`/avatars/${user.id}/${user.avatar}`, null, 512) : `https://cdn.discordapp.com/embed/avatars/${user.discriminator % 5}.png`; // hacky "solution" + let user = await this.ipc.fetchUser(member); + if (!user) user = await this.client.getRESTUser(member); + return user?.avatar ? this.client._formatImage(`/avatars/${user.id}/${user.avatar}`, null, 512) : `https://cdn.discordapp.com/embed/avatars/${user.discriminator % 5}.png`; // hacky "solution" } else if (mentionRegex.test(member)) { const id = member.match(mentionRegex)[1]; - if (id < 21154535154122752n) return "That's not a valid mention!"; + if (id < 21154535154122752n) { + this.success = false; + return "That's not a valid mention!"; + } try { const user = await this.client.getRESTUser(id); return user.avatar ? this.client._formatImage(`/avatars/${user.id}/${user.avatar}`, null, 512) : `https://cdn.discordapp.com/embed/avatars/${user.discriminator % 5}.png`; // repeat of hacky "solution" from above diff --git a/commands/general/banner.js b/commands/general/banner.js index 41da168..bc1e4ed 100644 --- a/commands/general/banner.js +++ b/commands/general/banner.js @@ -12,7 +12,10 @@ class BannerCommand extends Command { return user.dynamicBannerURL(null, 512) ?? "This user doesn't have a banner!"; } else if (mentionRegex.test(member)) { const id = member.match(mentionRegex)[1]; - if (id < 21154535154122752n) return "That's not a valid mention!"; + if (id < 21154535154122752n) { + this.success = false; + return "That's not a valid mention!"; + } try { const user = await this.client.getRESTUser(id); return user.dynamicBannerURL(null, 512) ?? "This user doesn't have a banner!"; diff --git a/commands/general/base64.js b/commands/general/base64.js index 47763b1..450e775 100644 --- a/commands/general/base64.js +++ b/commands/general/base64.js @@ -3,11 +3,13 @@ import { clean } from "../../utils/misc.js"; class Base64Command extends Command { async run() { + this.success = false; if (this.type === "classic" && this.args.length === 0) return "You need to provide whether you want to encode or decode the text!"; const command = this.type === "classic" ? this.args[0].toLowerCase() : this.optionsArray[0].name.toLowerCase(); if (command !== "decode" && command !== "encode") return "You need to provide whether you want to encode or decode the text!"; const string = this.options.text ?? this.args.slice(1).join(" "); if (!string || !string.trim()) return `You need to provide a string to ${command}!`; + this.success = true; if (command === "decode") { const b64Decoded = Buffer.from(string, "base64").toString("utf8"); return `\`\`\`\n${await clean(b64Decoded)}\`\`\``; diff --git a/commands/general/broadcast.js b/commands/general/broadcast.js index 5d7ad7f..2f7fef8 100644 --- a/commands/general/broadcast.js +++ b/commands/general/broadcast.js @@ -5,15 +5,20 @@ class BroadcastCommand extends Command { run() { return new Promise((resolve) => { const owners = process.env.OWNER.split(","); - if (!owners.includes(this.author.id)) return "Only the bot owner can broadcast messages!"; + if (!owners.includes(this.author.id)) { + this.success = false; + resolve("Only the bot owner can broadcast messages!"); + } const message = this.options.message ?? this.args.join(" "); if (message?.trim()) { + this.ipc.centralStore.set("broadcast", message); this.ipc.broadcast("playbroadcast", message); this.ipc.register("broadcastSuccess", () => { this.ipc.unregister("broadcastSuccess"); resolve("Successfully broadcasted message."); }); } else { + this.ipc.centralStore.delete("broadcast"); this.ipc.broadcast("broadcastend"); this.ipc.register("broadcastEnd", () => { this.ipc.unregister("broadcastEnd"); diff --git a/commands/general/channel.js b/commands/general/channel.js index be2208e..f870ca0 100644 --- a/commands/general/channel.js +++ b/commands/general/channel.js @@ -3,6 +3,7 @@ import Command from "../../classes/command.js"; class ChannelCommand extends Command { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; const owners = process.env.OWNER.split(","); if (!this.member.permissions.has("administrator") && !owners.includes(this.member.id)) return "You need to be an administrator to enable/disable me!"; @@ -23,6 +24,7 @@ class ChannelCommand extends Command { } await db.disableChannel(channel); + this.success = true; return `I have been disabled in this channel. To re-enable me, just run \`${guildDB.prefix}channel enable\`.`; } else if (this.args[0].toLowerCase() === "enable") { let channel; @@ -36,11 +38,12 @@ class ChannelCommand extends Command { } await db.enableChannel(channel); + this.success = true; return "I have been re-enabled in this channel."; } } - static description = "Enables/disables me in a channel (does not work with slash commands)"; + static description = "Enables/disables classic commands in a channel (use server settings for slash commands)"; static arguments = ["[enable/disable]", "{id}"]; static slashAllowed = false; static directAllowed = false; diff --git a/commands/general/command.js b/commands/general/command.js index 5a40b2c..d3b02c8 100644 --- a/commands/general/command.js +++ b/commands/general/command.js @@ -4,6 +4,7 @@ import * as collections from "../../utils/collections.js"; class CommandCommand extends Command { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; const owners = process.env.OWNER.split(","); if (!this.member.permissions.has("administrator") && !owners.includes(this.member.id)) return "You need to be an administrator to enable/disable me!"; @@ -21,16 +22,18 @@ class CommandCommand extends Command { if (disabled?.includes(command)) return "That command is already disabled!"; await db.disableCommand(this.channel.guild.id, command); + this.success = true; return `The command has been disabled. To re-enable it, just run \`${guildDB.prefix}command enable ${command}\`.`; } else if (this.args[0].toLowerCase() === "enable") { if (!disabled?.includes(command)) return "That command isn't disabled!"; await db.enableCommand(this.channel.guild.id, command); + this.success = true; return `The command \`${command}\` has been re-enabled.`; } } - static description = "Enables/disables a command for a server"; + static description = "Enables/disables a classic command for a server (use server settings for slash commands)"; static aliases = ["cmd"]; static arguments = ["[enable/disable]", "[command]"]; static slashAllowed = false; diff --git a/commands/general/count.js b/commands/general/count.js index c700e48..79266e6 100644 --- a/commands/general/count.js +++ b/commands/general/count.js @@ -4,7 +4,10 @@ import Command from "../../classes/command.js"; class CountCommand extends Command { async run() { - if (this.channel.guild && !this.channel.permissionsOf(this.client.user.id).has("embedLinks")) return "I don't have the `Embed Links` permission!"; + if (this.channel.guild && !this.channel.permissionsOf(this.client.user.id).has("embedLinks")) { + this.success = false; + return "I don't have the `Embed Links` permission!"; + } const counts = await database.getCounts(); const countArray = []; for (const entry of Object.entries(counts)) { diff --git a/commands/general/emote.js b/commands/general/emote.js index 3573a45..d3685ba 100644 --- a/commands/general/emote.js +++ b/commands/general/emote.js @@ -4,8 +4,7 @@ import Command from "../../classes/command.js"; class EmoteCommand extends Command { async run() { const emoji = this.options.emoji ?? this.content; - if (!emoji || !emoji.trim()) return "You need to provide an emoji!"; - if (emoji.split(" ")[0].match(/^$/)) { + if (emoji && emoji.trim() && emoji.split(" ")[0].match(/^$/)) { return `https://cdn.discordapp.com/emojis/${emoji.split(" ")[0].replace(/^<(a)?:.+:(\d+)>$/, "$2")}.${emoji.split(" ")[0].replace(/^<(a)?:.+:(\d+)>$/, "$1") === "a" ? "gif" : "png"}`; } else if (emoji.match(emojiRegex)) { const codePoints = []; @@ -14,6 +13,7 @@ class EmoteCommand extends Command { } return `https://twemoji.maxcdn.com/v/latest/72x72/${codePoints.join("-").replace("-fe0f", "")}.png`; } else { + this.success = false; return "You need to provide a valid emoji to get an image!"; } } diff --git a/commands/general/eval.js b/commands/general/eval.js index 9456bc1..5d8d110 100644 --- a/commands/general/eval.js +++ b/commands/general/eval.js @@ -4,7 +4,10 @@ import Command from "../../classes/command.js"; class EvalCommand extends Command { async run() { const owners = process.env.OWNER.split(","); - if (!owners.includes(this.author.id)) return "Only the bot owner can use eval!"; + if (!owners.includes(this.author.id)) { + this.success = false; + return "Only the bot owner can use eval!"; + } await this.acknowledge(); const code = this.options.code ?? this.args.join(" "); try { diff --git a/commands/general/evalraw.js b/commands/general/evalraw.js deleted file mode 100644 index 302d3ef..0000000 --- a/commands/general/evalraw.js +++ /dev/null @@ -1,31 +0,0 @@ -import { clean } from "../../utils/misc.js"; -import Command from "../../classes/command.js"; - -class EvalRawCommand extends Command { - async run() { - const owners = process.env.OWNER.split(","); - if (!owners.includes(this.author.id)) return "Only the bot owner can use evalraw!"; - const code = this.args.join(" "); - try { - const evaled = eval(code); - if (evaled.length >= 2000) { - return { - text: "The result was too large, so here it is as a file:", - file: evaled, - name: "result.txt" - }; - } else { - return evaled; - } - } catch (err) { - return `\`ERROR\` \`\`\`xl\n${await clean(err)}\n\`\`\``; - } - } - - static description = "Executes JavaScript code (with raw output)"; - static aliases = ["run"]; - static arguments = ["[code]"]; - static slashAllowed = false; -} - -export default EvalRawCommand; \ No newline at end of file diff --git a/commands/general/exec.js b/commands/general/exec.js index 5203675..c0bb4d6 100644 --- a/commands/general/exec.js +++ b/commands/general/exec.js @@ -7,7 +7,10 @@ import Command from "../../classes/command.js"; class ExecCommand extends Command { async run() { const owners = process.env.OWNER.split(","); - if (!owners.includes(this.author.id)) return "Only the bot owner can use exec!"; + if (!owners.includes(this.author.id)) { + this.success = false; + return "Only the bot owner can use exec!"; + } await this.acknowledge(); const code = this.options.cmd ?? this.args.join(" "); try { diff --git a/commands/general/help.js b/commands/general/help.js index dbd79bd..27abeea 100644 --- a/commands/general/help.js +++ b/commands/general/help.js @@ -54,7 +54,10 @@ class HelpCommand extends Command { } return embed; } else { - if (this.channel.guild && !this.channel.permissionsOf(this.client.user.id).has("embedLinks")) return "I don't have the `Embed Links` permission!"; + if (this.channel.guild && !this.channel.permissionsOf(this.client.user.id).has("embedLinks")) { + this.success = false; + return "I don't have the `Embed Links` permission!"; + } const pages = []; if (help.categories === help.categoryTemplate && !help.generated) await help.generateList(); for (const category of Object.keys(help.categories)) { diff --git a/commands/general/image.js b/commands/general/image.js index 7f92b5d..c030071 100644 --- a/commands/general/image.js +++ b/commands/general/image.js @@ -7,6 +7,7 @@ import Command from "../../classes/command.js"; class ImageSearchCommand extends Command { async run() { + this.success = false; if (this.channel.guild && !this.channel.permissionsOf(this.client.user.id).has("embedLinks")) return "I don't have the `Embed Links` permission!"; const query = this.options.query ?? this.args.join(" "); if (!query || !query.trim()) return "You need to provide something to search for!"; @@ -34,6 +35,7 @@ class ImageSearchCommand extends Command { }] }); } + this.success = true; return paginator(this.client, { type: this.type, message: this.message, interaction: this.interaction, channel: this.channel, author: this.author }, embeds); } diff --git a/commands/general/imagereload.js b/commands/general/imagereload.js index decc5c0..981604f 100644 --- a/commands/general/imagereload.js +++ b/commands/general/imagereload.js @@ -3,7 +3,10 @@ import Command from "../../classes/command.js"; class ImageReloadCommand extends Command { async run() { const owners = process.env.OWNER.split(","); - if (!owners.includes(this.author.id)) return "Only the bot owner can reload the image servers!"; + if (!owners.includes(this.author.id)) { + this.success = false; + return "Only the bot owner can reload the image servers!"; + } const amount = await this.ipc.serviceCommand("image", { type: "reload" }, true); if (amount > 0) { return `Successfully connected to ${amount} image servers.`; diff --git a/commands/general/lengthen.js b/commands/general/lengthen.js index 735a2c5..66e6a6c 100644 --- a/commands/general/lengthen.js +++ b/commands/general/lengthen.js @@ -6,9 +6,11 @@ class LengthenCommand extends Command { async run() { await this.acknowledge(); const input = this.options.url ?? this.args.join(" "); + this.success = false; if (!input || !input.trim() || !urlCheck(input)) return "You need to provide a short URL to lengthen!"; if (urlCheck(input)) { const url = await request(encodeURI(input), { method: "HEAD" }); + this.success = true; return url.headers.location || input; } else { return "That isn't a URL!"; diff --git a/commands/general/prefix.js b/commands/general/prefix.js index 6ab4648..cbcebcd 100644 --- a/commands/general/prefix.js +++ b/commands/general/prefix.js @@ -7,7 +7,10 @@ class PrefixCommand extends Command { const guild = await database.getGuild(this.channel.guild.id); if (this.args.length !== 0) { const owners = process.env.OWNER.split(","); - if (!this.member.permissions.has("administrator") && !owners.includes(this.member.id)) return "You need to be an administrator to change the bot prefix!"; + if (!this.member.permissions.has("administrator") && !owners.includes(this.member.id)) { + this.success = false; + return "You need to be an administrator to change the bot prefix!"; + } await database.setPrefix(this.args[0], this.channel.guild); return `The prefix has been changed to ${this.args[0]}.`; } else { diff --git a/commands/general/qrcreate.js b/commands/general/qrcreate.js index 4864bda..3c0193c 100644 --- a/commands/general/qrcreate.js +++ b/commands/general/qrcreate.js @@ -4,7 +4,10 @@ import Command from "../../classes/command.js"; class QrCreateCommand extends Command { async run() { - if (this.args.length === 0) return "You need to provide some text to generate a QR code!"; + if (this.args.length === 0) { + this.success = false; + return "You need to provide some text to generate a QR code!"; + } await this.acknowledge(); const writable = new PassThrough(); qrcode.toFileStream(writable, this.content, { margin: 1 }); diff --git a/commands/general/qrread.js b/commands/general/qrread.js index a9ca2bc..cc44cbe 100644 --- a/commands/general/qrread.js +++ b/commands/general/qrread.js @@ -8,12 +8,14 @@ import imageDetect from "../../utils/imagedetect.js"; class QrReadCommand extends Command { async run() { const image = await imageDetect(this.client, this.message, this.interaction, this.options); + this.success = false; if (image === undefined) return "You need to provide an image/GIF with a QR code to read!"; await this.acknowledge(); const data = Buffer.from(await (await request(image.path)).body.arrayBuffer()); const rawData = await sharp(data).ensureAlpha().raw().toBuffer({ resolveWithObject: true }); const qrBuffer = jsqr(rawData.data, rawData.info.width, rawData.info.height); if (!qrBuffer) return "I couldn't find a QR code!"; + this.success = true; return `\`\`\`\n${await clean(qrBuffer.data)}\n\`\`\``; } diff --git a/commands/general/raw.js b/commands/general/raw.js index cddc5fb..9c5c4be 100644 --- a/commands/general/raw.js +++ b/commands/general/raw.js @@ -5,7 +5,10 @@ class RawCommand extends Command { async run() { await this.acknowledge(); const image = await imageDetect(this.client, this.message, this.interaction, this.options); - if (image === undefined) return "You need to provide an image/GIF to get a raw URL!"; + if (image === undefined) { + this.success = false; + return "You need to provide an image/GIF to get a raw URL!"; + } return image.path; } diff --git a/commands/general/restart.js b/commands/general/restart.js index 746b524..8df5f54 100644 --- a/commands/general/restart.js +++ b/commands/general/restart.js @@ -3,7 +3,10 @@ import Command from "../../classes/command.js"; class RestartCommand extends Command { async run() { const owners = process.env.OWNER.split(","); - if (!owners.includes(this.author.id)) return "Only the bot owner can restart me!"; + if (!owners.includes(this.author.id)) { + this.success = false; + return "Only the bot owner can restart me!"; + } await this.client.createMessage(this.channel.id, Object.assign({ content: "esmBot is restarting." }, this.reference)); diff --git a/commands/general/serverinfo.js b/commands/general/serverinfo.js index 71d9812..a420b50 100644 --- a/commands/general/serverinfo.js +++ b/commands/general/serverinfo.js @@ -2,7 +2,10 @@ import Command from "../../classes/command.js"; class ServerInfoCommand extends Command { async run() { - if (!this.channel.guild) return "This command only works in servers!"; + if (!this.channel.guild) { + this.success = false; + return "This command only works in servers!"; + } const owner = await this.channel.guild.members.get(this.channel.guild.ownerID); return { embeds: [{ diff --git a/commands/general/snowflake.js b/commands/general/snowflake.js index 53a0253..6f6b532 100644 --- a/commands/general/snowflake.js +++ b/commands/general/snowflake.js @@ -2,8 +2,10 @@ import Command from "../../classes/command.js"; class SnowflakeCommand extends Command { async run() { + this.success = false; if (!this.args[0]) return "You need to provide a snowflake ID!"; if (!this.args[0].match(/^?$/) && this.args[0] < 21154535154122752n) return "That's not a valid snowflake!"; + this.success = true; return `", "") / 4194304) + 1420070400000) / 1000)}:F>`; } diff --git a/commands/general/soundreload.js b/commands/general/soundreload.js index bbba443..d92f533 100644 --- a/commands/general/soundreload.js +++ b/commands/general/soundreload.js @@ -5,7 +5,10 @@ class SoundReloadCommand extends Command { run() { return new Promise((resolve) => { const owners = process.env.OWNER.split(","); - if (!owners.includes(this.author.id)) return "Only the bot owner can reload Lavalink!"; + if (!owners.includes(this.author.id)) { + this.success = false; + return "Only the bot owner can reload Lavalink!"; + } this.acknowledge().then(() => { this.ipc.broadcast("soundreload"); this.ipc.register("soundReloadSuccess", (msg) => { diff --git a/commands/general/sticker.js b/commands/general/sticker.js index 275cc2d..a54cd45 100644 --- a/commands/general/sticker.js +++ b/commands/general/sticker.js @@ -4,10 +4,13 @@ import imagedetect from "../../utils/imagedetect.js"; class StickerCommand extends Command { async run() { const result = await imagedetect(this.client, this.message, this.interaction, this.options, false, false, true); + this.success = false; if (!result) return "You need to provide a sticker!"; if (result.format_type === 1) { // PNG + this.success = true; return `https://cdn.discordapp.com/stickers/${result.id}.png`; } else if (result.format_type === 2) { // APNG + this.success = true; return { embeds: [{ color: 16711680, @@ -18,6 +21,7 @@ class StickerCommand extends Command { }] }; } else if (result.format_type === 3) { // Lottie + this.success = true; return `I can't display this sticker because it uses the Lottie animation format; however, I can give you the raw JSON link to it: https://cdn.discordapp.com/stickers/${result.id}.json`; } else { return "I don't recognize that sticker format!"; diff --git a/commands/general/youtube.js b/commands/general/youtube.js index 50788b7..a135590 100644 --- a/commands/general/youtube.js +++ b/commands/general/youtube.js @@ -8,6 +8,7 @@ import Command from "../../classes/command.js"; class YouTubeCommand extends Command { async run() { const query = this.options.query ?? this.args.join(" "); + this.success = false; if (!query || !query.trim()) return "You need to provide something to search for!"; await this.acknowledge(); const messages = []; @@ -16,6 +17,7 @@ class YouTubeCommand extends Command { for (const [i, value] of videos.results.entries()) { messages.push({ content: `Page ${i + 1} of ${videos.results.length}\n<:youtube:637020823005167626> **${value.title.replaceAll("*", "\\*")}**\nUploaded by **${value.author.replaceAll("*", "\\*")}**\n${value.url}` }); } + this.success = true; return paginator(this.client, { type: this.type, message: this.message, interaction: this.interaction, channel: this.channel, author: this.author }, messages); } diff --git a/commands/message/select-image.js b/commands/message/select-image.js new file mode 100644 index 0000000..e279d95 --- /dev/null +++ b/commands/message/select-image.js @@ -0,0 +1,23 @@ +import Command from "../../classes/command.js"; +import imageDetect from "../../utils/imagedetect.js"; +import { selectedImages } from "../../utils/collections.js"; + +class SelectImageCommand extends Command { + async run() { + const message = this.interaction.data.resolved.messages.get(this.interaction.data.target_id); + const image = await imageDetect(this.client, message, this.interaction, this.options, true, false, false, true); + this.success = false; + if (image === undefined) { + return "I couldn't find an image in that message!"; + } else if (image.type === "large") { + return "That image is too large (>= 25MB)! Try using a smaller image."; + } else if (image.type === "tenorlimit") { + return "I've been rate-limited by Tenor. Please try uploading your GIF elsewhere."; + } + selectedImages.set(this.author.id, image); + this.success = true; + return "The image has been selected for your next command."; + } +} + +export default SelectImageCommand; \ No newline at end of file diff --git a/commands/music/host.js b/commands/music/host.js index 49a8d8c..b68948a 100644 --- a/commands/music/host.js +++ b/commands/music/host.js @@ -3,6 +3,7 @@ import MusicCommand from "../../classes/musicCommand.js"; class HostCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; @@ -37,9 +38,11 @@ class HostCommand extends MusicCommand { const object = this.connection; object.host = member.id; players.set(this.channel.guild.id, object); + this.success = true; return `🔊 ${member.mention} is the new voice channel host.`; } else { const member = this.channel.guild ? this.channel.guild.members.get(players.get(this.channel.guild.id).host) : undefined; + this.success = true; return `🔊 The current voice channel host is **${member?.username}#${member?.discriminator}**.`; } } diff --git a/commands/music/loop.js b/commands/music/loop.js index fe5c2d6..9f06701 100644 --- a/commands/music/loop.js +++ b/commands/music/loop.js @@ -3,6 +3,7 @@ import MusicCommand from "../../classes/musicCommand.js"; class LoopCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; @@ -10,6 +11,7 @@ class LoopCommand extends MusicCommand { const object = this.connection; object.loop = !object.loop; players.set(this.channel.guild.id, object); + this.success = true; return object.loop ? "🔊 The player is now looping." : "🔊 The player is no longer looping."; } diff --git a/commands/music/music.js b/commands/music/music.js index 6f55687..29510b3 100644 --- a/commands/music/music.js +++ b/commands/music/music.js @@ -5,7 +5,7 @@ import { commands, aliases, info, categories } from "../../utils/collections.js" class MusicAIOCommand extends Command { async run() { let cmd = this.type === "classic" ? this.args[0] : this.optionsArray[0].name; - if (cmd === "music" || this.constructor.aliases.includes(cmd)) return "https://media.discordapp.net/attachments/322114245632327703/941958748874887178/robot_dance-trans.gif"; + if (cmd === "music" || this.constructor.aliases.includes(cmd)) return "https://projectlounge.pw/robotdance.gif"; if (this.type === "classic") { this.origOptions.args.shift(); } else { @@ -14,8 +14,12 @@ class MusicAIOCommand extends Command { if (aliases.has(cmd)) cmd = aliases.get(cmd); if (commands.has(cmd) && info.get(cmd).category === "music") { const command = commands.get(cmd); - return await (new command(this.client, this.cluster, this.worker, this.ipc, this.origOptions)).run(); + const inst = new command(this.client, this.cluster, this.worker, this.ipc, this.origOptions); + const result = await inst.run(); + this.success = inst.success; + return result; } else { + this.success = false; return "That isn't a valid music command!"; } } diff --git a/commands/music/nowplaying.js b/commands/music/nowplaying.js index a3e6724..31b4f57 100644 --- a/commands/music/nowplaying.js +++ b/commands/music/nowplaying.js @@ -3,6 +3,7 @@ import MusicCommand from "../../classes/musicCommand.js"; class NowPlayingCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; @@ -10,6 +11,7 @@ class NowPlayingCommand extends MusicCommand { if (!player) return "I'm not playing anything!"; const track = await player.node.rest.decode(player.track); const parts = Math.floor((player.position / track.length) * 10); + this.success = true; return { embeds: [{ color: 16711680, diff --git a/commands/music/play.js b/commands/music/play.js index eb3d56e..39cfd98 100644 --- a/commands/music/play.js +++ b/commands/music/play.js @@ -5,9 +5,12 @@ const prefixes = ["ytsearch:", "ytmsearch:", "scsearch:", "spsearch:", "amsearch class PlayCommand extends MusicCommand { async run() { const input = this.options.query ?? this.args.join(" "); - if (!input && (this.type === "classic" ? (!this.message || this.message.attachments.length <= 0) : !this.options.file)) return "You need to provide what you want to play!"; + if (!input && ((!this.message || this.message?.attachments.length <= 0))) { + this.success = false; + return "You need to provide what you want to play!"; + } let query = input ? input.trim() : ""; - const attachment = this.type === "classic" ? this.message.attachments[0] : (this.options.file ? this.interaction.data.resolved.attachments[this.options.file] : null); + const attachment = this.type === "classic" ? this.message.attachments[0] : null; if (query.startsWith("||") && query.endsWith("||")) { query = query.substring(2, query.length - 2); } @@ -24,13 +27,10 @@ class PlayCommand extends MusicCommand { } static flags = [{ - name: "file", - type: 11, - description: "An audio file attachment" - }, { name: "query", type: 3, - description: "An audio search query or URL" + description: "An audio search query or URL", + required: true }]; static description = "Plays a song or adds it to the queue"; static aliases = ["p"]; diff --git a/commands/music/queue.js b/commands/music/queue.js index ad1b389..2b6feb1 100644 --- a/commands/music/queue.js +++ b/commands/music/queue.js @@ -6,6 +6,7 @@ import MusicCommand from "../../classes/musicCommand.js"; class QueueCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; @@ -52,6 +53,7 @@ class QueueCommand extends MusicCommand { }); } if (embeds.length === 0) return "There's nothing in the queue!"; + this.success = true; return paginator(this.client, { type: this.type, message: this.message, interaction: this.interaction, channel: this.channel, author: this.author }, embeds); } diff --git a/commands/music/remove.js b/commands/music/remove.js index a9904de..fb0df5e 100644 --- a/commands/music/remove.js +++ b/commands/music/remove.js @@ -3,6 +3,7 @@ import MusicCommand from "../../classes/musicCommand.js"; class RemoveCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; @@ -13,6 +14,7 @@ class RemoveCommand extends MusicCommand { if (removed.length === 0) return "That's not a valid position!"; const track = await this.connection.player.node.rest.decode(removed[0]); queues.set(this.channel.guild.id, this.queue); + this.success = true; return `🔊 The song \`${track.title ? track.title : "(blank)"}\` has been removed from the queue.`; } diff --git a/commands/music/seek.js b/commands/music/seek.js index 1bda07c..85467bc 100644 --- a/commands/music/seek.js +++ b/commands/music/seek.js @@ -2,6 +2,7 @@ import MusicCommand from "../../classes/musicCommand.js"; class SeekCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; @@ -11,13 +12,14 @@ class SeekCommand extends MusicCommand { if (!track.isSeekable) return "This track isn't seekable!"; const pos = this.options.position ?? this.args[0]; let seconds; - if (pos.includes(":")) { + if (typeof pos === "string" && pos.includes(":")) { seconds = +(pos.split(":").reduce((acc, time) => (60 * acc) + +time)); } else { seconds = parseFloat(pos); } if (isNaN(seconds) || (seconds * 1000) > track.length || (seconds * 1000) < 0) return "That's not a valid position!"; player.seekTo(seconds * 1000); + this.success = true; return `🔊 Seeked track to ${seconds} second(s).`; } diff --git a/commands/music/shuffle.js b/commands/music/shuffle.js index 28536d5..cab7957 100644 --- a/commands/music/shuffle.js +++ b/commands/music/shuffle.js @@ -3,6 +3,7 @@ import MusicCommand from "../../classes/musicCommand.js"; class ShuffleCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; @@ -10,6 +11,7 @@ class ShuffleCommand extends MusicCommand { const object = this.connection; object.shuffle = !object.shuffle; players.set(this.channel.guild.id, object); + this.success = true; return object.shuffle ? "🔊 The player is now shuffling." : "🔊 The player is no longer shuffling."; } diff --git a/commands/music/skip.js b/commands/music/skip.js index f060103..d8ee219 100644 --- a/commands/music/skip.js +++ b/commands/music/skip.js @@ -3,6 +3,7 @@ import MusicCommand from "../../classes/musicCommand.js"; class SkipCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; @@ -18,13 +19,16 @@ class SkipCommand extends MusicCommand { if (votes.count + 1 === votes.max) { await player.player.stopTrack(this.channel.guild.id); skipVotes.set(this.channel.guild.id, { count: 0, ids: [], max: Math.min(3, player.voiceChannel.voiceMembers.filter((i) => i.id !== this.client.user.id && !i.bot).length) }); + this.success = true; if (this.type === "application") return "🔊 The current song has been skipped."; } else { skipVotes.set(this.channel.guild.id, newObject); + this.success = true; return `🔊 Voted to skip song (${votes.count + 1}/${votes.max} people have voted).`; } } else { await player.player.stopTrack(); + this.success = true; if (this.type === "application") return "🔊 The current song has been skipped."; } } diff --git a/commands/music/stop.js b/commands/music/stop.js index f2ae558..f5a4fbc 100644 --- a/commands/music/stop.js +++ b/commands/music/stop.js @@ -3,11 +3,13 @@ import MusicCommand from "../../classes/musicCommand.js"; class StopCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; if (!this.connection) { await manager.getNode().leaveChannel(this.channel.guild.id); + this.success = true; return "🔊 The current voice channel session has ended."; } if (this.connection.host !== this.author.id && !this.member.permissions.has("manageChannels")) return "Only the current voice session host can stop the music!"; @@ -15,6 +17,7 @@ class StopCommand extends MusicCommand { connection.node.leaveChannel(this.channel.guild.id); players.delete(this.channel.guild.id); queues.delete(this.channel.guild.id); + this.success = true; return "🔊 The current voice channel session has ended."; } diff --git a/commands/music/toggle.js b/commands/music/toggle.js index 986ae4c..6499900 100644 --- a/commands/music/toggle.js +++ b/commands/music/toggle.js @@ -2,12 +2,14 @@ import MusicCommand from "../../classes/musicCommand.js"; class ToggleCommand extends MusicCommand { async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; if (!this.member.voiceState.channelID) return "You need to be in a voice channel first!"; if (!this.channel.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!"; if (this.connection.host !== this.author.id && !this.member.permissions.has("manageChannels")) return "Only the current voice session host can pause/resume the music!"; const player = this.connection.player; player.setPaused(!player.paused ? true : false); + this.success = true; return `🔊 The player has been ${player.paused ? "paused" : "resumed"}.`; } diff --git a/commands/soundboard/soundboard.js b/commands/soundboard/soundboard.js index 39aaaef..8375dc9 100644 --- a/commands/soundboard/soundboard.js +++ b/commands/soundboard/soundboard.js @@ -6,7 +6,10 @@ import { sounds, info } from "../../utils/collections.js"; class SoundboardAIOCommand extends Command { async run() { const soundName = this.type === "classic" ? this.args[0] : this.optionsArray[0].name; - if (!sounds.has(soundName)) return "You need to provide a sound to play!"; + if (!sounds.has(soundName)) { + this.success = false; + return "You need to provide a sound to play!"; + } const name = sounds.get(soundName); return await play(this.client, name, { channel: this.channel, member: this.member, type: this.type, interaction: this.interaction }); } diff --git a/commands/tags/tags.js b/commands/tags/tags.js index 737df88..18ea7fe 100644 --- a/commands/tags/tags.js +++ b/commands/tags/tags.js @@ -7,6 +7,7 @@ const blacklist = ["create", "add", "edit", "remove", "delete", "list", "random" class TagsCommand extends Command { // todo: attempt to not make this file the worst thing that human eyes have ever seen async run() { + this.success = false; if (!this.channel.guild) return "This command only works in servers!"; const cmd = this.type === "classic" ? (this.args[0] ?? "").toLowerCase() : this.optionsArray[0].name; if (!cmd || !cmd.trim()) return "You need to provide the name of the tag you want to view!"; @@ -18,6 +19,7 @@ class TagsCommand extends Command { const getResult = await database.getTag(this.channel.guild.id, tagName); if (getResult) return "This tag already exists!"; const result = await database.setTag(tagName, { content: this.type === "classic" ? this.args.slice(2).join(" ") : this.optionsArray[0].options[1].value, author: this.member.id }, this.channel.guild); + this.success = true; if (result) return result; return `The tag \`${tagName}\` has been added!`; } else if (cmd === "delete" || cmd === "remove") { @@ -27,6 +29,7 @@ class TagsCommand extends Command { const owners = process.env.OWNER.split(","); if (getResult.author !== this.author.id && !this.member.permissions.has("manageMessages") && !owners.includes(this.author.id)) return "You don't own this tag!"; await database.removeTag(tagName, this.channel.guild); + this.success = true; return `The tag \`${tagName}\` has been deleted!`; } else if (cmd === "edit") { if (!tagName || !tagName.trim()) return "You need to provide the name of the tag you want to edit!"; @@ -35,12 +38,14 @@ class TagsCommand extends Command { const owners = process.env.OWNER.split(","); if (getResult.author !== this.author.id && !this.member.permissions.has("manageMessages") && !owners.includes(this.author.id)) return "You don't own this tag!"; await database.editTag(tagName, { content: this.type === "classic" ? this.args.slice(2).join(" ") : this.optionsArray[0].options[1].value, author: this.member.id }, this.channel.guild); + this.success = true; return `The tag \`${tagName}\` has been edited!`; } else if (cmd === "own" || cmd === "owner") { if (!tagName || !tagName.trim()) return "You need to provide the name of the tag you want to check the owner of!"; const getResult = await database.getTag(this.channel.guild.id, tagName); if (!getResult) return "This tag doesn't exist!"; const user = await this.ipc.fetchUser(getResult.author); + this.success = true; if (!user) { try { const restUser = await this.client.getRESTUser(getResult.author); @@ -77,6 +82,7 @@ class TagsCommand extends Command { }); } if (embeds.length === 0) return "I couldn't find any tags!"; + this.success = true; return paginator(this.client, { type: this.type, message: this.message, interaction: this.interaction, channel: this.channel, author: this.author }, embeds); } else { let getResult; @@ -87,6 +93,7 @@ class TagsCommand extends Command { getResult = await database.getTag(this.channel.guild.id, this.type === "classic" ? cmd : tagName); } if (!getResult) return "This tag doesn't exist!"; + this.success = true; if (getResult.content.length > 2000) { return { embeds: [{ diff --git a/events/interactionCreate.js b/events/interactionCreate.js index f80f2cf..67e6888 100644 --- a/events/interactionCreate.js +++ b/events/interactionCreate.js @@ -1,31 +1,40 @@ import database from "../utils/database.js"; import * as logger from "../utils/logger.js"; -import { commands } from "../utils/collections.js"; -import { CommandInteraction } from "eris"; +import { commands, messageCommands } from "../utils/collections.js"; import { clean } from "../utils/misc.js"; import { upload } from "../utils/tempimages.js"; // run when a slash command is executed export default async (client, cluster, worker, ipc, interaction) => { - if (!(interaction instanceof CommandInteraction)) return; + if (interaction?.type !== 2) return; // check if command exists and if it's enabled const command = interaction.data.name; - const cmd = commands.get(command); - if (!cmd) return; + let cmd = commands.get(command); + if (!cmd) { + cmd = messageCommands.get(command); + if (!cmd) return; + } const invoker = interaction.member ?? interaction.user; // actually run the command - logger.log("log", `${invoker.username} (${invoker.id}) ran slash command ${command}`); + logger.log("log", `${invoker.username} (${invoker.id}) ran application command ${command}`); try { await database.addCount(command); // eslint-disable-next-line no-unused-vars const commandClass = new cmd(client, cluster, worker, ipc, { type: "application", interaction }); const result = await commandClass.run(); const replyMethod = interaction.acknowledged ? "editOriginalMessage" : "createMessage"; - if (typeof result === "string" || (typeof result === "object" && result.embeds)) { - await interaction[replyMethod](result); + if (typeof result === "string") { + await interaction[replyMethod]({ + content: result, + flags: commandClass.success ? 0 : 64 + }); + } else if (typeof result === "object" && result.embeds) { + await interaction[replyMethod](Object.assign(result, { + flags: result.flags ?? (commandClass.success ? 0 : 64) + })); } else if (typeof result === "object" && result.file) { let fileSize = 8388119; if (interaction.channel.guild) { @@ -42,7 +51,10 @@ export default async (client, cluster, worker, ipc, interaction) => { if (process.env.TEMPDIR && process.env.TEMPDIR !== "") { await upload(client, ipc, result, interaction, true); } else { - await interaction[replyMethod]("The resulting image was more than 8MB in size, so I can't upload it."); + await interaction[replyMethod]({ + content: "The resulting image was more than 8MB in size, so I can't upload it.", + flags: 64 + }); } } else { await interaction[replyMethod](result.text ? result.text : {}, result); @@ -51,13 +63,13 @@ export default async (client, cluster, worker, ipc, interaction) => { } catch (error) { const replyMethod = interaction.acknowledged ? "editOriginalMessage" : "createMessage"; if (error.toString().includes("Request entity too large")) { - await interaction[replyMethod]("The resulting file was too large to upload. Try again with a smaller image if possible."); + await interaction[replyMethod]({ content: "The resulting file was too large to upload. Try again with a smaller image if possible.", flags: 64 }); } else if (error.toString().includes("Job ended prematurely")) { - await interaction[replyMethod]("Something happened to the image servers before I could receive the image. Try running your command again."); + await interaction[replyMethod]({ content: "Something happened to the image servers before I could receive the image. Try running your command again.", flags: 64 }); } else if (error.toString().includes("Timed out")) { - await interaction[replyMethod]("The request timed out before I could download that image. Try uploading your image somewhere else or reducing its size."); + await interaction[replyMethod]({ content: "The request timed out before I could download that image. Try uploading your image somewhere else or reducing its size.", flags: 64 }); } else { - logger.error(`Error occurred with slash command ${command} with arguments ${JSON.stringify(interaction.data.options)}: ${error.stack || error}`); + logger.error(`Error occurred with application command ${command} with arguments ${JSON.stringify(interaction.data.options)}: ${error.stack || error}`); try { await interaction[replyMethod]("Uh oh! I ran into an error while running this command. Please report the content of the attached file at the following link or on the esmBot Support server: ", { file: `Message: ${await clean(error)}\n\nStack Trace: ${await clean(error.stack)}`, diff --git a/package.json b/package.json index da7f330..b512d79 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "dependencies": { "@top-gg/sdk": "^3.1.3", "cmake-js": "^6.3.2", - "dotenv": "^16.0.1", + "dotenv": "^16.0.2", "emoji-regex": "^10.1.0", "eris": "github:esmBot/eris#dev", "eris-fleet": "github:esmBot/eris-fleet#dev", @@ -37,23 +37,23 @@ "qrcode": "^1.5.1", "sharp": "^0.30.7", "shoukaku": "github:Deivu/shoukaku", - "undici": "^5.8.2", + "undici": "^5.10.0", "winston": "^3.8.1", "winston-daily-rotate-file": "^4.7.1" }, "devDependencies": { - "@babel/core": "^7.18.10", + "@babel/core": "^7.18.13", "@babel/eslint-parser": "^7.18.9", "@babel/eslint-plugin": "^7.18.10", "@babel/plugin-proposal-class-properties": "^7.18.6", - "eslint": "^8.21.0", + "eslint": "^8.23.0", "eslint-plugin-unicorn": "^42.0.0" }, "optionalDependencies": { "better-sqlite3": "^7.6.2", "bufferutil": "^4.0.6", "erlpack": "github:abalabahaha/erlpack", - "pg": "^8.7.3", + "pg": "^8.8.0", "uuid": "^8.3.2", "ws": "^8.8.1", "zlib-sync": "^0.1.7" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b195b65..096593d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,7 +1,7 @@ lockfileVersion: 5.4 specifiers: - '@babel/core': ^7.18.10 + '@babel/core': ^7.18.13 '@babel/eslint-parser': ^7.18.9 '@babel/eslint-plugin': ^7.18.10 '@babel/plugin-proposal-class-properties': ^7.18.6 @@ -9,23 +9,23 @@ specifiers: better-sqlite3: ^7.6.2 bufferutil: ^4.0.6 cmake-js: ^6.3.2 - dotenv: ^16.0.1 + dotenv: ^16.0.2 emoji-regex: ^10.1.0 eris: github:esmBot/eris#dev eris-fleet: github:esmBot/eris-fleet#dev erlpack: github:abalabahaha/erlpack - eslint: ^8.21.0 + eslint: ^8.23.0 eslint-plugin-unicorn: ^42.0.0 file-type: ^17.1.6 format-duration: ^2.0.0 jsqr: ^1.4.0 node-addon-api: ^5.0.0 node-emoji: ^1.11.0 - pg: ^8.7.3 + pg: ^8.8.0 qrcode: ^1.5.1 sharp: ^0.30.7 shoukaku: github:Deivu/shoukaku - undici: ^5.8.2 + undici: ^5.10.0 uuid: ^8.3.2 winston: ^3.8.1 winston-daily-rotate-file: ^4.7.1 @@ -35,10 +35,10 @@ specifiers: dependencies: '@top-gg/sdk': 3.1.3 cmake-js: 6.3.2 - dotenv: 16.0.1 + dotenv: 16.0.2 emoji-regex: 10.1.0 - eris: github.com/esmBot/eris/a1a919a19af8e73443b826ea587116db93bcc7a7_bufferutil@4.0.6 - eris-fleet: github.com/esmBot/eris-fleet/5eac4f4d7e99603fc59ed6d28b834279d95948d3_eris@0.17.2-dev + eris: github.com/esmBot/eris/fbc637e7f92963d7f9e57c86223e995269e70de0_bufferutil@4.0.6 + eris-fleet: github.com/esmBot/eris-fleet/a19920fa0b2723e6afb6a9d31375b419a8743e82_eris@0.17.2-dev file-type: 17.1.6 format-duration: 2.0.0 jsqr: 1.4.0 @@ -47,7 +47,7 @@ dependencies: qrcode: 1.5.1 sharp: 0.30.7 shoukaku: github.com/Deivu/shoukaku/b6c724bf6e72a5dcf14beb6f51d35bc4b6a17647_bufferutil@4.0.6 - undici: 5.8.2 + undici: 5.10.0 winston: 3.8.1 winston-daily-rotate-file: 4.7.1_winston@3.8.1 @@ -55,18 +55,18 @@ optionalDependencies: better-sqlite3: 7.6.2 bufferutil: 4.0.6 erlpack: github.com/abalabahaha/erlpack/f7d730debe32c416d1b55b4217f8aef2ade05874 - pg: 8.7.3 + pg: 8.8.0 uuid: 8.3.2 ws: 8.8.1_bufferutil@4.0.6 zlib-sync: 0.1.7 devDependencies: - '@babel/core': 7.18.10 - '@babel/eslint-parser': 7.18.9_xqt7ek4fk233nrovqiamjvck4u - '@babel/eslint-plugin': 7.18.10_nydfxhofap6opqwg3seb7aoezu - '@babel/plugin-proposal-class-properties': 7.18.6_@babel+core@7.18.10 - eslint: 8.21.0 - eslint-plugin-unicorn: 42.0.0_eslint@8.21.0 + '@babel/core': 7.18.13 + '@babel/eslint-parser': 7.18.9_f6qngz4m6vfa3g3bk2x4qa2a2q + '@babel/eslint-plugin': 7.18.10_4q6j6uxclgkhf7c4z5hym4nj7a + '@babel/plugin-proposal-class-properties': 7.18.6_@babel+core@7.18.13 + eslint: 8.23.0 + eslint-plugin-unicorn: 42.0.0_eslint@8.23.0 packages: @@ -75,7 +75,7 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/gen-mapping': 0.1.1 - '@jridgewell/trace-mapping': 0.3.14 + '@jridgewell/trace-mapping': 0.3.15 dev: true /@babel/code-frame/7.18.6: @@ -85,25 +85,25 @@ packages: '@babel/highlight': 7.18.6 dev: true - /@babel/compat-data/7.18.8: - resolution: {integrity: sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==} + /@babel/compat-data/7.18.13: + resolution: {integrity: sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.18.10: - resolution: {integrity: sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==} + /@babel/core/7.18.13: + resolution: {integrity: sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.18.6 - '@babel/generator': 7.18.12 - '@babel/helper-compilation-targets': 7.18.9_@babel+core@7.18.10 + '@babel/generator': 7.18.13 + '@babel/helper-compilation-targets': 7.18.9_@babel+core@7.18.13 '@babel/helper-module-transforms': 7.18.9 '@babel/helpers': 7.18.9 - '@babel/parser': 7.18.11 + '@babel/parser': 7.18.13 '@babel/template': 7.18.10 - '@babel/traverse': 7.18.11 - '@babel/types': 7.18.10 + '@babel/traverse': 7.18.13 + '@babel/types': 7.18.13 convert-source-map: 1.8.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -113,37 +113,37 @@ packages: - supports-color dev: true - /@babel/eslint-parser/7.18.9_xqt7ek4fk233nrovqiamjvck4u: + /@babel/eslint-parser/7.18.9_f6qngz4m6vfa3g3bk2x4qa2a2q: resolution: {integrity: sha512-KzSGpMBggz4fKbRbWLNyPVTuQr6cmCcBhOyXTw/fieOVaw5oYAwcAj4a7UKcDYCPxQq+CG1NCDZH9e2JTXquiQ==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: '@babel/core': '>=7.11.0' eslint: ^7.5.0 || ^8.0.0 dependencies: - '@babel/core': 7.18.10 - eslint: 8.21.0 + '@babel/core': 7.18.13 + eslint: 8.23.0 eslint-scope: 5.1.1 eslint-visitor-keys: 2.1.0 semver: 6.3.0 dev: true - /@babel/eslint-plugin/7.18.10_nydfxhofap6opqwg3seb7aoezu: + /@babel/eslint-plugin/7.18.10_4q6j6uxclgkhf7c4z5hym4nj7a: resolution: {integrity: sha512-iV1OZj/7eg4wZIcsVEkXS3MUWdhmpLsu2h+9Zr2ppywKWdCRs6VfjxbRzmHHYeurTizrrnaJ9ZkbO8KOv4lauQ==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: '@babel/eslint-parser': '>=7.11.0' eslint: '>=7.5.0' dependencies: - '@babel/eslint-parser': 7.18.9_xqt7ek4fk233nrovqiamjvck4u - eslint: 8.21.0 + '@babel/eslint-parser': 7.18.9_f6qngz4m6vfa3g3bk2x4qa2a2q + eslint: 8.23.0 eslint-rule-composer: 0.3.0 dev: true - /@babel/generator/7.18.12: - resolution: {integrity: sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==} + /@babel/generator/7.18.13: + resolution: {integrity: sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 dev: true @@ -152,29 +152,29 @@ packages: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 dev: true - /@babel/helper-compilation-targets/7.18.9_@babel+core@7.18.10: + /@babel/helper-compilation-targets/7.18.9_@babel+core@7.18.13: resolution: {integrity: sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.18.8 - '@babel/core': 7.18.10 + '@babel/compat-data': 7.18.13 + '@babel/core': 7.18.13 '@babel/helper-validator-option': 7.18.6 browserslist: 4.21.3 semver: 6.3.0 dev: true - /@babel/helper-create-class-features-plugin/7.18.9_@babel+core@7.18.10: - resolution: {integrity: sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==} + /@babel/helper-create-class-features-plugin/7.18.13_@babel+core@7.18.13: + resolution: {integrity: sha512-hDvXp+QYxSRL+23mpAlSGxHMDyIGChm0/AwTfTAAK5Ufe40nCsyNdaYCGuK91phn/fVu9kqayImRDkvNAgdrsA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.18.10 + '@babel/core': 7.18.13 '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.18.9 @@ -196,28 +196,28 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.18.10 - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 dev: true /@babel/helper-hoist-variables/7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 dev: true /@babel/helper-member-expression-to-functions/7.18.9: resolution: {integrity: sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 dev: true /@babel/helper-module-imports/7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 dev: true /@babel/helper-module-transforms/7.18.9: @@ -230,8 +230,8 @@ packages: '@babel/helper-split-export-declaration': 7.18.6 '@babel/helper-validator-identifier': 7.18.6 '@babel/template': 7.18.10 - '@babel/traverse': 7.18.11 - '@babel/types': 7.18.10 + '@babel/traverse': 7.18.13 + '@babel/types': 7.18.13 transitivePeerDependencies: - supports-color dev: true @@ -240,7 +240,7 @@ packages: resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 dev: true /@babel/helper-plugin-utils/7.18.9: @@ -255,8 +255,8 @@ packages: '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-member-expression-to-functions': 7.18.9 '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/traverse': 7.18.11 - '@babel/types': 7.18.10 + '@babel/traverse': 7.18.13 + '@babel/types': 7.18.13 transitivePeerDependencies: - supports-color dev: true @@ -265,14 +265,14 @@ packages: resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 dev: true /@babel/helper-split-export-declaration/7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 dev: true /@babel/helper-string-parser/7.18.10: @@ -295,8 +295,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.18.10 - '@babel/traverse': 7.18.11 - '@babel/types': 7.18.10 + '@babel/traverse': 7.18.13 + '@babel/types': 7.18.13 transitivePeerDependencies: - supports-color dev: true @@ -310,22 +310,22 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser/7.18.11: - resolution: {integrity: sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==} + /@babel/parser/7.18.13: + resolution: {integrity: sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.18.10 + '@babel/types': 7.18.13 dev: true - /@babel/plugin-proposal-class-properties/7.18.6_@babel+core@7.18.10: + /@babel/plugin-proposal-class-properties/7.18.6_@babel+core@7.18.13: resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.18.10 - '@babel/helper-create-class-features-plugin': 7.18.9_@babel+core@7.18.10 + '@babel/core': 7.18.13 + '@babel/helper-create-class-features-plugin': 7.18.13_@babel+core@7.18.13 '@babel/helper-plugin-utils': 7.18.9 transitivePeerDependencies: - supports-color @@ -336,30 +336,30 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.18.11 - '@babel/types': 7.18.10 + '@babel/parser': 7.18.13 + '@babel/types': 7.18.13 dev: true - /@babel/traverse/7.18.11: - resolution: {integrity: sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==} + /@babel/traverse/7.18.13: + resolution: {integrity: sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/generator': 7.18.12 + '@babel/generator': 7.18.13 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.18.9 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.18.11 - '@babel/types': 7.18.10 + '@babel/parser': 7.18.13 + '@babel/types': 7.18.13 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types/7.18.10: - resolution: {integrity: sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==} + /@babel/types/7.18.13: + resolution: {integrity: sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.18.10 @@ -380,13 +380,13 @@ packages: kuler: 2.0.0 dev: false - /@eslint/eslintrc/1.3.0: - resolution: {integrity: sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==} + /@eslint/eslintrc/1.3.1: + resolution: {integrity: sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4 - espree: 9.3.3 + espree: 9.4.0 globals: 13.17.0 ignore: 5.2.0 import-fresh: 3.3.0 @@ -412,6 +412,11 @@ packages: resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} dev: true + /@humanwhocodes/module-importer/1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + /@humanwhocodes/object-schema/1.2.1: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true @@ -430,7 +435,7 @@ packages: dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.14 + '@jridgewell/trace-mapping': 0.3.15 dev: true /@jridgewell/resolve-uri/3.1.0: @@ -447,8 +452,8 @@ packages: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} dev: true - /@jridgewell/trace-mapping/0.3.14: - resolution: {integrity: sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==} + /@jridgewell/trace-mapping/0.3.15: + resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 @@ -638,8 +643,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001375 - electron-to-chromium: 1.4.215 + caniuse-lite: 1.0.30001387 + electron-to-chromium: 1.4.237 node-releases: 2.0.6 update-browserslist-db: 1.0.5_browserslist@4.21.3 dev: true @@ -704,8 +709,8 @@ packages: engines: {node: '>=6'} dev: false - /caniuse-lite/1.0.30001375: - resolution: {integrity: sha512-kWIMkNzLYxSvnjy0hL8w1NOaWNr2rn39RTAVyIwcw8juu60bZDWiF1/loOYANzjtJmy6qPgNmn38ro5Pygagdw==} + /caniuse-lite/1.0.30001387: + resolution: {integrity: sha512-fKDH0F1KOJvR+mWSOvhj8lVRr/Q/mc5u5nabU2vi1/sgvlSqEsE8dOq0Hy/BqVbDkCYQPRRHB1WRjW6PGB/7PA==} dev: true /chainsaw/0.1.0: @@ -924,8 +929,8 @@ packages: esutils: 2.0.3 dev: true - /dotenv/16.0.1: - resolution: {integrity: sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==} + /dotenv/16.0.2: + resolution: {integrity: sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==} engines: {node: '>=12'} dev: false @@ -935,8 +940,8 @@ packages: readable-stream: 2.1.5 dev: false - /electron-to-chromium/1.4.215: - resolution: {integrity: sha512-vqZxT8C5mlDZ//hQFhneHmOLnj1LhbzxV0+I1yqHV8SB1Oo4Y5Ne9+qQhwHl7O1s9s9cRuo2l5CoLEHdhMTwZg==} + /electron-to-chromium/1.4.237: + resolution: {integrity: sha512-vxVyGJcsgArNOVUJcXm+7iY3PJAfmSapEszQD1HbyPLl0qoCmNQ1o/EX3RI7Et5/88In9oLxX3SGF8J3orkUgA==} dev: true /emoji-regex/10.1.0: @@ -982,7 +987,7 @@ packages: engines: {node: '>=10'} dev: true - /eslint-plugin-unicorn/42.0.0_eslint@8.21.0: + /eslint-plugin-unicorn/42.0.0_eslint@8.23.0: resolution: {integrity: sha512-ixBsbhgWuxVaNlPTT8AyfJMlhyC5flCJFjyK3oKE8TRrwBnaHvUbuIkCM1lqg8ryYrFStL/T557zfKzX4GKSlg==} engines: {node: '>=12'} peerDependencies: @@ -991,8 +996,8 @@ packages: '@babel/helper-validator-identifier': 7.18.6 ci-info: 3.3.2 clean-regexp: 1.0.0 - eslint: 8.21.0 - eslint-utils: 3.0.0_eslint@8.21.0 + eslint: 8.23.0 + eslint-utils: 3.0.0_eslint@8.23.0 esquery: 1.4.0 indent-string: 4.0.0 is-builtin-module: 3.2.0 @@ -1026,13 +1031,13 @@ packages: estraverse: 5.3.0 dev: true - /eslint-utils/3.0.0_eslint@8.21.0: + /eslint-utils/3.0.0_eslint@8.23.0: resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.21.0 + eslint: 8.23.0 eslint-visitor-keys: 2.1.0 dev: true @@ -1046,14 +1051,15 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint/8.21.0: - resolution: {integrity: sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==} + /eslint/8.23.0: + resolution: {integrity: sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.3.0 + '@eslint/eslintrc': 1.3.1 '@humanwhocodes/config-array': 0.10.4 '@humanwhocodes/gitignore-to-minimatch': 1.0.2 + '@humanwhocodes/module-importer': 1.0.1 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 @@ -1061,9 +1067,9 @@ packages: doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.1.1 - eslint-utils: 3.0.0_eslint@8.21.0 + eslint-utils: 3.0.0_eslint@8.23.0 eslint-visitor-keys: 3.3.0 - espree: 9.3.3 + espree: 9.4.0 esquery: 1.4.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -1089,13 +1095,12 @@ packages: strip-ansi: 6.0.1 strip-json-comments: 3.1.1 text-table: 0.2.0 - v8-compile-cache: 2.3.0 transitivePeerDependencies: - supports-color dev: true - /espree/9.3.3: - resolution: {integrity: sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==} + /espree/9.4.0: + resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: acorn: 8.8.0 @@ -1223,12 +1228,12 @@ packages: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flatted: 3.2.6 + flatted: 3.2.7 rimraf: 3.0.2 dev: true - /flatted/3.2.6: - resolution: {integrity: sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==} + /flatted/3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true /fn.name/1.1.0: @@ -1822,12 +1827,6 @@ packages: word-wrap: 1.2.3 dev: true - /opusscript/0.0.8: - resolution: {integrity: sha512-VSTi1aWFuCkRCVq+tx/BQ5q9fMnQ9pVZ3JU4UHKqTkf0ED3fKEPdr+gKAAl3IA2hj9rrP6iyq3hlcJq3HELtNQ==} - requiresBuild: true - dev: false - optional: true - /os-locale/1.4.0: resolution: {integrity: sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==} engines: {node: '>=0.10.0'} @@ -1925,12 +1924,12 @@ packages: dev: false optional: true - /pg-pool/3.5.1_pg@8.7.3: - resolution: {integrity: sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==} + /pg-pool/3.5.2_pg@8.8.0: + resolution: {integrity: sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==} peerDependencies: pg: '>=8.0' dependencies: - pg: 8.7.3 + pg: 8.8.0 dev: false optional: true @@ -1951,12 +1950,12 @@ packages: dev: false optional: true - /pg/8.7.3: - resolution: {integrity: sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==} + /pg/8.8.0: + resolution: {integrity: sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==} engines: {node: '>= 8.0.0'} requiresBuild: true peerDependencies: - pg-native: '>=2.0.0' + pg-native: '>=3.0.1' peerDependenciesMeta: pg-native: optional: true @@ -1964,7 +1963,7 @@ packages: buffer-writer: 2.0.0 packet-reader: 1.0.0 pg-connection-string: 2.5.0 - pg-pool: 3.5.1_pg@8.7.3 + pg-pool: 3.5.2_pg@8.8.0 pg-protocol: 1.5.0 pg-types: 2.2.0 pgpass: 1.0.5 @@ -2332,7 +2331,7 @@ packages: resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.11 + spdx-license-ids: 3.0.12 dev: true /spdx-exceptions/2.3.0: @@ -2343,11 +2342,11 @@ packages: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.11 + spdx-license-ids: 3.0.12 dev: true - /spdx-license-ids/3.0.11: - resolution: {integrity: sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==} + /spdx-license-ids/3.0.12: + resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} dev: true /split2/4.1.0: @@ -2544,12 +2543,6 @@ packages: safe-buffer: 5.2.1 dev: false - /tweetnacl/1.0.3: - resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} - requiresBuild: true - dev: false - optional: true - /type-check/0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -2572,8 +2565,8 @@ packages: engines: {node: '>=8'} dev: true - /undici/5.8.2: - resolution: {integrity: sha512-3KLq3pXMS0Y4IELV045fTxqz04Nk9Ms7yfBBHum3yxsTR4XNn+ZCaUbf/mWitgYDAhsplQ0B1G4S5D345lMO3A==} + /undici/5.10.0: + resolution: {integrity: sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==} engines: {node: '>=12.18'} dev: false @@ -2583,7 +2576,7 @@ packages: dev: false /unpipe/1.0.0: - resolution: {integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=} + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} dev: false @@ -2633,10 +2626,6 @@ packages: dev: false optional: true - /v8-compile-cache/2.3.0: - resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} - dev: true - /validate-npm-package-license/3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -2838,7 +2827,7 @@ packages: prepare: true requiresBuild: true dependencies: - undici: 5.8.2 + undici: 5.10.0 ws: 8.8.1_bufferutil@4.0.6 transitivePeerDependencies: - bufferutil @@ -2856,28 +2845,25 @@ packages: dev: false optional: true - github.com/esmBot/eris-fleet/5eac4f4d7e99603fc59ed6d28b834279d95948d3_eris@0.17.2-dev: - resolution: {tarball: https://codeload.github.com/esmBot/eris-fleet/tar.gz/5eac4f4d7e99603fc59ed6d28b834279d95948d3} - id: github.com/esmBot/eris-fleet/5eac4f4d7e99603fc59ed6d28b834279d95948d3 + github.com/esmBot/eris-fleet/a19920fa0b2723e6afb6a9d31375b419a8743e82_eris@0.17.2-dev: + resolution: {tarball: https://codeload.github.com/esmBot/eris-fleet/tar.gz/a19920fa0b2723e6afb6a9d31375b419a8743e82} + id: github.com/esmBot/eris-fleet/a19920fa0b2723e6afb6a9d31375b419a8743e82 name: eris-fleet version: 1.0.2 peerDependencies: eris: ~0.16.0 dependencies: - eris: github.com/esmBot/eris/a1a919a19af8e73443b826ea587116db93bcc7a7_bufferutil@4.0.6 + eris: github.com/esmBot/eris/fbc637e7f92963d7f9e57c86223e995269e70de0_bufferutil@4.0.6 dev: false - github.com/esmBot/eris/a1a919a19af8e73443b826ea587116db93bcc7a7_bufferutil@4.0.6: - resolution: {tarball: https://codeload.github.com/esmBot/eris/tar.gz/a1a919a19af8e73443b826ea587116db93bcc7a7} - id: github.com/esmBot/eris/a1a919a19af8e73443b826ea587116db93bcc7a7 + github.com/esmBot/eris/fbc637e7f92963d7f9e57c86223e995269e70de0_bufferutil@4.0.6: + resolution: {tarball: https://codeload.github.com/esmBot/eris/tar.gz/fbc637e7f92963d7f9e57c86223e995269e70de0} + id: github.com/esmBot/eris/fbc637e7f92963d7f9e57c86223e995269e70de0 name: eris version: 0.17.2-dev engines: {node: '>=10.4.0'} dependencies: ws: 8.8.1_bufferutil@4.0.6 - optionalDependencies: - opusscript: 0.0.8 - tweetnacl: 1.0.3 transitivePeerDependencies: - bufferutil - utf-8-validate diff --git a/shard.js b/shard.js index ebeb3e0..f28510f 100644 --- a/shard.js +++ b/shard.js @@ -55,8 +55,9 @@ class Shard extends BaseClusterWorker { const commandArray = await update(this.bot, this.clusterID, this.workerID, this.ipc, soundStatus); try { await this.bot.bulkEditCommands(commandArray); - } catch { - log("error", "Failed to send command data to Discord, slash commands may be unavailable."); + } catch (e) { + log("error", e); + log("error", "Failed to send command data to Discord, slash/message commands may be unavailable."); } } log("info", "Finished loading commands."); @@ -127,6 +128,14 @@ class Shard extends BaseClusterWorker { // connect to lavalink if (!status && !connected) connect(this.bot); + const broadcastMessage = await this.ipc.centralStore.get("broadcast"); + if (broadcastMessage) { + broadcast = true; + this.bot.editStatus("dnd", { + name: `${broadcastMessage} | @${this.bot.user.username} help`, + }); + } + this.activityChanger(); log("info", `Started worker ${this.workerID}.`); diff --git a/utils/collections.js b/utils/collections.js index ced45a3..98e64d9 100644 --- a/utils/collections.js +++ b/utils/collections.js @@ -1,4 +1,5 @@ export const commands = new Map(); +export const messageCommands = new Map(); export const paths = new Map(); export const aliases = new Map(); export const info = new Map(); @@ -6,15 +7,20 @@ export const sounds = new Map(); export const categories = new Map(); class TimedMap extends Map { + constructor(time, values) { + super(values); + this.time = time; + } set(key, value) { super.set(key, value); setTimeout(() => { if (super.has(key)) super.delete(key); - }, 5000); + }, this.time); } } -export const runningCommands = new TimedMap(); +export const runningCommands = new TimedMap(5000); +export const selectedImages = new TimedMap(180000); class Cache extends Map { constructor(values) { diff --git a/utils/handler.js b/utils/handler.js index 89ceffb..d78fdcc 100644 --- a/utils/handler.js +++ b/utils/handler.js @@ -1,4 +1,4 @@ -import { paths, commands, info, sounds, categories, aliases as _aliases } from "./collections.js"; +import { paths, commands, messageCommands, info, sounds, categories, aliases as _aliases } from "./collections.js"; import { log } from "./logger.js"; import { readFileSync } from "fs"; @@ -16,46 +16,62 @@ export async function load(client, cluster, worker, ipc, command, soundStatus, s return; } const commandArray = command.split("/"); - const commandName = commandArray[commandArray.length - 1].split(".")[0]; + let commandName = commandArray[commandArray.length - 1].split(".")[0]; + const category = commandArray[commandArray.length - 2]; if (blacklist.includes(commandName)) { log("warn", `Skipped loading blacklisted command ${command}...`); return; } + if (category === "message") { + const nameStringArray = commandName.split("-"); + for (const index of nameStringArray.keys()) { + nameStringArray[index] = nameStringArray[index].charAt(0).toUpperCase() + nameStringArray[index].slice(1); + } + commandName = nameStringArray.join(" "); + } + props.init(); - paths.set(commandName, command); - commands.set(commandName, props); - if (Object.getPrototypeOf(props).name === "SoundboardCommand") sounds.set(commandName, props.file); - - const category = commandArray[commandArray.length - 2]; - info.set(commandName, { + const commandInfo = { category: category, description: props.description, aliases: props.aliases, params: props.arguments, flags: props.flags, slashAllowed: props.slashAllowed, - directAllowed: props.directAllowed - }); + directAllowed: props.directAllowed, + type: 1 + }; + + if (category === "message") { + messageCommands.set(commandName, props); + commandInfo.type = 3; + } else { + commands.set(commandName, props); + + if (slashReload && props.slashAllowed) { + const commandList = await client.getCommands(); + const oldCommand = commandList.filter((item) => { + return item.name === commandName; + })[0]; + await client.editCommand(oldCommand.id, { + name: commandName, + type: 1, + description: props.description, + options: props.flags + }); + } + } + + if (Object.getPrototypeOf(props).name === "SoundboardCommand") sounds.set(commandName, props.file); + + info.set(commandName, commandInfo); const categoryCommands = categories.get(category); categories.set(category, categoryCommands ? [...categoryCommands, commandName] : [commandName]); - - if (slashReload && props.slashAllowed) { - const commandList = await client.getCommands(); - const oldCommand = commandList.filter((item) => { - return item.name === commandName; - })[0]; - await client.editCommand(oldCommand.id, { - name: commandName, - type: 1, - description: props.description, - options: props.flags - }); - } if (props.aliases) { for (const alias of props.aliases) { @@ -68,11 +84,11 @@ export async function load(client, cluster, worker, ipc, command, soundStatus, s export async function update() { const commandArray = []; - for (const [name, command] of commands.entries()) { + const merged = new Map([...commands, ...messageCommands]); + for (const [name, command] of merged.entries()) { let cmdInfo = info.get(name); if (command.postInit) { const cmd = command.postInit(); - //commands.set(name, cmd); cmdInfo = { category: cmdInfo.category, description: cmd.description, @@ -80,17 +96,26 @@ export async function update() { params: cmd.arguments, flags: cmd.flags, slashAllowed: cmd.slashAllowed, - directAllowed: cmd.directAllowed + directAllowed: cmd.directAllowed, + type: cmdInfo.type }; info.set(name, cmdInfo); } - if (cmdInfo?.slashAllowed) commandArray.push({ - name, - type: 1, - description: cmdInfo.description, - options: cmdInfo.flags, - dm_permission: cmdInfo.directAllowed - }); + if (cmdInfo?.type === 3) { + commandArray.push({ + name: name, + type: cmdInfo.type, + dm_permission: cmdInfo.directAllowed + }); + } else if (cmdInfo?.slashAllowed) { + commandArray.push({ + name, + type: cmdInfo.type, + description: cmdInfo.description, + options: cmdInfo.flags, + dm_permission: cmdInfo.directAllowed + }); + } } return commandArray; } \ No newline at end of file diff --git a/utils/imagedetect.js b/utils/imagedetect.js index 15d87f9..ee92244 100644 --- a/utils/imagedetect.js +++ b/utils/imagedetect.js @@ -133,7 +133,7 @@ const checkImages = async (message, extraReturnTypes, video, sticker) => { }; // this checks for the latest message containing an image and returns the url of the image -export default async (client, cmdMessage, interaction, options, extraReturnTypes = false, video = false, sticker = false) => { +export default async (client, cmdMessage, interaction, options, extraReturnTypes = false, video = false, sticker = false, singleMessage = false) => { // we start by determining whether or not we're dealing with an interaction or a message if (interaction) { // we can get a raw attachment or a URL in the interaction itself @@ -147,7 +147,8 @@ export default async (client, cmdMessage, interaction, options, extraReturnTypes if (result !== false) return result; } } - } else { + } + if (cmdMessage) { // check if the message is a reply to another message if (cmdMessage.messageReference) { const replyMessage = await client.getMessage(cmdMessage.messageReference.channelID, cmdMessage.messageReference.messageID).catch(() => undefined); @@ -160,15 +161,17 @@ export default async (client, cmdMessage, interaction, options, extraReturnTypes const result = await checkImages(cmdMessage, extraReturnTypes, video, sticker); if (result !== false) return result; } - // if there aren't any replies or interaction attachments then iterate over the last few messages in the channel - const messages = await client.getMessages((interaction ? interaction : cmdMessage).channel.id); - // iterate over each message - for (const message of messages) { - const result = await checkImages(message, extraReturnTypes, video, sticker); - if (result === false) { - continue; - } else { - return result; + if (!singleMessage) { + // if there aren't any replies or interaction attachments then iterate over the last few messages in the channel + const messages = await client.getMessages((interaction ? interaction : cmdMessage).channel.id); + // iterate over each message + for (const message of messages) { + const result = await checkImages(message, extraReturnTypes, video, sticker); + if (result === false) { + continue; + } else { + return result; + } } } }; diff --git a/utils/soundplayer.js b/utils/soundplayer.js index f86bf21..d237495 100644 --- a/utils/soundplayer.js +++ b/utils/soundplayer.js @@ -60,13 +60,13 @@ export function reload() { } export async function play(client, sound, options, music = false) { - if (!manager) return "The sound commands are still starting up!"; - if (!options.channel.guild) return "This command only works in servers!"; - if (!options.member.voiceState.channelID) return "You need to be in a voice channel first!"; - if (!options.channel.guild.permissionsOf(client.user.id).has("voiceConnect")) return "I can't join this voice channel!"; + if (!manager) return { content: "The sound commands are still starting up!", flags: 64 }; + if (!options.channel.guild) return { content: "This command only works in servers!", flags: 64 }; + if (!options.member.voiceState.channelID) return { content: "You need to be in a voice channel first!", flags: 64 }; + if (!options.channel.guild.permissionsOf(client.user.id).has("voiceConnect")) return { content: "I can't join this voice channel!", flags: 64 }; const voiceChannel = options.channel.guild.channels.get(options.member.voiceState.channelID); - if (!voiceChannel.permissionsOf(client.user.id).has("voiceConnect")) return "I don't have permission to join this voice channel!"; - if (!music && manager.players.has(options.channel.guild.id)) return "I can't play a sound effect while other audio is playing!"; + if (!voiceChannel.permissionsOf(client.user.id).has("voiceConnect")) return { content: "I don't have permission to join this voice channel!", flags: 64 }; + if (!music && manager.players.has(options.channel.guild.id)) return { content: "I can't play a sound effect while other audio is playing!", flags: 64 }; let node = manager.getNode(); if (!node) { const status = await checkStatus(); @@ -81,14 +81,14 @@ export async function play(client, sound, options, music = false) { let response; try { response = await node.rest.resolve(sound); - if (!response) return "🔊 I couldn't get a response from the audio server."; - if (response.loadType === "NO_MATCHES" || response.loadType === "LOAD_FAILED") return "I couldn't find that song!"; + if (!response) return { content: "🔊 I couldn't get a response from the audio server.", flags: 64 }; + if (response.loadType === "NO_MATCHES" || response.loadType === "LOAD_FAILED") return { content: "I couldn't find that song!", flags: 64 }; } catch (e) { logger.error(e); - return "🔊 Hmmm, seems that all of the audio servers are down. Try again in a bit."; + return { content: "🔊 Hmmm, seems that all of the audio servers are down. Try again in a bit.", flags: 64 }; } const oldQueue = queues.get(voiceChannel.guild.id); - if (!response.tracks || response.tracks.length === 0) return "I couldn't find that song!"; + if (!response.tracks || response.tracks.length === 0) return { content: "I couldn't find that song!", flags: 64 }; if (music) { const sortedTracks = response.tracks.map((val) => { return val.track; }); const playlistTracks = response.playlistInfo.selectedTrack ? sortedTracks : [sortedTracks[0]];