Skip to content
This repository was archived by the owner on Apr 17, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c12dbff
chore(deps): regenerate lockfile
Nov 18, 2021
67dc993
fix(PlayCommand): remove `select` params
Nov 18, 2021
50c5a87
chore(config): remove `databaseCacheLifetime`
Nov 18, 2021
e9582bc
fix(MusicHandler): add return to `reset` function
Nov 18, 2021
e6dbd43
feat(SetupCommand): add `MANAGE_MESSAGE` to perms check
Nov 13, 2021
216cc5c
feat(SetupCommand): change to reaction
Nov 13, 2021
eb8ac5d
chore(config): add `GUILD_MESSAGE_REACTIONS` intent
Nov 13, 2021
298f436
chore(config): add player emojis
Nov 13, 2021
9ed4f00
feat(SetupCommand): import from config instead
Nov 13, 2021
c814764
feat(GuildSettingManager): check reaction cache on boot
Nov 13, 2021
68ad1f0
feat(InteractionCreateEvent): completely remove interaction player su…
Nov 18, 2021
458e2da
feat(Music): completely move to reaction
Nov 19, 2021
cf514c8
fix(SetupCommand): eslint error
Nov 19, 2021
6c5457d
fix(MessageReactionAddEvent): remove database `select`
Nov 19, 2021
c56f84a
feat(MusicHandler): make updateInterval undefined
Nov 22, 2021
5d4e0a6
feat(Music): better `updatePlayerEmbed` handling
Nov 22, 2021
50d9b6a
feat(NodeRawEvent): shouldn't update every emitted
Nov 22, 2021
efba904
feat(NodeRawEvent): debug when dev mode
Nov 22, 2021
b3fb91f
chore(config): remove `emojis`
Nov 22, 2021
97c03bf
feat(Music): back to interaction button
Nov 22, 2021
4b80eed
feat(Logger): Use pino (#132)
satoufuyuki Nov 22, 2021
44bf308
feat(Logger): remove shard thingy from old logger
Nov 22, 2021
2249b48
refactor(CommandContext): remove useless space
Nov 22, 2021
bf16a42
feat(Global): extend string prototype
Nov 22, 2021
c0c803f
feat(Music): escape the title
Nov 22, 2021
9358737
feat: import global extension
Nov 22, 2021
f55a470
feat(extension): use `BotClient#queue`
Nov 22, 2021
ee7b7d3
feat(*): Use `BotClient#queue` instead
Nov 22, 2021
2cf26e4
fix(Global): import should be in `bot.ts`
Nov 22, 2021
100146d
chore(Shard): use `DISCORD_TOKEN` from .env
Nov 22, 2021
64ae03e
chore(bot): access token from `DISCORD_TOKEN`
Nov 22, 2021
ff68926
fix(MusicHandler): don't delete queue
satoufuyuki Nov 23, 2021
d265777
chore(RemoveCommand): change usage
satoufuyuki Nov 28, 2021
2f0f66f
feat(EightDCommand): defer interaction
satoufuyuki Nov 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
570 changes: 567 additions & 3 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"start": "node dist/index.js",
"start:dev": "ts-node -r dotenv/config src/bot.ts"
"start:dev": "ts-node -r dotenv/config src/index.ts"
},
"main": "dist/index.js",
"dependencies": {
Expand All @@ -23,6 +23,8 @@
"erela.js-filter": "^0.2.3",
"got": "^11.8.2",
"mongodb": "^3.7.3",
"pino": "^7.3.0",
"pino-pretty": "^7.2.0",
"reflect-metadata": "^0.1.13",
"tslib": "^2.3.1",
"typeorm": "^0.2.40",
Expand Down
26 changes: 11 additions & 15 deletions src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import "./extension/Global";
import { BotClient } from "./structures/BotClient";
import { clientOptions } from "./config";
import { NoStackError } from "./utils/NoStackError";
import { CustomError } from "./utils/CustomError";

export const client = new BotClient(clientOptions);

process.on("exit", code => {
client.logger.info(`NodeJS process exited with code ${code}`);
});
process.on("uncaughtException", err => {
// Temporary fix for winston crash
if (err.message === "self._addDefaultMeta is not a function") {
return undefined;
process.on("unhandledRejection", e => {
if (e instanceof Error) {
client.logger.error(e);
} else {
client.logger.error(CustomError("PromiseError", e as string));
}
client.logger.error("UNCAUGHT_EXCEPTION:", err);
client.logger.warn("Uncaught Exception detected. Restarting...");
process.exit(1);
});
process.on("unhandledRejection", reason => {
client.logger.error("UNHANDLED_REJECTION:", (reason as Error).stack ? reason : new NoStackError(reason as string));
process.on("uncaughtException", e => {
client.logger.fatal(e);
process.exit(1);
});
process.on("warning", client.logger.warn);

client.build(process.env.DISCORD_TOKEN!)
.catch(e => client.logger.error("PROMISE_ERR:", e));
.catch(e => client.logger.error(e));
4 changes: 2 additions & 2 deletions src/commands/administrator/SetupCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ export class SetupCommand extends BaseCommand {
embeds: [createEmbed("error", `Already setup in ${old.toString()}`)]
});
}
if (!channel.permissionsFor(this.client.user!.id)?.has(["SEND_MESSAGES", "ATTACH_FILES"])) {
if (!channel.permissionsFor(this.client.user!.id)?.has(["SEND_MESSAGES", "ATTACH_FILES", "MANAGE_MESSAGES"])) {
return ctx.send({
embeds: [createEmbed("error", "I need these permissions to make requester channel: `SEND_MESSAGES`, `ATTACH_FILES`")]
embeds: [createEmbed("error", "I need these permissions to make requester channel: `SEND_MESSAGES`, `ATTACH_FILES`, `MANAGE_MESSAGES`")]
});
}
if (channel.isText()) {
Expand Down
5 changes: 3 additions & 2 deletions src/commands/developers/EvalCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { MessageEmbed } from "discord.js";
import { request } from "https";
import { DefineCommand } from "../../utils/decorators/DefineCommand";
import { CommandContext } from "../../structures/CommandContext";
import { CustomError } from "../../utils/CustomError";

@DefineCommand({
aliases: ["ev", "js-exec", "e", "evaluate"],
Expand Down Expand Up @@ -57,14 +58,14 @@ export class EvalCommand extends BaseCommand {
const hastebin = await this.hastebin(output);
embed.addField("Output", `${hastebin}.js`);
} else { embed.addField("Output", `\`\`\`js\n${output}\`\`\``); }
ctx.send({ embeds: [embed] }).catch(e => this.client.logger.error("PROMISE_ERR:", e));
ctx.send({ embeds: [embed] }).catch(e => this.client.logger.error(CustomError("PROMISE_ERR:", String(e))));
} catch (e) {
const error = this.clean(String(e));
if (error.length > 1024) {
const hastebin = await this.hastebin(error);
embed.addField("Error", `${hastebin}.js`);
} else { embed.setColor("#FF0000").addField("Error", `\`\`\`js\n${error}\`\`\``); }
ctx.send({ embeds: [embed] }).catch(e => this.client.logger.error("PROMISE_ERR:", e));
ctx.send({ embeds: [embed] }).catch(e => this.client.logger.error(CustomError("PROMISE_ERR:", String(e))));
}
}

Expand Down
1 change: 1 addition & 0 deletions src/commands/filters/EightDCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class EightDCommand extends BaseCommand {
@isMemberVoiceChannelJoinable()
@isSameVoiceChannel()
public async execute(ctx: CommandContext): Promise<any> {
if (ctx.isInteraction() && !ctx.deferred) await ctx.deferReply();
await ctx.guild!.music.player!.setEightD(!ctx.guild!.music.player!.filters.eightD);
const msg = await ctx.send({
embeds: [
Expand Down
15 changes: 9 additions & 6 deletions src/commands/music/PlayCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class PlayCommand extends BaseCommand {
embeds: [createEmbed("error", `This command is restricted to <#${ctx.guild!.music.playerChannel}>.`)]
});
}
const { max_queue: maxQueue, duplicate_song: duplicateSong } = await this.client.databases.guilds.get(ctx.guild!.id, { select: ["max_queue", "duplicate_song"] });
const { max_queue: maxQueue, duplicate_song: duplicateSong } = await this.client.databases.guilds.get(ctx.guild!.id);
if (maxQueue <= (ctx.guild!.music.player?.queue.totalSize || 0)) {
const msg = await ctx.send({
embeds: [
Expand Down Expand Up @@ -111,8 +111,11 @@ export class PlayCommand extends BaseCommand {
}
if (!ctx.guild!.music.player) await ctx.guild!.music.join(vc!.id, ctx.channel as TextChannel);
if (response.loadType === "PLAYLIST_LOADED") {
const duplicated = response.tracks.filter(x => ctx.guild!.music.player!.queue.find(y => y.identifier === x.identifier));
const toAdd = response.tracks.filter(x => duplicateSong && !ctx.guild!.music.player?.queue.find(y => y.identifier === x.identifier));
const duplicated = response.tracks.filter(x => ctx.guild!.music.player!.queue.some(y => y.identifier === x.identifier) || ctx.guild!.music.player!.queue.current?.identifier === x.identifier);
const toAdd = response.tracks.filter(x => {
if (duplicateSong) return !duplicated.some(y => y.identifier === x.identifier);
return true;
});
for (const trck of toAdd) await ctx.guild!.music.player!.queue.add(trck);
if (duplicateSong && duplicated.length) {
const duplicateMessage = await ctx.send({
Expand All @@ -138,7 +141,7 @@ export class PlayCommand extends BaseCommand {
if (duplicateSong && duplicated) {
const duplicateMessage = await ctx.send({
embeds: [
createEmbed("warn", `Track **[${duplicated.title}](${duplicated.uri!})** is already queued, and this server configuration disallow duplicated tracks in queue`)
createEmbed("warn", `Track **[${duplicated.title.escapeMarkdown()}](${duplicated.uri!})** is already queued, and this server configuration disallow duplicated tracks in queue`)
]
});
if (fromRequester) {
Expand All @@ -151,11 +154,11 @@ export class PlayCommand extends BaseCommand {
if (!ctx.additionalArgs.get("values") && (!ctx.additionalArgs.get("fromRequesterChannel"))) {
if (fromRequester && ctx.isInteraction()) {
await ctx.send({
embeds: [createEmbed("info", `✅ Track **[${response.tracks[0].title}](${response.tracks[0].uri})** has been added to the queue`).setThumbnail(response.tracks[0].thumbnail!)]
embeds: [createEmbed("info", `✅ Track **[${response.tracks[0].title.escapeMarkdown()}](${response.tracks[0].uri})** has been added to the queue`).setThumbnail(response.tracks[0].thumbnail!)]
});
} else if (!fromRequester) {
await ctx.send({
embeds: [createEmbed("info", `✅ Track **[${response.tracks[0].title}](${response.tracks[0].uri})** has been added to the queue`).setThumbnail(response.tracks[0].thumbnail!)]
embeds: [createEmbed("info", `✅ Track **[${response.tracks[0].title.escapeMarkdown()}](${response.tracks[0].uri})** has been added to the queue`).setThumbnail(response.tracks[0].thumbnail!)]
});
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/commands/music/QueueCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ export class QueueCommand extends BaseCommand {
if (ctx.isInteraction() && !ctx.deferred) await ctx.deferReply();
const { music } = ctx.guild!;
const queue = music.player?.queue ?? [];
const pages = chunk(queue.map((x, i) => `**${++i}.** **[${x.title}](${x.uri!})** <@${String(x.requester)}>`), 10).map(x => x.join("\n"));
const pages = chunk(queue.map((x, i) => `**${++i}.** **[${x.title.escapeMarkdown()}](${x.uri!})** <@${String(x.requester)}>`), 10).map(x => x.join("\n"));
const embed = createEmbed("info", pages[0] || "Empty, add some by using `play` command", false)
.setAuthor(`${ctx.guild!.name} Queue`, ctx.guild!.iconURL({ dynamic: true, size: 4096 })!);
const msg = await ctx.send({
embeds: [embed],
content: music.player?.queue.current ? `▶ **Now playing: __${music.player.queue.current.title}__**` : null
content: music.player?.queue.current ? `▶ **Now playing: __${music.player.queue.current.title.escapeMarkdown()}__**` : null
});
if (pages.length) embed.setFooter(`Page 1 of ${pages.length}.`);
if (pages.length > 1) {
const pagination = new ButtonPagination(msg, {
author: ctx.author.id,
content: music.player?.queue.current ? `▶ **Now playing: __${music.player.queue.current.title}__**` : "",
content: music.player?.queue.current ? `▶ **Now playing: __${music.player.queue.current.title.escapeMarkdown()}__**` : "",
edit: (i, emb, page): MessageEmbed => emb.setDescription(page).setFooter(`Page ${i + 1} of ${pages.length}`),
embed, pages
});
Expand Down
4 changes: 2 additions & 2 deletions src/commands/music/RemoveCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { isMemberDJ, isMemberInVoiceChannel, isMemberVoiceChannelJoinable, isMus
}
]
},
usage: "{prefix}volume [new volume]"
usage: "{prefix}remove [track position]"
})
export class RemoveCommand extends BaseCommand {
@isMusicPlaying()
Expand All @@ -37,7 +37,7 @@ export class RemoveCommand extends BaseCommand {
});
}
const removed = music.player!.queue.splice(position - 1, 1)[0];
const m = await ctx.send({ embeds: [createEmbed("info", `Removed **[${removed.title}](${removed.uri!})** from the queue!`)] });
const m = await ctx.send({ embeds: [createEmbed("info", `Removed **[${removed.title.escapeMarkdown()}](${removed.uri!})** from the queue!`)] });
if (ctx.channel!.id === ctx.guild!.music.playerChannel) {
setTimeout(() => m.delete().catch(() => null), 5000);
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/music/SearchCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export class SearchCommand extends BaseCommand {
const emojis = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟"];
return tracks.slice(0, 10).map((x, i) => (
{
label: x.title.length > 98 ? `${x.title.substr(0, 97)}...` : x.title,
label: x.title.escapeMarkdown().length > 98 ? `${x.title.escapeMarkdown().substr(0, 97)}...` : x.title.escapeMarkdown(),
emoji: emojis[i],
description: `${x.author} · ${readableTime(x.duration)}`,
value: x.uri
Expand Down
2 changes: 1 addition & 1 deletion src/commands/music/SkipCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class SkipCommand extends BaseCommand {
}
const msg = await ctx.send({
embeds: [
createEmbed("info", `Skipped **[${music.player!.queue.current!.title}](${music.player!.queue.current!.uri!})**`, true)
createEmbed("info", `Skipped **[${music.player!.queue.current!.title.escapeMarkdown()}](${music.player!.queue.current!.uri!})**`, true)
]
});
if (music.playerChannel === ctx.context.channelId) {
Expand Down
4 changes: 2 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const defaultPrefix = ".";
export const devs: UserResolvable[] = ["725331428962992131", "740075062190669884", "736943755344609301"];
export const clientOptions: ClientOptions = {
allowedMentions: { parse: ["users"] },
intents: [Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_VOICE_STATES, Intents.FLAGS.GUILD_MEMBERS],
intents: [Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_VOICE_STATES, Intents.FLAGS.GUILD_MEMBERS, Intents.FLAGS.GUILD_MESSAGE_REACTIONS],
makeCache: () => new Collection(),
restTimeOffset: 300,
retryLimit: 3
Expand Down Expand Up @@ -32,7 +32,7 @@ export const leftTimeout = 120000;
export const defaultBanner = process.env.DEFAULT_BANNER!;
export const databaseName = process.env.DATABASE_NAME;
export const enableProgressBar = process.env.ENABLE_PROGRESS_BAR === "yes";
export const databaseCacheLifetime = 60000;
// export const emojis = ["⏯", "⏭", "🔁", "⏹", "🔀"];

if (typeof databaseName !== "string") throw new Error("config#databaseName must be a string.");
if (typeof defaultBanner !== "string") throw new Error("config#defaultBanner must be a string.");
9 changes: 9 additions & 0 deletions src/extension/Global.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Util } from "discord.js";

globalThis.String.prototype.toProperCase = function toProperCase() {
return this.replace(/([^\W_]+[^\s-]*) */g, txt => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase());
};

globalThis.String.prototype.escapeMarkdown = function escapeMarkdown() {
return Util.escapeMarkdown(this.toString());
};
2 changes: 1 addition & 1 deletion src/extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import { Guild } from "discord.js";
Reflect.defineProperty(Guild.prototype, "music", {
get() {
// @ts-expect-error-next-line
return this.client._music.fetch(this.id);
return this.client.queue.fetch(this.id);
}
});
44 changes: 27 additions & 17 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
import "dotenv/config";
import { ShardingManager } from "discord.js";
import { resolve } from "path";
import { isProd, shardsCount } from "./config";
import { ShardingManager } from "discord.js";
import { createLogger } from "./utils/Logger";
import { shardsCount as totalShards, isDev } from "./config";
const log = createLogger(`shardingmanager`, "en-US", "manager", undefined, isDev);

const log = createLogger(`shardingmanager`, isProd);

const manager = new ShardingManager(resolve(__dirname, "bot.js"), {
totalShards: shardsCount,
respawn: true,
token: process.env.DISCORD_TOKEN,
mode: "process"
process.on("uncaughtException", e => {
log.fatal(e);
process.exit(1);
});

manager.on("shardCreate", shard => {
log.info(`[ShardManager] Shard #${shard.id} Spawned.`);
shard.on("disconnect", () => {
log.warn("SHARD_DISCONNECTED: ", { stack: `[ShardManager] Shard #${shard.id} Disconnected` });
}).on("reconnecting", () => {
log.info(`[ShardManager] Shard #${shard.id} Reconnected.`);
// @ts-expect-error Ignore next line
if (process[Symbol.for("ts-node.register.instance")]) {
log.warn("ts-node detected, sharding is disabled. Please only use ts-node for development purposes.");
require("./bot");
} else {
const manager = new ShardingManager(resolve(__dirname, "bot.js"), {
totalShards,
mode: "worker",
respawn: true,
token: process.env.DISCORD_TOKEN
});
if (manager.shards.size === manager.totalShards) log.info("[ShardManager] All shards spawned successfully.");
}).spawn().catch(e => log.error("SHARD_SPAWN_ERR: ", e));

manager.on("shardCreate", shard => {
log.info(`[ShardManager] Shard #${shard.id} Spawned.`);
shard.on("disconnect", () => {
log.warn("SHARD_DISCONNECTED: ", { stack: `[ShardManager] Shard #${shard.id} Disconnected` });
}).on("reconnecting", () => {
log.info(`[ShardManager] Shard #${shard.id} Reconnected.`);
});
if (manager.shards.size === manager.totalShards) log.info("[ShardManager] All shards spawned successfully.");
}).spawn().catch(e => log.error(e.status ? `Error while fetching recommended shards: ${e.status}, ${e.statusText}` : e));
}
14 changes: 2 additions & 12 deletions src/listeners/InteractionCreateEvent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
import { Interaction, VoiceChannel } from "discord.js";
import { BaseListener } from "../structures/BaseListener";
import { CommandContext } from "../structures/CommandContext";
Expand Down Expand Up @@ -71,15 +70,6 @@ export class InteractionCreateEvent extends BaseListener {
setTimeout(() => this.client.util.convertToMessage(msg).delete().catch(() => null), 5000);
return undefined;
}
if (!vc.permissionsFor(interaction.guild!.me!)!.has(["CONNECT", "SPEAK"])) {
await interaction.deferReply({ ephemeral: true });
const msg = await interaction.followUp({
ephemeral: true,
embeds: [createEmbed("error", "I'm missing `CONNECT` or `SPEAK` permission in your voice!", true)]
});
setTimeout(() => this.client.util.convertToMessage(msg).delete().catch(() => null), 5000);
return undefined;
}
if (!vc.joinable) {
await interaction.deferReply({ ephemeral: true });
const msg = await interaction.followUp({
Expand Down Expand Up @@ -111,7 +101,7 @@ export class InteractionCreateEvent extends BaseListener {
return undefined;
}
}
this.client.logger.info(`${this.client.shard ? `[Shard #${this.client.shard.ids[0]}]` : ""} ${interaction.user.tag} [${interaction.user.id}] executed "${action}" on ${interaction.guild!.name} [${interaction.guildId}]`);
this.client.logger.info(`${interaction.user.tag} [${interaction.user.id}] executed "${action}" on ${interaction.guild!.name} [${interaction.guildId}]`);
if (action === "resumepause") {
await music.player.pause(!music.player.paused);
await interaction.deferUpdate();
Expand All @@ -126,7 +116,7 @@ export class InteractionCreateEvent extends BaseListener {
context.args = [loopModes[(music.loopType + 1) as 0|1|2] || loopModes[LoopType.NONE]];
void this.client.commands.get("loop")!.execute(context);
} else if (action === "stop") {
await music.player!.destroy();
await music.player.destroy();
await music.reset();
await interaction.deferUpdate();
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/listeners/MessageCreateEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class MessageCreateEvent extends BaseListener {
public async execute(message: Message): Promise<any> {
if (message.channel.type === "DM" || !this.client.commands.isReady) return message;
const data = await this.client.databases.guilds.get(message.guild!.id);
if (message.channelId === message.guild!.music.playerChannel) {
if (message.channelId === data.requesterChannel) {
if (message.deletable && message.author.id !== this.client.user!.id) await message.delete().catch(() => null);
if ((!message.content.startsWith(data.prefix) && !message.content.startsWith(this.client.config.prefix)) && !message.author.bot) {
this.client.logger.info(`${message.author.tag} [${message.author.id}] is using play command on ${message.guild!.name}`);
Expand All @@ -18,7 +18,7 @@ export class MessageCreateEvent extends BaseListener {
if (message.author.bot) return;
if (message.content.startsWith(data.prefix) || message.content.startsWith(this.client.config.prefix)) void this.client.commands.handle(message, message.content.startsWith(this.client.config.prefix) ? this.client.config.prefix : data.prefix);

if ((await this.getUserFromMention(message.content))?.id === this.client.user?.id && message.channelId !== message.guild!.music.playerChannel) {
if ((await this.getUserFromMention(message.content))?.id === this.client.user?.id && message.channelId !== data.requesterChannel) {
message.channel.send({
embeds: [
new MessageEmbed()
Expand Down
Loading