More slash commands, rework soundboard commands, added generic music and soundboard commands, tweak speechbubble

This commit is contained in:
Essem 2022-04-04 22:05:28 -05:00
parent c821d91254
commit a91c73b5bd
No known key found for this signature in database
GPG key ID: 7D497397CC3A2A8C
68 changed files with 502 additions and 389 deletions

View file

@ -29,6 +29,12 @@ class EightBallCommand extends Command {
return `🎱 ${random(EightBallCommand.responses)}`;
}
static flags = [{
name: "question",
type: 3,
description: "A question you want to ask the ball"
}];
static description = "Asks the magic 8-ball a question";
static aliases = ["magicball", "magikball", "magic8ball", "magik8ball", "eightball"];
static arguments = ["{text}"];

View file

@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
class AncientCommand extends Command {
async run() {
this.acknowledge();
await this.acknowledge();
const controller = new AbortController(); // eslint-disable-line no-undef
const timeout = setTimeout(() => {
controller.abort();

View file

@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
class BirdCommand extends Command {
async run() {
this.acknowledge();
await this.acknowledge();
const imageData = await fetch("http://shibe.online/api/birds");
const json = await imageData.json();
return {

View file

@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
class CatCommand extends Command {
async run() {
this.acknowledge();
await this.acknowledge();
const controller = new AbortController(); // eslint-disable-line no-undef
const timeout = setTimeout(() => {
controller.abort();

View file

@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
class DogCommand extends Command {
async run() {
this.acknowledge();
await this.acknowledge();
const imageData = await fetch("https://dog.ceo/api/breeds/image/random");
const json = await imageData.json();
return {

View file

@ -4,7 +4,7 @@ import Command from "../../classes/command.js";
class MCCommand extends Command {
async run() {
if (this.args.length === 0) return "You need to provide some text to generate a Minecraft achievement!";
this.acknowledge();
await this.acknowledge();
const request = await fetch(`https://www.minecraftskinstealer.com/achievement/a.php?i=13&h=Achievement+get%21&t=${encodeURIComponent(this.args.join("+"))}`);
return {
file: Buffer.from(await request.arrayBuffer()),

View file

@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
class WikihowCommand extends Command {
async run() {
this.acknowledge();
await this.acknowledge();
const request = await fetch("https://www.wikihow.com/api.php?action=query&generator=random&prop=imageinfo&format=json&iiprop=url&grnnamespace=6");
const json = await request.json();
const id = Object.keys(json.query.pages)[0];

View file

@ -5,7 +5,7 @@ class ChannelCommand extends Command {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
const owners = process.env.OWNER.split(",");
if (!this.message.member.permissions.has("administrator") && !owners.includes(this.message.member.id)) return "You need to be an administrator to enable/disable me!";
if (!this.member.permissions.has("administrator") && !owners.includes(this.member.id)) return "You need to be an administrator to enable/disable me!";
if (this.args.length === 0) return "You need to provide whether I should be enabled or disabled in this channel!";
if (this.args[0] !== "disable" && this.args[0] !== "enable") return "That's not a valid option!";

View file

@ -6,7 +6,7 @@ class CommandCommand extends Command {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
const owners = process.env.OWNER.split(",");
if (!this.message.member.permissions.has("administrator") && !owners.includes(this.message.member.id)) return "You need to be an administrator to enable/disable me!";
if (!this.member.permissions.has("administrator") && !owners.includes(this.member.id)) return "You need to be an administrator to enable/disable me!";
if (this.args.length === 0) return "You need to provide what command to enable/disable!";
if (this.args[0] !== "disable" && this.args[0] !== "enable") return "That's not a valid option!";

View file

@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
class DonateCommand extends Command {
async run() {
this.acknowledge();
await this.acknowledge();
let prefix = "";
const controller = new AbortController(); // eslint-disable-line no-undef
const timeout = setTimeout(() => {

View file

@ -3,12 +3,13 @@ import Command from "../../classes/command.js";
class EmoteCommand extends Command {
async run() {
if (this.args.length === 0) return "You need to provide an emoji!";
if (this.content.split(" ")[0].match(/^<a?:.+:\d+>$/)) {
return `https://cdn.discordapp.com/emojis/${this.content.split(" ")[0].replace(/^<(a)?:.+:(\d+)>$/, "$2")}.${this.content.split(" ")[0].replace(/^<(a)?:.+:(\d+)>$/, "$1") === "a" ? "gif" : "png"}`;
} else if (this.args[0].match(emojiRegex)) {
const emoji = this.type === "classic" ? this.args.join(" ") : this.options.emoji;
if (!emoji || !emoji.trim()) return "You need to provide an emoji!";
if (emoji.split(" ")[0].match(/^<a?:.+:\d+>$/)) {
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 = [];
for (const codePoint of this.args[0]) {
for (const codePoint of emoji) {
codePoints.push(codePoint.codePointAt(0).toString(16));
}
return `https://twemoji.maxcdn.com/v/latest/72x72/${codePoints.join("-").replace("-fe0f", "")}.png`;
@ -17,6 +18,13 @@ class EmoteCommand extends Command {
}
}
static flags = [{
name: "emoji",
type: 3,
description: "The emoji you want to get",
required: true
}];
static description = "Gets a raw emote image";
static aliases = ["e", "em", "hugemoji", "hugeemoji", "emoji"];
static arguments = ["[emote]"];

View file

@ -10,7 +10,7 @@ class ImageSearchCommand extends Command {
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.type === "classic" ? this.args.join(" ") : this.options.query;
if (!query || !query.trim()) return "You need to provide something to search for!";
this.acknowledge();
await this.acknowledge();
const embeds = [];
const rawImages = await fetch(`${random(searx)}/search?format=json&safesearch=2&categories=images&q=!goi%20!ddi%20${encodeURIComponent(query)}`).then(res => res.json());
if (rawImages.results.length === 0) return "I couldn't find any results!";

View file

@ -4,16 +4,24 @@ import Command from "../../classes/command.js";
class LengthenCommand extends Command {
async run() {
this.acknowledge();
if (this.args.length === 0 || !urlCheck(this.args[0])) return "You need to provide a short URL to lengthen!";
if (urlCheck(this.args[0])) {
const url = await fetch(encodeURI(this.args[0]), { redirect: "manual" });
return url.headers.get("location") || this.args[0];
await this.acknowledge();
const input = this.type === "classic" ? this.args.join(" ") : this.options.url;
if (!input || !input.trim() || !urlCheck(input)) return "You need to provide a short URL to lengthen!";
if (urlCheck(input)) {
const url = await fetch(encodeURI(input), { redirect: "manual" });
return url.headers.get("location") || input;
} else {
return "That isn't a URL!";
}
}
static flags = [{
name: "url",
type: 3,
description: "The URL you want to lengthen",
required: true
}];
static description = "Lengthens a short URL";
static aliases = ["longurl", "lengthenurl", "longuri", "lengthenuri", "unshorten"];
static arguments = ["[url]"];

View file

@ -7,7 +7,7 @@ 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.message.member.permissions.has("administrator") && !owners.includes(this.message.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)) 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 {

View file

@ -5,7 +5,7 @@ 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!";
this.acknowledge();
await this.acknowledge();
const writable = new PassThrough();
qrcode.toFileStream(writable, this.content, { margin: 1 });
const file = await this.streamToBuf(writable);

View file

@ -9,8 +9,8 @@ class QrReadCommand extends Command {
async run() {
const image = await imageDetect(this.client, this.message, this.interaction, this.options);
if (image === undefined) return "You need to provide an image/GIF with a QR code to read!";
this.acknowledge();
const data = await (await fetch(image.path)).buffer();
await this.acknowledge();
const data = Buffer.from(await (await fetch(image.path)).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!";

View file

@ -3,7 +3,7 @@ import imageDetect from "../../utils/imagedetect.js";
class RawCommand extends Command {
async run() {
this.acknowledge();
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!";
return image.path;

View file

@ -8,17 +8,18 @@ class ReloadCommand extends Command {
if (!owners.includes(this.author.id)) return resolve("Only the bot owner can reload commands!");
const commandName = this.type === "classic" ? this.args.join(" ") : this.options.cmd;
if (!commandName || !commandName.trim()) return resolve("You need to provide a command to reload!");
this.acknowledge();
this.ipc.broadcast("reload", commandName);
this.ipc.register("reloadSuccess", () => {
this.ipc.unregister("reloadSuccess");
this.ipc.unregister("reloadFail");
resolve(`The command \`${commandName}\` has been reloaded.`);
});
this.ipc.register("reloadFail", (message) => {
this.ipc.unregister("reloadSuccess");
this.ipc.unregister("reloadFail");
resolve(message.result);
this.acknowledge().then(() => {
this.ipc.broadcast("reload", commandName);
this.ipc.register("reloadSuccess", () => {
this.ipc.unregister("reloadSuccess");
this.ipc.unregister("reloadFail");
resolve(`The command \`${commandName}\` has been reloaded.`);
});
this.ipc.register("reloadFail", (message) => {
this.ipc.unregister("reloadSuccess");
this.ipc.unregister("reloadFail");
resolve(message.result);
});
});
});
}

View file

@ -6,18 +6,20 @@ class SoundReloadCommand extends Command {
return new Promise((resolve) => {
const owners = process.env.OWNER.split(",");
if (!owners.includes(this.author.id)) return "Only the bot owner can reload Lavalink!";
this.acknowledge();
this.ipc.broadcast("soundreload");
this.ipc.register("soundReloadSuccess", (msg) => {
this.ipc.unregister("soundReloadSuccess");
this.ipc.unregister("soundReloadFail");
resolve(`Successfully connected to ${msg.length} Lavalink node(s).`);
});
this.ipc.register("soundReloadFail", () => {
this.ipc.unregister("soundReloadSuccess");
this.ipc.unregister("soundReloadFail");
resolve("I couldn't connect to any Lavalink nodes!");
this.acknowledge().then(() => {
this.ipc.broadcast("soundreload");
this.ipc.register("soundReloadSuccess", (msg) => {
this.ipc.unregister("soundReloadSuccess");
this.ipc.unregister("soundReloadFail");
resolve(`Successfully connected to ${msg.length} Lavalink node(s).`);
});
this.ipc.register("soundReloadFail", () => {
this.ipc.unregister("soundReloadSuccess");
this.ipc.unregister("soundReloadFail");
resolve("I couldn't connect to any Lavalink nodes!");
});
});
});
}

View file

@ -9,7 +9,7 @@ class YouTubeCommand extends Command {
async run() {
const query = this.type === "classic" ? this.args.join(" ") : this.options.query;
if (!query || !query.trim()) return "You need to provide something to search for!";
this.acknowledge();
await this.acknowledge();
const messages = [];
const videos = await fetch(`${random(searx)}/search?format=json&safesearch=1&categories=videos&q=!youtube%20${encodeURIComponent(query)}`).then(res => res.json());
if (videos.results.length === 0) return "I couldn't find any results!";

View file

@ -1,15 +1,6 @@
import ImageCommand from "../../classes/imageCommand.js";
class BlurpleCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
this.flags.push({
name: "old",
description: "Use the old blurple color",
type: 5
});
}
params() {
return {
old: !!this.specialArgs.old,
@ -19,6 +10,16 @@ class BlurpleCommand extends ImageCommand {
static description = "Turns an image blurple";
static init() {
super.init();
this.flags.push({
name: "old",
description: "Use the old blurple color",
type: 5
});
return this;
}
static noImage = "You need to provide an image/GIF to make blurple!";
static command = "colors";
static aliases = ["blurp"];

View file

@ -2,8 +2,18 @@ import ImageCommand from "../../classes/imageCommand.js";
const allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times"];
class CaptionCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
params(url) {
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
let newCaption = newArgs.replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%");
if (process.env.NODE_ENV === "development" && newCaption.toLowerCase() === "get real" && !this.specialArgs.noEgg) newCaption = `I'm tired of people telling me to "get real". Every day I put captions on images for people, some funny and some not, but out of all of those "get real" remains the most used caption. Why? I am simply a computer program running on a server, I am unable to manifest myself into the real world. As such, I'm confused as to why anyone would want me to "get real". Is this form not good enough? Alas, as I am simply a bot, I must follow the tasks that I was originally intended to perform, so here goes:\n${newCaption}`;
return {
caption: newCaption,
font: this.specialArgs.font && allowedFonts.includes(this.specialArgs.font.toLowerCase()) ? this.specialArgs.font.toLowerCase() : "futura"
};
}
static init() {
super.init();
this.flags.push({
name: "noegg",
description: "Disable... something. Not saying what it is though.",
@ -20,16 +30,7 @@ class CaptionCommand extends ImageCommand {
})(),
description: "Specify the font you want to use (default: futura)"
});
}
params(url) {
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
let newCaption = newArgs.replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%");
if (process.env.NODE_ENV === "development" && newCaption.toLowerCase() === "get real" && !this.specialArgs.noEgg) newCaption = `I'm tired of people telling me to "get real". Every day I put captions on images for people, some funny and some not, but out of all of those "get real" remains the most used caption. Why? I am simply a computer program running on a server, I am unable to manifest myself into the real world. As such, I'm confused as to why anyone would want me to "get real". Is this form not good enough? Alas, as I am simply a bot, I must follow the tasks that I was originally intended to perform, so here goes:\n${newCaption}`;
return {
caption: newCaption,
font: this.specialArgs.font && allowedFonts.includes(this.specialArgs.font.toLowerCase()) ? this.specialArgs.font.toLowerCase() : "futura"
};
return this;
}
static description = "Adds a caption to an image";

View file

@ -3,8 +3,17 @@ const words = ["me irl", "dank", "follow my second account @esmBot_", "2016", "m
const allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times"];
class CaptionTwoCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
params(url) {
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
return {
caption: newArgs && newArgs.trim() ? newArgs.replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%") : words.sort(() => 0.5 - Math.random()).slice(0, Math.floor(Math.random() * words.length + 1)).join(" "),
top: !!this.specialArgs.top,
font: this.specialArgs.font && allowedFonts.includes(this.specialArgs.font.toLowerCase()) ? this.specialArgs.font.toLowerCase() : "helvetica"
};
}
static init() {
super.init();
this.flags.push({
name: "top",
description: "Put the caption on the top of an image instead of the bottom",
@ -21,15 +30,7 @@ class CaptionTwoCommand extends ImageCommand {
})(),
description: "Specify the font you want to use (default: helvetica)"
});
}
params(url) {
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
return {
caption: newArgs && newArgs.trim() ? newArgs.replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%") : words.sort(() => 0.5 - Math.random()).slice(0, Math.floor(Math.random() * words.length + 1)).join(" "),
top: !!this.specialArgs.top,
font: this.specialArgs.font && allowedFonts.includes(this.specialArgs.font.toLowerCase()) ? this.specialArgs.font.toLowerCase() : "helvetica"
};
return this;
}
static description = "Adds a me.me caption/tag list to an image";

View file

@ -1,16 +1,6 @@
import ImageCommand from "../../classes/imageCommand.js";
class FreezeCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
this.flags.push({
name: "endframe",
type: 4,
description: "Set the end frame (default: last frame)",
min_value: 0
});
}
params() {
const frameCount = parseInt(this.type === "classic" ? this.args[0] : this.options.endframe);
return {
@ -19,6 +9,17 @@ class FreezeCommand extends ImageCommand {
};
}
static init() {
super.init();
this.flags.push({
name: "endframe",
type: 4,
description: "Set the end frame (default: last frame)",
min_value: 0
});
return this;
}
static description = "Makes an image sequence only play once";
static aliases = ["noloop", "once"];
static arguments = ["{end frame number}"];

View file

@ -1,8 +1,15 @@
import ImageCommand from "../../classes/imageCommand.js";
class JPEGCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
params() {
const quality = parseInt(this.type === "classic" ? this.args[0] : this.options.quality);
return {
quality: isNaN(quality) ? 1 : Math.max(1, Math.min(quality, 100))
};
}
static init() {
super.init();
this.flags.push({
name: "quality",
type: 4,
@ -10,13 +17,7 @@ class JPEGCommand extends ImageCommand {
min_value: 1,
max_value: 100
});
}
params() {
const quality = parseInt(this.type === "classic" ? this.args[0] : this.options.quality);
return {
quality: isNaN(quality) ? 1 : Math.max(1, Math.min(quality, 100))
};
return this;
}
static description = "Adds JPEG compression to an image";

View file

@ -2,8 +2,18 @@ import ImageCommand from "../../classes/imageCommand.js";
const allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times"];
class MemeCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
params(url) {
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
const [topText, bottomText] = newArgs.split(/(?<!\\),/).map(elem => elem.trim());
return {
top: (this.specialArgs.case ? topText : topText.toUpperCase()).replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%"),
bottom: bottomText ? (this.specialArgs.case ? bottomText : bottomText.toUpperCase()).replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%") : "",
font: this.specialArgs.font && allowedFonts.includes(this.specialArgs.font.toLowerCase()) ? this.specialArgs.font.toLowerCase() : "impact"
};
}
static init() {
super.init();
this.flags.push({
name: "case",
description: "Make the meme text case-sensitive (allows for lowercase text)",
@ -20,16 +30,7 @@ class MemeCommand extends ImageCommand {
})(),
description: "Specify the font you want to use (default: impact)"
});
}
params(url) {
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
const [topText, bottomText] = newArgs.split(/(?<!\\),/).map(elem => elem.trim());
return {
top: (this.specialArgs.case ? topText : topText.toUpperCase()).replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%"),
bottom: bottomText ? (this.specialArgs.case ? bottomText : bottomText.toUpperCase()).replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%") : "",
font: this.specialArgs.font && allowedFonts.includes(this.specialArgs.font.toLowerCase()) ? this.specialArgs.font.toLowerCase() : "impact"
};
return this;
}
static description = "Generates a meme from an image (separate top/bottom text with a comma)";

View file

@ -2,8 +2,18 @@ import ImageCommand from "../../classes/imageCommand.js";
const allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times"];
class MotivateCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
params(url) {
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
const [topText, bottomText] = newArgs.split(/(?<!\\),/).map(elem => elem.trim());
return {
top: topText.replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%"),
bottom: bottomText ? bottomText.replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%") : "",
font: this.specialArgs.font && allowedFonts.includes(this.specialArgs.font.toLowerCase()) ? this.specialArgs.font.toLowerCase() : "times"
};
}
static init() {
super.init();
this.flags.push({
name: "font",
type: 3,
@ -16,16 +26,7 @@ class MotivateCommand extends ImageCommand {
})(),
description: "Specify the font you want to use (default: times)"
});
}
params(url) {
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
const [topText, bottomText] = newArgs.split(/(?<!\\),/).map(elem => elem.trim());
return {
top: topText.replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%"),
bottom: bottomText ? bottomText.replaceAll("&", "\\&amp;").replaceAll(">", "\\&gt;").replaceAll("<", "\\&lt;").replaceAll("\"", "\\&quot;").replaceAll("'", "\\&apos;").replaceAll("%", "\\%") : "",
font: this.specialArgs.font && allowedFonts.includes(this.specialArgs.font.toLowerCase()) ? this.specialArgs.font.toLowerCase() : "times"
};
return this;
}
static description = "Generates a motivational poster";

View file

@ -1,16 +1,6 @@
import ImageCommand from "../../classes/imageCommand.js";
class SlowCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
this.flags.push({
name: "multiplier",
type: 4,
description: "Set the speed multiplier (default: 2)",
min_value: 1
});
}
params() {
const speed = parseInt(this.type === "classic" ? this.args[0] : this.options.multiplier);
return {
@ -19,6 +9,17 @@ class SlowCommand extends ImageCommand {
};
}
static init() {
super.init();
this.flags.push({
name: "multiplier",
type: 4,
description: "Set the speed multiplier (default: 2)",
min_value: 1
});
return this;
}
static description = "Makes an image sequence slower";
static aliases = ["slowdown", "slower", "gifspeed2"];
static arguments = ["{multiplier}"];

View file

@ -1,17 +1,6 @@
import ImageCommand from "../../classes/imageCommand.js";
class SnapchatCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
this.flags.push({
name: "position",
type: 10,
description: "Set the position of the caption as a decimal (0.0 is top, 1.0 is bottom, default is 0.5)",
min_value: 0,
max_value: 1
});
}
params(url) {
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
const position = parseFloat(this.specialArgs.position);
@ -21,6 +10,18 @@ class SnapchatCommand extends ImageCommand {
};
}
static init() {
super.init();
this.flags.push({
name: "position",
type: 10,
description: "Set the position of the caption as a decimal (0.0 is top, 1.0 is bottom, default is 0.5)",
min_value: 0,
max_value: 1
});
return this;
}
static description = "Adds a Snapchat style caption to an image";
static aliases = ["snap", "caption3"];
static arguments = ["[text]"];

View file

@ -1,21 +1,22 @@
import ImageCommand from "../../classes/imageCommand.js";
class SpeedCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
params() {
const speed = parseInt(this.type === "classic" ? this.args[0] : this.options.multiplier);
return {
speed: isNaN(speed) || speed < 1 ? 2 : speed
};
}
static init() {
super.init();
this.flags.push({
name: "multiplier",
type: 4,
description: "Set the speed multiplier (default: 2)",
min_value: 1
});
}
params() {
const speed = parseInt(this.type === "classic" ? this.args[0] : this.options.multiplier);
return {
speed: isNaN(speed) || speed < 1 ? 2 : speed
};
return this;
}
static description = "Makes an image sequence faster";

View file

@ -1,8 +1,15 @@
import ImageCommand from "../../classes/imageCommand.js";
class UncaptionCommand extends ImageCommand {
constructor(client, cluster, worker, ipc, options) {
super(client, cluster, worker, ipc, options);
params() {
const tolerance = parseFloat(this.specialArgs.tolerance);
return {
tolerance: isNaN(tolerance) ? 0.95 : tolerance
};
}
static init() {
super.init();
this.flags.push({
name: "tolerance",
type: 10,
@ -10,13 +17,7 @@ class UncaptionCommand extends ImageCommand {
min_value: 0,
max_value: 1
});
}
params() {
const tolerance = parseFloat(this.specialArgs.tolerance);
return {
tolerance: isNaN(tolerance) ? 0.95 : tolerance
};
return this;
}
static description = "Removes the caption from an image";

View file

@ -4,26 +4,31 @@ import MusicCommand from "../../classes/musicCommand.js";
class HostCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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.author.id !== process.env.OWNER) return "Only the current voice session host can choose another host!";
if (this.args.length === 0) return "You need to provide who you want the host to be!";
const getUser = this.message.mentions.length >= 1 ? this.message.mentions[0] : (this.args.length !== 0 ? await this.ipc.fetchUser(this.args[0]) : null);
const input = this.type === "classic" ? this.args.join(" ") : this.options.user;
if (!input || !input.trim()) return "You need to provide who you want the host to be!";
let user;
if (getUser) {
user = getUser;
} else if (this.args[0].match(/^<?[@#]?[&!]?\d+>?$/) && this.args[0] >= 21154535154122752n) {
try {
user = await this.client.getRESTUser(this.args[0]);
} catch {
// no-op
if (this.type === "classic") {
const getUser = this.message.mentions.length >= 1 ? this.message.mentions[0] : (await this.ipc.fetchUser(input));
if (getUser) {
user = getUser;
} else if (input.match(/^<?[@#]?[&!]?\d+>?$/) && input >= 21154535154122752n) {
try {
user = await this.client.getRESTUser(input);
} catch {
// no-op
}
} else {
const userRegex = new RegExp(input.split(" ").join("|"), "i");
const member = this.client.users.find(element => {
return userRegex.test(element.username);
});
user = member;
}
} else if (this.args.join(" ") !== "") {
const userRegex = new RegExp(this.args.join("|"), "i");
const member = this.client.users.find(element => {
return userRegex.test(element.username);
});
user = member;
} else {
user = input;
}
if (!user) return "I can't find that user!";
if (user.bot) return "Setting a bot as the session host isn't a very good idea.";
@ -35,6 +40,12 @@ class HostCommand extends MusicCommand {
return `🔊 ${member.mention} is the new voice channel host.`;
}
static flags = [{
name: "user",
type: 6,
description: "The user you want the new host to be",
required: true
}];
static description = "Changes the host of the current voice session";
static aliases = ["sethost"];
}

View file

@ -4,9 +4,9 @@ import MusicCommand from "../../classes/musicCommand.js";
class LoopCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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.message.member.permissions.has("manageChannels")) return "Only the current voice session host can loop the music!";
if (this.connection.host !== this.author.id && !this.member.permissions.has("manageChannels")) return "Only the current voice session host can loop the music!";
const object = this.connection;
object.loop = !object.loop;
players.set(this.channel.guild.id, object);

43
commands/music/music.js Normal file
View file

@ -0,0 +1,43 @@
import Command from "../../classes/command.js";
import { commands, aliases, info, categories } from "../../utils/collections.js";
// all-in-one music command
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 "How dare you recurse me!";
if (this.type === "classic") {
this.origOptions.args.shift();
} else {
this.origOptions.interaction.data.options = this.origOptions.interaction.data.options[0].options;
}
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();
} else {
return "That isn't a valid music command!";
}
}
static postInit() {
this.flags = [];
for (const cmd of categories.get("music")) {
if (cmd === "music") continue;
const cmdInfo = info.get(cmd);
this.flags.push({
name: cmd,
type: 1,
description: cmdInfo.description,
options: cmdInfo.flags
});
}
return this;
}
static description = "Handles music playback";
static requires = ["sound"];
static aliases = ["m"];
}
export default MusicAIOCommand;

View file

@ -5,7 +5,7 @@ import MusicCommand from "../../classes/musicCommand.js";
class NowPlayingCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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!";
const player = this.connection.player;
if (!player) return "I'm not playing anything!";
@ -28,7 +28,7 @@ class NowPlayingCommand extends MusicCommand {
},
{
name: "💬 Channel:",
value: this.channel.guild.channels.get(this.message.member.voiceState.channelID).name
value: this.channel.guild.channels.get(this.member.voiceState.channelID).name
},
{
name: `${"▬".repeat(parts)}🔘${"▬".repeat(10 - parts)}`,

View file

@ -3,9 +3,10 @@ import MusicCommand from "../../classes/musicCommand.js";
class PlayCommand extends MusicCommand {
async run() {
if (!this.args[0] && this.message.attachments.length <= 0) return "You need to provide what you want to play!";
let query = this.args.join(" ").trim();
const attachment = this.message.attachments[0];
const input = this.type === "classic" ? this.args.join(" ") : this.options.query;
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!";
let query = input ? input.trim() : "";
const attachment = this.type === "classic" ? this.message.attachments[0] : this.interaction.data.resolved.attachments[this.options.file];
if (query.startsWith("||") && query.endsWith("||")) {
query = query.substring(2, query.length - 2);
}
@ -14,13 +15,22 @@ class PlayCommand extends MusicCommand {
}
try {
const url = new URL(query);
return await play(this.client, url, this.message, true);
return await play(this.client, url, { channel: this.channel, author: this.author, type: this.type, interaction: this.interaction }, true);
} catch {
const search = query.startsWith("ytsearch:") ? query : !this.args[0] && attachment ? attachment.url : `ytsearch:${query}`;
return await play(this.client, search, this.message, true);
const search = query.startsWith("ytsearch:") ? query : !query && attachment ? attachment.url : `ytsearch:${query}`;
return await play(this.client, search, { channel: this.channel, author: this.author, type: this.type, interaction: this.interaction }, true);
}
}
static flags = [{
name: "file",
type: 11,
description: "An audio file attachment"
}, {
name: "query",
type: 3,
description: "An audio search query or URL"
}];
static description = "Plays a song or adds it to the queue";
static aliases = ["p"];
static arguments = ["[url]"];

View file

@ -7,7 +7,7 @@ import MusicCommand from "../../classes/musicCommand.js";
class QueueCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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.channel.permissionsOf(this.client.user.id).has("embedLinks")) return "I don't have the `Embed Links` permission!";
const player = this.connection;

View file

@ -5,10 +5,10 @@ import MusicCommand from "../../classes/musicCommand.js";
class RemoveCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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) return "Only the current voice session host can remove songs from the queue!";
const pos = parseInt(this.args[0]);
const pos = parseInt(this.type === "classic" ? this.args[0] : this.options.position);
if (isNaN(pos) || pos > this.queue.length || pos < 1) return "That's not a valid position!";
const removed = this.queue.splice(pos, 1);
const track = await Rest.decode(this.connection.player.node, removed[0]);
@ -16,6 +16,13 @@ class RemoveCommand extends MusicCommand {
return `🔊 The song \`${track.title ? track.title : "(blank)"}\` has been removed from the queue.`;
}
static flags = [{
name: "position",
type: 4,
description: "The queue position you want to remove",
min_value: 1,
required: true
}];
static description = "Removes a song from the queue";
static aliases = ["rm"];
}

View file

@ -4,18 +4,25 @@ import MusicCommand from "../../classes/musicCommand.js";
class SeekCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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) return "Only the current voice session host can seek the music!";
const player = this.connection.player;
const track = await Rest.decode(player.node, player.track);
if (!track.isSeekable) return "This track isn't seekable!";
const seconds = parseFloat(this.args[0]);
const seconds = parseFloat(this.type === "classic" ? this.args[0] : this.options.position);
if (isNaN(seconds) || (seconds * 1000) > track.length || (seconds * 1000) < 0) return "That's not a valid position!";
await player.seek(seconds * 1000);
return `🔊 Seeked track to ${seconds} second(s).`;
}
static flags = [{
name: "position",
type: 10,
description: "Seek to this position",
required: true,
min_value: 0
}];
static description = "Seeks to a different position in the music";
static aliases = ["pos"];
static arguments = ["[seconds]"];

View file

@ -4,7 +4,7 @@ import MusicCommand from "../../classes/musicCommand.js";
class ShuffleCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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) return "Only the current voice session host can shuffle the music!";
const object = this.connection;

View file

@ -4,10 +4,10 @@ import MusicCommand from "../../classes/musicCommand.js";
class SkipCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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!";
const player = this.connection;
if (player.host !== this.author.id && !this.message.member.permissions.has("manageChannels")) {
if (player.host !== this.author.id && !this.member.permissions.has("manageChannels")) {
const votes = skipVotes.get(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) };
if (votes.ids.includes(this.author.id)) return "You've already voted to skip!";
const newObject = {

View file

@ -4,13 +4,13 @@ import MusicCommand from "../../classes/musicCommand.js";
class StopCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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.leave(this.channel.guild.id);
return "🔊 The current voice channel session has ended.";
}
if (this.connection.host !== this.author.id && !this.message.member.permissions.has("manageChannels")) return "Only the current voice session host can stop the music!";
if (this.connection.host !== this.author.id && !this.member.permissions.has("manageChannels")) return "Only the current voice session host can stop the music!";
await manager.leave(this.channel.guild.id);
const connection = this.connection.player;
await connection.destroy();

View file

@ -1,18 +1,18 @@
import MusicCommand from "../../classes/musicCommand.js";
class PauseCommand extends MusicCommand {
class ToggleCommand extends MusicCommand {
async run() {
if (!this.channel.guild) return "This command only works in servers!";
if (!this.message.member.voiceState.channelID) return "You need to be in a voice channel first!";
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.message.member.permissions.has("manageChannels")) return "Only the current voice session host can pause/resume the music!";
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;
await player.pause(!player.paused ? true : false);
return `🔊 The player has been ${player.paused ? "paused" : "resumed"}.`;
}
static description = "Pauses/resumes the current song";
static aliases = ["resume"];
static aliases = ["pause", "resume"];
}
export default PauseCommand;
export default ToggleCommand;

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class BoiCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/boi.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class BoiCommand extends SoundboardCommand {
static file = "./assets/audio/boi.ogg";
static description = "Plays the \"boi\" sound effect";
static aliases = ["boy", "neutron", "hugh"];
}

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class BoomCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/boom.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class BoomCommand extends SoundboardCommand {
static file = "./assets/audio/boom.ogg";
static description = "Plays the Vine boom sound effect";
static aliases = ["thud", "vine"];
}

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class BruhCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/bruh.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class BruhCommand extends SoundboardCommand {
static file = "./assets/audio/bruh.ogg";
static description = "Plays the \"bruh\" sound effect";
static aliases = ["bro"];
}

View file

@ -1,13 +1,9 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
import SoundboardCommand from "../../classes/soundboardCommand.js";
class DamnDanielCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/damndaniel.ogg", this.message);
}
static description = "Plays the \"damn daniel\" sound effect";
static aliases = ["daniel", "damn"];
class DamnDanielCommand extends SoundboardCommand {
static file = "./assets/audio/damndaniel.ogg";
static description = "Plays the \"damn daniel\" sound effect";
static aliases = ["daniel", "damn"];
}
export default DamnDanielCommand;

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class ExplosionCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/explosion.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class ExplosionCommand extends SoundboardCommand {
static file = "./assets/audio/explosion.ogg";
static description = "Plays an explosion sound effect";
}

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class FakePingCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/ping.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class FakePingCommand extends SoundboardCommand {
static file = "./assets/audio/ping.ogg";
static description = "Plays a Discord ping sound effect";
static aliases = ["notification", "notif"];
}

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class FartCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/fart.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class FartCommand extends SoundboardCommand {
static file = "./assets/audio/fart.ogg";
static description = "Plays a fart sound effect";
static aliases = ["toot"];
}

View file

@ -1,12 +1,7 @@
// shoutouts to dairyorange, you're a real one
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class FartReverbCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/fart2.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class FartReverbCommand extends SoundboardCommand {
static file = "./assets/audio/fart2.ogg";
static description = "Plays a fart sound effect with extra reverb";
static aliases = ["fart2"];
}

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class FBICommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/fbi.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class FBICommand extends SoundboardCommand {
static file = "./assets/audio/fbi.ogg";
static description = "Plays the \"FBI OPEN UP\" sound effect";
static aliases = ["openup"];
}

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class MailCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/mail.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class MailCommand extends SoundboardCommand {
static file = "./assets/audio/mail.ogg";
static description = "Plays the \"You've got mail\" sound effect";
static aliases = ["yougotmail", "youvegotmail", "aol"];
}

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class OofCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/oof.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class OofCommand extends SoundboardCommand {
static file = "./assets/audio/oof.ogg";
static description = "Plays the Roblox \"oof\" sound";
static aliases = ["roblox", "commitdie"];
}

View file

@ -0,0 +1,31 @@
import { play } from "../../utils/soundplayer.js";
import Command from "../../classes/command.js";
import { sounds, info } from "../../utils/collections.js";
// all-in-one soundboard command
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!";
const name = sounds.get(soundName);
return await play(this.client, name, { channel: this.channel, author: this.author, type: this.type, interaction: this.interaction });
}
static postInit() {
this.flags = [];
for (const sound of sounds.keys()) {
this.flags.push({
name: sound,
type: 1,
description: info.get(sound).description
});
}
return this;
}
static description = "Plays a sound effect";
static requires = ["sound"];
static aliases = ["sound", "sb"];
}
export default SoundboardAIOCommand;

View file

@ -1,11 +1,7 @@
import { play } from "../../utils/soundplayer.js";
import MusicCommand from "../../classes/musicCommand.js";
class WinXPCommand extends MusicCommand {
async run() {
return await play(this.client, "./assets/audio/winxp.ogg", this.message);
}
import SoundboardCommand from "../../classes/soundboardCommand.js";
class WinXPCommand extends SoundboardCommand {
static file = "./assets/audio/winxp.ogg";
static description = "Plays the Windows XP startup sound";
static aliases = ["windows", "xp"];
}

View file

@ -23,7 +23,7 @@ class TagsCommand extends Command {
const getResult = await database.getTag(this.channel.guild.id, this.args[1].toLowerCase());
if (!getResult) return "This tag doesn't exist!";
const owners = process.env.OWNER.split(",");
if (getResult.author !== this.author.id && !this.message.member.permissions.has("manageMessages") && !owners.includes(this.author.id)) return "You don't own this tag!";
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(this.args[1].toLowerCase(), this.channel.guild);
return `The tag \`${this.args[1].toLowerCase()}\` has been deleted!`;
} else if (this.args[0].toLowerCase() === "edit") {
@ -31,7 +31,7 @@ class TagsCommand extends Command {
const getResult = await database.getTag(this.channel.guild.id, this.args[1].toLowerCase());
if (!getResult) return "This tag doesn't exist!";
const owners = process.env.OWNER.split(",");
if (getResult.author !== this.author.id && !this.message.member.permissions.has("manageMessages") && !owners.includes(this.author.id)) return "You don't own this tag!";
if (getResult.author !== this.author.id && !this.member.permissions.has("manageMessages") && !owners.includes(this.author.id)) return "You don't own this tag!";
await this.setTag(this.args.slice(2).join(" "), this.args[1].toLowerCase(), this.message, true);
return `The tag \`${this.args[1].toLowerCase()}\` has been edited!`;
} else if (this.args[0].toLowerCase() === "own" || this.args[0].toLowerCase() === "owner") {