More slash commands, rework soundboard commands, added generic music and soundboard commands, tweak speechbubble
This commit is contained in:
parent
c821d91254
commit
a91c73b5bd
68 changed files with 502 additions and 389 deletions
Binary file not shown.
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 40 KiB |
|
@ -4,12 +4,14 @@ class Command {
|
|||
this.cluster = cluster;
|
||||
this.worker = worker;
|
||||
this.ipc = ipc;
|
||||
this.origOptions = options;
|
||||
this.type = options.type;
|
||||
this.args = options.args;
|
||||
if (options.type === "classic") {
|
||||
this.message = options.message;
|
||||
this.channel = options.message.channel;
|
||||
this.author = options.message.author;
|
||||
this.member = options.message.member;
|
||||
this.content = options.content;
|
||||
this.specialArgs = options.specialArgs;
|
||||
this.reference = {
|
||||
|
@ -26,12 +28,13 @@ class Command {
|
|||
} else if (options.type === "application") {
|
||||
this.interaction = options.interaction;
|
||||
this.channel = options.interaction.channel;
|
||||
this.author = options.interaction.guildID ? options.interaction.member : options.interaction.user;
|
||||
this.author = this.member = options.interaction.guildID ? options.interaction.member : options.interaction.user;
|
||||
if (options.interaction.data.options) {
|
||||
this.specialArgs = this.options = options.interaction.data.options.reduce((obj, item) => {
|
||||
obj[item.name] = item.value;
|
||||
return obj;
|
||||
}, {});
|
||||
this.optionsArray = options.interaction.data.options;
|
||||
} else {
|
||||
this.specialArgs = this.options = {};
|
||||
}
|
||||
|
@ -50,6 +53,10 @@ class Command {
|
|||
}
|
||||
}
|
||||
|
||||
static init() {
|
||||
return this;
|
||||
}
|
||||
|
||||
static description = "No description found";
|
||||
static aliases = [];
|
||||
static arguments = [];
|
||||
|
|
|
@ -33,30 +33,6 @@ class ImageCommand extends Command {
|
|||
]
|
||||
};*/
|
||||
|
||||
constructor(client, cluster, worker, ipc, options) {
|
||||
super(client, cluster, worker, ipc, options);
|
||||
this.flags = [];
|
||||
if (this.constructor.requiresText || this.constructor.textOptional) {
|
||||
this.flags.push({
|
||||
name: "text",
|
||||
type: 3,
|
||||
description: "The text to put on the image",
|
||||
required: !this.constructor.textOptional
|
||||
});
|
||||
}
|
||||
if (this.constructor.requiresImage) {
|
||||
this.flags.push({
|
||||
name: "image",
|
||||
type: 11,
|
||||
description: "An image/GIF attachment"
|
||||
}, {
|
||||
name: "link",
|
||||
type: 3,
|
||||
description: "An image/GIF URL"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async criteria() {
|
||||
return true;
|
||||
}
|
||||
|
@ -98,7 +74,6 @@ class ImageCommand extends Command {
|
|||
runningCommands.delete(this.author.id);
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.constructor.requiresText) {
|
||||
|
@ -122,7 +97,7 @@ class ImageCommand extends Command {
|
|||
if (magickParams.params.type === "image/gif" && this.type === "classic") {
|
||||
status = await this.processMessage(this.message);
|
||||
} else {
|
||||
this.acknowledge();
|
||||
await this.acknowledge();
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -148,6 +123,30 @@ class ImageCommand extends Command {
|
|||
return this.client.createMessage(message.channel.id, `${random(emotes) || process.env.PROCESSING_EMOJI || "<a:processing:479351417102925854>"} Processing... This might take a while`);
|
||||
}
|
||||
|
||||
static init() {
|
||||
this.flags = [];
|
||||
if (this.requiresText || this.textOptional) {
|
||||
this.flags.push({
|
||||
name: "text",
|
||||
type: 3,
|
||||
description: "The text to put on the image",
|
||||
required: !this.textOptional
|
||||
});
|
||||
}
|
||||
if (this.requiresImage) {
|
||||
this.flags.push({
|
||||
name: "image",
|
||||
type: 11,
|
||||
description: "An image/GIF attachment"
|
||||
}, {
|
||||
name: "link",
|
||||
type: 3,
|
||||
description: "An image/GIF URL"
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
static requiresImage = true;
|
||||
static requiresText = false;
|
||||
static textOptional = false;
|
||||
|
|
14
classes/soundboardCommand.js
Normal file
14
classes/soundboardCommand.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import Command from "./command.js";
|
||||
import { play } from "../utils/soundplayer.js";
|
||||
|
||||
// only exists to sort the various soundboard commands
|
||||
class SoundboardCommand extends Command {
|
||||
async run() {
|
||||
return await play(this.client, this.constructor.file, { channel: this.channel, author: this.author, type: this.type, interaction: this.interaction });
|
||||
}
|
||||
|
||||
static requires = ["sound"];
|
||||
static slashAllowed = false;
|
||||
}
|
||||
|
||||
export default SoundboardCommand;
|
|
@ -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}"];
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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!";
|
||||
|
||||
|
|
|
@ -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!";
|
||||
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
|
@ -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]"];
|
||||
|
|
|
@ -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!";
|
||||
|
|
|
@ -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]"];
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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!";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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!");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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!";
|
||||
|
|
|
@ -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"];
|
||||
|
|
|
@ -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("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").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("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").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";
|
||||
|
|
|
@ -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("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").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("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").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";
|
||||
|
|
|
@ -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}"];
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").replaceAll("%", "\\%"),
|
||||
bottom: bottomText ? (this.specialArgs.case ? bottomText : bottomText.toUpperCase()).replaceAll("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").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("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").replaceAll("%", "\\%"),
|
||||
bottom: bottomText ? (this.specialArgs.case ? bottomText : bottomText.toUpperCase()).replaceAll("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").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)";
|
||||
|
|
|
@ -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("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").replaceAll("%", "\\%"),
|
||||
bottom: bottomText ? bottomText.replaceAll("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").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("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").replaceAll("%", "\\%"),
|
||||
bottom: bottomText ? bottomText.replaceAll("&", "\\&").replaceAll(">", "\\>").replaceAll("<", "\\<").replaceAll("\"", "\\"").replaceAll("'", "\\'").replaceAll("%", "\\%") : "",
|
||||
font: this.specialArgs.font && allowedFonts.includes(this.specialArgs.font.toLowerCase()) ? this.specialArgs.font.toLowerCase() : "times"
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
static description = "Generates a motivational poster";
|
||||
|
|
|
@ -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}"];
|
||||
|
|
|
@ -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]"];
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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
43
commands/music/music.js
Normal 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;
|
|
@ -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)}`,
|
||||
|
|
|
@ -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]"];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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]"];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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"];
|
||||
}
|
||||
|
|
31
commands/soundboard/soundboard.js
Normal file
31
commands/soundboard/soundboard.js
Normal 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;
|
|
@ -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"];
|
||||
}
|
||||
|
|
|
@ -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") {
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
"MilkyTracker",
|
||||
"with chimps",
|
||||
"with the TF2 source code",
|
||||
"alvin the chipmunk nightcore",
|
||||
"alvin chipmunk nightcore",
|
||||
"Troll",
|
||||
"ay yo the pizza here",
|
||||
"100 gecs",
|
||||
|
|
15
shard.js
15
shard.js
|
@ -8,13 +8,13 @@ import { fileURLToPath } from "url";
|
|||
// fancy loggings
|
||||
import { log, error } from "./utils/logger.js";
|
||||
// initialize command loader
|
||||
import { load } from "./utils/handler.js";
|
||||
import { load, update } from "./utils/handler.js";
|
||||
// lavalink stuff
|
||||
import { checkStatus, connect, status, connected } from "./utils/soundplayer.js";
|
||||
// database stuff
|
||||
import database from "./utils/database.js";
|
||||
// command collections
|
||||
import { paths, info } from "./utils/collections.js";
|
||||
import { paths } from "./utils/collections.js";
|
||||
// playing messages
|
||||
const { messages } = JSON.parse(readFileSync(new URL("./messages.json", import.meta.url)));
|
||||
// other stuff
|
||||
|
@ -35,23 +35,16 @@ class Shard extends BaseClusterWorker {
|
|||
async init() {
|
||||
// register commands and their info
|
||||
const soundStatus = await checkStatus();
|
||||
const commandArray = [];
|
||||
log("info", "Attempting to load commands...");
|
||||
for await (const commandFile of this.getFiles(resolve(dirname(fileURLToPath(import.meta.url)), "./commands/"))) {
|
||||
log("log", `Loading command from ${commandFile}...`);
|
||||
try {
|
||||
const name = await load(this.bot, this.clusterID, this.workerID, this.ipc, commandFile, soundStatus);
|
||||
const commandInfo = info.get(name);
|
||||
if (commandInfo && commandInfo.slashAllowed) commandArray.push({
|
||||
name,
|
||||
type: 1,
|
||||
description: commandInfo.description,
|
||||
options: commandInfo.flags
|
||||
});
|
||||
await load(this.bot, this.clusterID, this.workerID, this.ipc, commandFile, soundStatus);
|
||||
} catch (e) {
|
||||
error(`Failed to register command from ${commandFile}: ${e}`);
|
||||
}
|
||||
}
|
||||
const commandArray = await update(this.bot, this.clusterID, this.workerID, this.ipc, soundStatus);
|
||||
log("info", "Finished loading commands.");
|
||||
|
||||
await database.setup(this.ipc);
|
||||
|
|
|
@ -2,6 +2,8 @@ export const commands = new Map();
|
|||
export const paths = new Map();
|
||||
export const aliases = new Map();
|
||||
export const info = new Map();
|
||||
export const sounds = new Map();
|
||||
export const categories = new Map();
|
||||
|
||||
class TimedMap extends Map {
|
||||
set(key, value) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { paths, commands, info, aliases as _aliases } from "./collections.js";
|
||||
import { paths, commands, info, sounds, categories, aliases as _aliases } from "./collections.js";
|
||||
import { log } from "./logger.js";
|
||||
|
||||
let queryValue = 0;
|
||||
|
@ -13,21 +13,27 @@ export async function load(client, cluster, worker, ipc, command, soundStatus, s
|
|||
}
|
||||
const commandArray = command.split("/");
|
||||
const commandName = commandArray[commandArray.length - 1].split(".")[0];
|
||||
|
||||
props.init();
|
||||
|
||||
paths.set(commandName, command);
|
||||
commands.set(commandName, props);
|
||||
|
||||
const propsInstance = new props(client, cluster, worker, ipc, {});
|
||||
if (Object.getPrototypeOf(props).name === "SoundboardCommand") sounds.set(commandName, props.file);
|
||||
|
||||
const category = commandArray[commandArray.length - 2];
|
||||
info.set(commandName, {
|
||||
category: commandArray[commandArray.length - 2],
|
||||
category: category,
|
||||
description: props.description,
|
||||
aliases: props.aliases,
|
||||
params: props.arguments,
|
||||
flags: propsInstance.flags ?? props.flags,
|
||||
flags: props.flags,
|
||||
slashAllowed: props.slashAllowed
|
||||
});
|
||||
|
||||
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) => {
|
||||
|
@ -37,7 +43,7 @@ export async function load(client, cluster, worker, ipc, command, soundStatus, s
|
|||
name: commandName,
|
||||
type: 1,
|
||||
description: props.description,
|
||||
options: propsInstance.flags ?? props.flags
|
||||
options: props.flags
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -49,3 +55,30 @@ export async function load(client, cluster, worker, ipc, command, soundStatus, s
|
|||
}
|
||||
return commandName;
|
||||
}
|
||||
|
||||
export async function update() {
|
||||
const commandArray = [];
|
||||
for (const [name, command] of commands.entries()) {
|
||||
let cmdInfo = info.get(name);
|
||||
if (command.postInit) {
|
||||
const cmd = command.postInit();
|
||||
//commands.set(name, cmd);
|
||||
cmdInfo = {
|
||||
category: cmdInfo.category,
|
||||
description: cmd.description,
|
||||
aliases: cmd.aliases,
|
||||
params: cmd.arguments,
|
||||
flags: cmd.flags,
|
||||
slashAllowed: cmd.slashAllowed
|
||||
};
|
||||
info.set(name, cmdInfo);
|
||||
}
|
||||
if (cmdInfo && cmdInfo.slashAllowed) commandArray.push({
|
||||
name,
|
||||
type: 1,
|
||||
description: cmdInfo.description,
|
||||
options: cmdInfo.flags
|
||||
});
|
||||
}
|
||||
return commandArray;
|
||||
}
|
|
@ -133,7 +133,7 @@ export default async (client, cmdMessage, interaction, options, extraReturnTypes
|
|||
// we can get a raw attachment or a URL in the interaction itself
|
||||
if (options) {
|
||||
if (options.image) {
|
||||
const result = await getImage(options.image.proxy_url, options.image.url, video);
|
||||
const result = await getImage(interaction.data.resolved.attachments[options.image].proxy_url, interaction.data.resolved.attachments[options.image].url, video);
|
||||
if (result !== false) return result;
|
||||
} else if (options.link) {
|
||||
const result = await getImage(options.link, options.link, video);
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
// eris doesn't come with an awaitMessages method by default, so we make our own
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
class MessageCollector extends EventEmitter {
|
||||
constructor(client, channel, filter, options = {}) {
|
||||
super();
|
||||
this.filter = filter;
|
||||
this.channel = channel;
|
||||
this.options = options;
|
||||
this.ended = false;
|
||||
this.collected = [];
|
||||
this.bot = client;
|
||||
this.listener = message => this.verify(message);
|
||||
this.bot.on("messageCreate", this.listener);
|
||||
if (options.time) setTimeout(() => this.stop("time"), options.time);
|
||||
}
|
||||
|
||||
verify(message) {
|
||||
if (this.channel.id !== message.channel.id) return false;
|
||||
if (this.filter(message)) {
|
||||
this.collected.push(message);
|
||||
this.emit("message", message);
|
||||
if (this.collected.length >= this.options.maxMatches) this.stop("maxMatches");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
stop(reason) {
|
||||
if (this.ended) return;
|
||||
this.ended = true;
|
||||
this.bot.removeListener("messageCreate", this.listener);
|
||||
this.emit("end", this.collected, reason);
|
||||
}
|
||||
}
|
||||
|
||||
export default MessageCollector;
|
|
@ -50,15 +50,15 @@ export async function connect(client) {
|
|||
return length;
|
||||
}
|
||||
|
||||
export async function play(client, sound, message, music = false) {
|
||||
export async function play(client, sound, options, music = false) {
|
||||
if (!manager) return "The sound commands are still starting up!";
|
||||
if (!message.channel.guild) return "This command only works in servers!";
|
||||
if (!message.member.voiceState.channelID) return "You need to be in a voice channel first!";
|
||||
if (!message.channel.guild.permissionsOf(client.user.id).has("voiceConnect")) return "I can't join this voice channel!";
|
||||
const voiceChannel = message.channel.guild.channels.get(message.member.voiceState.channelID);
|
||||
if (!options.channel.guild) return "This command only works in servers!";
|
||||
if (!options.author.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!";
|
||||
const voiceChannel = options.channel.guild.channels.get(options.author.voiceState.channelID);
|
||||
if (!voiceChannel.permissionsOf(client.user.id).has("voiceConnect")) return "I don't have permission to join this voice channel!";
|
||||
const player = players.get(message.channel.guild.id);
|
||||
if (!music && manager.voiceStates.has(message.channel.guild.id) && (player && player.type === "music")) return "I can't play a sound effect while playing music!";
|
||||
const player = players.get(options.channel.guild.id);
|
||||
if (!music && manager.voiceStates.has(options.channel.guild.id) && (player && player.type === "music")) return "I can't play a sound effect while playing music!";
|
||||
let node = manager.idealNodes[0];
|
||||
if (!node) {
|
||||
const status = await checkStatus();
|
||||
|
@ -92,12 +92,12 @@ export async function play(client, sound, message, music = false) {
|
|||
if (oldQueue && oldQueue.length !== 0 && music) {
|
||||
return `Your ${playlistInfo.name ? "playlist" : "tune"} \`${playlistInfo.name ? playlistInfo.name.trim() : (tracks[0].info.title !== "" ? tracks[0].info.title.trim() : "(blank)")}\` has been added to the queue!`;
|
||||
} else {
|
||||
nextSong(client, message, connection, tracks[0].track, tracks[0].info, music, voiceChannel, player ? player.host : message.author.id, player ? player.loop : false, player ? player.shuffle : false);
|
||||
nextSong(client, options, connection, tracks[0].track, tracks[0].info, music, voiceChannel, player ? player.host : options.author.id, player ? player.loop : false, player ? player.shuffle : false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export async function nextSong(client, message, connection, track, info, music, voiceChannel, host, loop = false, shuffle = false, lastTrack = null) {
|
||||
export async function nextSong(client, options, connection, track, info, music, voiceChannel, host, loop = false, shuffle = false, lastTrack = null) {
|
||||
skipVotes.delete(voiceChannel.guild.id);
|
||||
const parts = Math.floor((0 / info.length) * 10);
|
||||
let playingMessage;
|
||||
|
@ -114,7 +114,7 @@ export async function nextSong(client, message, connection, track, info, music,
|
|||
playingMessage = players.get(voiceChannel.guild.id).playMessage;
|
||||
} else {
|
||||
try {
|
||||
playingMessage = await client.createMessage(message.channel.id, !music ? "🔊 Playing sound..." : {
|
||||
const content = !music ? "🔊 Playing sound..." : {
|
||||
embeds: [{
|
||||
color: 16711680,
|
||||
author: {
|
||||
|
@ -138,7 +138,13 @@ export async function nextSong(client, message, connection, track, info, music,
|
|||
value: `0:00/${info.isStream ? "∞" : format(info.length)}`
|
||||
}]
|
||||
}]
|
||||
});
|
||||
};
|
||||
if (options.type === "classic") {
|
||||
playingMessage = await client.createMessage(options.channel.id, content);
|
||||
} else {
|
||||
await options.interaction[options.interaction.acknowledged ? "editOriginalMessage" : "createMessage"](content);
|
||||
playingMessage = await options.interaction.getOriginalMessage();
|
||||
}
|
||||
} catch {
|
||||
// no-op
|
||||
}
|
||||
|
@ -147,7 +153,7 @@ export async function nextSong(client, message, connection, track, info, music,
|
|||
connection.removeAllListeners("end");
|
||||
await connection.play(track);
|
||||
await connection.volume(75);
|
||||
players.set(voiceChannel.guild.id, { player: connection, type: music ? "music" : "sound", host: host, voiceChannel: voiceChannel, originalChannel: message.channel, loop: loop, shuffle: shuffle, playMessage: playingMessage });
|
||||
players.set(voiceChannel.guild.id, { player: connection, type: music ? "music" : "sound", host: host, voiceChannel: voiceChannel, originalChannel: options.channel, loop: loop, shuffle: shuffle, playMessage: playingMessage });
|
||||
connection.once("error", async (error) => {
|
||||
try {
|
||||
if (playingMessage.channel.messages.has(playingMessage.id)) await playingMessage.delete();
|
||||
|
@ -166,7 +172,7 @@ export async function nextSong(client, message, connection, track, info, music,
|
|||
players.delete(voiceChannel.guild.id);
|
||||
queues.delete(voiceChannel.guild.id);
|
||||
logger.error(error);
|
||||
await client.createMessage(message.channel.id, `🔊 Looks like there was an error regarding sound playback:\n\`\`\`${error.type}: ${error.error}\`\`\``);
|
||||
await (options.type === "classic" ? options.channel.createMessage : options.interaction.createMessage)(`🔊 Looks like there was an error regarding sound playback:\n\`\`\`${error.type}: ${error.error}\`\`\``);
|
||||
});
|
||||
connection.on("end", async (data) => {
|
||||
if (data.reason === "REPLACED") return;
|
||||
|
@ -194,7 +200,7 @@ export async function nextSong(client, message, connection, track, info, music,
|
|||
queues.set(voiceChannel.guild.id, newQueue);
|
||||
if (newQueue.length !== 0) {
|
||||
const newTrack = await Rest.decode(connection.node, newQueue[0]);
|
||||
nextSong(client, message, connection, newQueue[0], newTrack, music, voiceChannel, host, player.loop, player.shuffle, track);
|
||||
nextSong(client, options, connection, newQueue[0], newTrack, music, voiceChannel, host, player.loop, player.shuffle, track);
|
||||
try {
|
||||
if (newQueue[0] !== track && playingMessage.channel.messages.has(playingMessage.id)) await playingMessage.delete();
|
||||
if (newQueue[0] !== track && player.playMessage.channel.messages.has(player.playMessage.id)) await player.playMessage.delete();
|
||||
|
@ -207,7 +213,7 @@ export async function nextSong(client, message, connection, track, info, music,
|
|||
players.delete(voiceChannel.guild.id);
|
||||
queues.delete(voiceChannel.guild.id);
|
||||
skipVotes.delete(voiceChannel.guild.id);
|
||||
if (music) await client.createMessage(message.channel.id, "🔊 The current voice channel session has ended.");
|
||||
if (music) await (options.type === "classic" ? options.channel.createMessage : options.interaction.createMessage)("🔊 The current voice channel session has ended.");
|
||||
try {
|
||||
if (playingMessage.channel.messages.has(playingMessage.id)) await playingMessage.delete();
|
||||
if (player && player.playMessage.channel.messages.has(player.playMessage.id)) await player.playMessage.delete();
|
||||
|
|
Loading…
Reference in a new issue