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.cluster = cluster;
|
||||||
this.worker = worker;
|
this.worker = worker;
|
||||||
this.ipc = ipc;
|
this.ipc = ipc;
|
||||||
|
this.origOptions = options;
|
||||||
this.type = options.type;
|
this.type = options.type;
|
||||||
this.args = options.args;
|
this.args = options.args;
|
||||||
if (options.type === "classic") {
|
if (options.type === "classic") {
|
||||||
this.message = options.message;
|
this.message = options.message;
|
||||||
this.channel = options.message.channel;
|
this.channel = options.message.channel;
|
||||||
this.author = options.message.author;
|
this.author = options.message.author;
|
||||||
|
this.member = options.message.member;
|
||||||
this.content = options.content;
|
this.content = options.content;
|
||||||
this.specialArgs = options.specialArgs;
|
this.specialArgs = options.specialArgs;
|
||||||
this.reference = {
|
this.reference = {
|
||||||
|
@ -26,12 +28,13 @@ class Command {
|
||||||
} else if (options.type === "application") {
|
} else if (options.type === "application") {
|
||||||
this.interaction = options.interaction;
|
this.interaction = options.interaction;
|
||||||
this.channel = options.interaction.channel;
|
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) {
|
if (options.interaction.data.options) {
|
||||||
this.specialArgs = this.options = options.interaction.data.options.reduce((obj, item) => {
|
this.specialArgs = this.options = options.interaction.data.options.reduce((obj, item) => {
|
||||||
obj[item.name] = item.value;
|
obj[item.name] = item.value;
|
||||||
return obj;
|
return obj;
|
||||||
}, {});
|
}, {});
|
||||||
|
this.optionsArray = options.interaction.data.options;
|
||||||
} else {
|
} else {
|
||||||
this.specialArgs = this.options = {};
|
this.specialArgs = this.options = {};
|
||||||
}
|
}
|
||||||
|
@ -50,6 +53,10 @@ class Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static init() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
static description = "No description found";
|
static description = "No description found";
|
||||||
static aliases = [];
|
static aliases = [];
|
||||||
static arguments = [];
|
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() {
|
async criteria() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -98,7 +74,6 @@ class ImageCommand extends Command {
|
||||||
runningCommands.delete(this.author.id);
|
runningCommands.delete(this.author.id);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.constructor.requiresText) {
|
if (this.constructor.requiresText) {
|
||||||
|
@ -122,7 +97,7 @@ class ImageCommand extends Command {
|
||||||
if (magickParams.params.type === "image/gif" && this.type === "classic") {
|
if (magickParams.params.type === "image/gif" && this.type === "classic") {
|
||||||
status = await this.processMessage(this.message);
|
status = await this.processMessage(this.message);
|
||||||
} else {
|
} else {
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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`);
|
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 requiresImage = true;
|
||||||
static requiresText = false;
|
static requiresText = false;
|
||||||
static textOptional = 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)}`;
|
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 description = "Asks the magic 8-ball a question";
|
||||||
static aliases = ["magicball", "magikball", "magic8ball", "magik8ball", "eightball"];
|
static aliases = ["magicball", "magikball", "magic8ball", "magik8ball", "eightball"];
|
||||||
static arguments = ["{text}"];
|
static arguments = ["{text}"];
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
|
||||||
|
|
||||||
class AncientCommand extends Command {
|
class AncientCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
const controller = new AbortController(); // eslint-disable-line no-undef
|
const controller = new AbortController(); // eslint-disable-line no-undef
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
|
||||||
|
|
||||||
class BirdCommand extends Command {
|
class BirdCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
const imageData = await fetch("http://shibe.online/api/birds");
|
const imageData = await fetch("http://shibe.online/api/birds");
|
||||||
const json = await imageData.json();
|
const json = await imageData.json();
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
|
||||||
|
|
||||||
class CatCommand extends Command {
|
class CatCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
const controller = new AbortController(); // eslint-disable-line no-undef
|
const controller = new AbortController(); // eslint-disable-line no-undef
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
|
||||||
|
|
||||||
class DogCommand extends Command {
|
class DogCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
const imageData = await fetch("https://dog.ceo/api/breeds/image/random");
|
const imageData = await fetch("https://dog.ceo/api/breeds/image/random");
|
||||||
const json = await imageData.json();
|
const json = await imageData.json();
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Command from "../../classes/command.js";
|
||||||
class MCCommand extends Command {
|
class MCCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
if (this.args.length === 0) return "You need to provide some text to generate a Minecraft achievement!";
|
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("+"))}`);
|
const request = await fetch(`https://www.minecraftskinstealer.com/achievement/a.php?i=13&h=Achievement+get%21&t=${encodeURIComponent(this.args.join("+"))}`);
|
||||||
return {
|
return {
|
||||||
file: Buffer.from(await request.arrayBuffer()),
|
file: Buffer.from(await request.arrayBuffer()),
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Command from "../../classes/command.js";
|
||||||
|
|
||||||
class WikihowCommand extends Command {
|
class WikihowCommand extends Command {
|
||||||
async run() {
|
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 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 json = await request.json();
|
||||||
const id = Object.keys(json.query.pages)[0];
|
const id = Object.keys(json.query.pages)[0];
|
||||||
|
|
|
@ -5,7 +5,7 @@ class ChannelCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
if (!this.channel.guild) return "This command only works in servers!";
|
||||||
const owners = process.env.OWNER.split(",");
|
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.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!";
|
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() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
if (!this.channel.guild) return "This command only works in servers!";
|
||||||
const owners = process.env.OWNER.split(",");
|
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.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!";
|
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 {
|
class DonateCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
let prefix = "";
|
let prefix = "";
|
||||||
const controller = new AbortController(); // eslint-disable-line no-undef
|
const controller = new AbortController(); // eslint-disable-line no-undef
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
|
|
|
@ -3,12 +3,13 @@ import Command from "../../classes/command.js";
|
||||||
|
|
||||||
class EmoteCommand extends Command {
|
class EmoteCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
if (this.args.length === 0) return "You need to provide an emoji!";
|
const emoji = this.type === "classic" ? this.args.join(" ") : this.options.emoji;
|
||||||
if (this.content.split(" ")[0].match(/^<a?:.+:\d+>$/)) {
|
if (!emoji || !emoji.trim()) return "You need to provide an emoji!";
|
||||||
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"}`;
|
if (emoji.split(" ")[0].match(/^<a?:.+:\d+>$/)) {
|
||||||
} else if (this.args[0].match(emojiRegex)) {
|
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 = [];
|
const codePoints = [];
|
||||||
for (const codePoint of this.args[0]) {
|
for (const codePoint of emoji) {
|
||||||
codePoints.push(codePoint.codePointAt(0).toString(16));
|
codePoints.push(codePoint.codePointAt(0).toString(16));
|
||||||
}
|
}
|
||||||
return `https://twemoji.maxcdn.com/v/latest/72x72/${codePoints.join("-").replace("-fe0f", "")}.png`;
|
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 description = "Gets a raw emote image";
|
||||||
static aliases = ["e", "em", "hugemoji", "hugeemoji", "emoji"];
|
static aliases = ["e", "em", "hugemoji", "hugeemoji", "emoji"];
|
||||||
static arguments = ["[emote]"];
|
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!";
|
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;
|
const query = this.type === "classic" ? this.args.join(" ") : this.options.query;
|
||||||
if (!query || !query.trim()) return "You need to provide something to search for!";
|
if (!query || !query.trim()) return "You need to provide something to search for!";
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
const embeds = [];
|
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());
|
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!";
|
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 {
|
class LengthenCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
if (this.args.length === 0 || !urlCheck(this.args[0])) return "You need to provide a short URL to lengthen!";
|
const input = this.type === "classic" ? this.args.join(" ") : this.options.url;
|
||||||
if (urlCheck(this.args[0])) {
|
if (!input || !input.trim() || !urlCheck(input)) return "You need to provide a short URL to lengthen!";
|
||||||
const url = await fetch(encodeURI(this.args[0]), { redirect: "manual" });
|
if (urlCheck(input)) {
|
||||||
return url.headers.get("location") || this.args[0];
|
const url = await fetch(encodeURI(input), { redirect: "manual" });
|
||||||
|
return url.headers.get("location") || input;
|
||||||
} else {
|
} else {
|
||||||
return "That isn't a URL!";
|
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 description = "Lengthens a short URL";
|
||||||
static aliases = ["longurl", "lengthenurl", "longuri", "lengthenuri", "unshorten"];
|
static aliases = ["longurl", "lengthenurl", "longuri", "lengthenuri", "unshorten"];
|
||||||
static arguments = ["[url]"];
|
static arguments = ["[url]"];
|
||||||
|
|
|
@ -7,7 +7,7 @@ class PrefixCommand extends Command {
|
||||||
const guild = await database.getGuild(this.channel.guild.id);
|
const guild = await database.getGuild(this.channel.guild.id);
|
||||||
if (this.args.length !== 0) {
|
if (this.args.length !== 0) {
|
||||||
const owners = process.env.OWNER.split(",");
|
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);
|
await database.setPrefix(this.args[0], this.channel.guild);
|
||||||
return `The prefix has been changed to ${this.args[0]}.`;
|
return `The prefix has been changed to ${this.args[0]}.`;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Command from "../../classes/command.js";
|
||||||
class QrCreateCommand extends Command {
|
class QrCreateCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
if (this.args.length === 0) return "You need to provide some text to generate a QR code!";
|
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();
|
const writable = new PassThrough();
|
||||||
qrcode.toFileStream(writable, this.content, { margin: 1 });
|
qrcode.toFileStream(writable, this.content, { margin: 1 });
|
||||||
const file = await this.streamToBuf(writable);
|
const file = await this.streamToBuf(writable);
|
||||||
|
|
|
@ -9,8 +9,8 @@ class QrReadCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
const image = await imageDetect(this.client, this.message, this.interaction, this.options);
|
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!";
|
if (image === undefined) return "You need to provide an image/GIF with a QR code to read!";
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
const data = await (await fetch(image.path)).buffer();
|
const data = Buffer.from(await (await fetch(image.path)).arrayBuffer());
|
||||||
const rawData = await sharp(data).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
const rawData = await sharp(data).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
||||||
const qrBuffer = jsqr(rawData.data, rawData.info.width, rawData.info.height);
|
const qrBuffer = jsqr(rawData.data, rawData.info.width, rawData.info.height);
|
||||||
if (!qrBuffer) return "I couldn't find a QR code!";
|
if (!qrBuffer) return "I couldn't find a QR code!";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import imageDetect from "../../utils/imagedetect.js";
|
||||||
|
|
||||||
class RawCommand extends Command {
|
class RawCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
const image = await imageDetect(this.client, this.message, this.interaction, this.options);
|
const image = await imageDetect(this.client, this.message, this.interaction, this.options);
|
||||||
if (image === undefined) return "You need to provide an image/GIF to get a raw URL!";
|
if (image === undefined) return "You need to provide an image/GIF to get a raw URL!";
|
||||||
return image.path;
|
return image.path;
|
||||||
|
|
|
@ -8,7 +8,7 @@ class ReloadCommand extends Command {
|
||||||
if (!owners.includes(this.author.id)) return resolve("Only the bot owner can reload commands!");
|
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;
|
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!");
|
if (!commandName || !commandName.trim()) return resolve("You need to provide a command to reload!");
|
||||||
this.acknowledge();
|
this.acknowledge().then(() => {
|
||||||
this.ipc.broadcast("reload", commandName);
|
this.ipc.broadcast("reload", commandName);
|
||||||
this.ipc.register("reloadSuccess", () => {
|
this.ipc.register("reloadSuccess", () => {
|
||||||
this.ipc.unregister("reloadSuccess");
|
this.ipc.unregister("reloadSuccess");
|
||||||
|
@ -21,6 +21,7 @@ class ReloadCommand extends Command {
|
||||||
resolve(message.result);
|
resolve(message.result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static flags = [{
|
static flags = [{
|
||||||
|
|
|
@ -6,7 +6,7 @@ class SoundReloadCommand extends Command {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const owners = process.env.OWNER.split(",");
|
const owners = process.env.OWNER.split(",");
|
||||||
if (!owners.includes(this.author.id)) return "Only the bot owner can reload Lavalink!";
|
if (!owners.includes(this.author.id)) return "Only the bot owner can reload Lavalink!";
|
||||||
this.acknowledge();
|
this.acknowledge().then(() => {
|
||||||
this.ipc.broadcast("soundreload");
|
this.ipc.broadcast("soundreload");
|
||||||
this.ipc.register("soundReloadSuccess", (msg) => {
|
this.ipc.register("soundReloadSuccess", (msg) => {
|
||||||
this.ipc.unregister("soundReloadSuccess");
|
this.ipc.unregister("soundReloadSuccess");
|
||||||
|
@ -19,6 +19,8 @@ class SoundReloadCommand extends Command {
|
||||||
resolve("I couldn't connect to any Lavalink nodes!");
|
resolve("I couldn't connect to any Lavalink nodes!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static description = "Attempts to reconnect to all available Lavalink nodes";
|
static description = "Attempts to reconnect to all available Lavalink nodes";
|
||||||
|
|
|
@ -9,7 +9,7 @@ class YouTubeCommand extends Command {
|
||||||
async run() {
|
async run() {
|
||||||
const query = this.type === "classic" ? this.args.join(" ") : this.options.query;
|
const query = this.type === "classic" ? this.args.join(" ") : this.options.query;
|
||||||
if (!query || !query.trim()) return "You need to provide something to search for!";
|
if (!query || !query.trim()) return "You need to provide something to search for!";
|
||||||
this.acknowledge();
|
await this.acknowledge();
|
||||||
const messages = [];
|
const messages = [];
|
||||||
const videos = await fetch(`${random(searx)}/search?format=json&safesearch=1&categories=videos&q=!youtube%20${encodeURIComponent(query)}`).then(res => res.json());
|
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!";
|
if (videos.results.length === 0) return "I couldn't find any results!";
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
import ImageCommand from "../../classes/imageCommand.js";
|
import ImageCommand from "../../classes/imageCommand.js";
|
||||||
|
|
||||||
class BlurpleCommand extends ImageCommand {
|
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() {
|
params() {
|
||||||
return {
|
return {
|
||||||
old: !!this.specialArgs.old,
|
old: !!this.specialArgs.old,
|
||||||
|
@ -19,6 +10,16 @@ class BlurpleCommand extends ImageCommand {
|
||||||
|
|
||||||
static description = "Turns an image blurple";
|
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 noImage = "You need to provide an image/GIF to make blurple!";
|
||||||
static command = "colors";
|
static command = "colors";
|
||||||
static aliases = ["blurp"];
|
static aliases = ["blurp"];
|
||||||
|
|
|
@ -2,8 +2,18 @@ import ImageCommand from "../../classes/imageCommand.js";
|
||||||
const allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times"];
|
const allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times"];
|
||||||
|
|
||||||
class CaptionCommand extends ImageCommand {
|
class CaptionCommand extends ImageCommand {
|
||||||
constructor(client, cluster, worker, ipc, options) {
|
params(url) {
|
||||||
super(client, cluster, worker, ipc, options);
|
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({
|
this.flags.push({
|
||||||
name: "noegg",
|
name: "noegg",
|
||||||
description: "Disable... something. Not saying what it is though.",
|
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)"
|
description: "Specify the font you want to use (default: futura)"
|
||||||
});
|
});
|
||||||
}
|
return this;
|
||||||
|
|
||||||
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 description = "Adds a caption to an image";
|
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"];
|
const allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times"];
|
||||||
|
|
||||||
class CaptionTwoCommand extends ImageCommand {
|
class CaptionTwoCommand extends ImageCommand {
|
||||||
constructor(client, cluster, worker, ipc, options) {
|
params(url) {
|
||||||
super(client, cluster, worker, ipc, options);
|
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({
|
this.flags.push({
|
||||||
name: "top",
|
name: "top",
|
||||||
description: "Put the caption on the top of an image instead of the bottom",
|
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)"
|
description: "Specify the font you want to use (default: helvetica)"
|
||||||
});
|
});
|
||||||
}
|
return this;
|
||||||
|
|
||||||
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 description = "Adds a me.me caption/tag list to an image";
|
static description = "Adds a me.me caption/tag list to an image";
|
||||||
|
|
|
@ -1,16 +1,6 @@
|
||||||
import ImageCommand from "../../classes/imageCommand.js";
|
import ImageCommand from "../../classes/imageCommand.js";
|
||||||
|
|
||||||
class FreezeCommand extends ImageCommand {
|
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() {
|
params() {
|
||||||
const frameCount = parseInt(this.type === "classic" ? this.args[0] : this.options.endframe);
|
const frameCount = parseInt(this.type === "classic" ? this.args[0] : this.options.endframe);
|
||||||
return {
|
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 description = "Makes an image sequence only play once";
|
||||||
static aliases = ["noloop", "once"];
|
static aliases = ["noloop", "once"];
|
||||||
static arguments = ["{end frame number}"];
|
static arguments = ["{end frame number}"];
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
import ImageCommand from "../../classes/imageCommand.js";
|
import ImageCommand from "../../classes/imageCommand.js";
|
||||||
|
|
||||||
class JPEGCommand extends ImageCommand {
|
class JPEGCommand extends ImageCommand {
|
||||||
constructor(client, cluster, worker, ipc, options) {
|
params() {
|
||||||
super(client, cluster, worker, ipc, options);
|
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({
|
this.flags.push({
|
||||||
name: "quality",
|
name: "quality",
|
||||||
type: 4,
|
type: 4,
|
||||||
|
@ -10,13 +17,7 @@ class JPEGCommand extends ImageCommand {
|
||||||
min_value: 1,
|
min_value: 1,
|
||||||
max_value: 100
|
max_value: 100
|
||||||
});
|
});
|
||||||
}
|
return this;
|
||||||
|
|
||||||
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 description = "Adds JPEG compression to an image";
|
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"];
|
const allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times"];
|
||||||
|
|
||||||
class MemeCommand extends ImageCommand {
|
class MemeCommand extends ImageCommand {
|
||||||
constructor(client, cluster, worker, ipc, options) {
|
params(url) {
|
||||||
super(client, cluster, worker, ipc, options);
|
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({
|
this.flags.push({
|
||||||
name: "case",
|
name: "case",
|
||||||
description: "Make the meme text case-sensitive (allows for lowercase text)",
|
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)"
|
description: "Specify the font you want to use (default: impact)"
|
||||||
});
|
});
|
||||||
}
|
return this;
|
||||||
|
|
||||||
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 description = "Generates a meme from an image (separate top/bottom text with a comma)";
|
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"];
|
const allowedFonts = ["futura", "impact", "helvetica", "arial", "roboto", "noto", "times"];
|
||||||
|
|
||||||
class MotivateCommand extends ImageCommand {
|
class MotivateCommand extends ImageCommand {
|
||||||
constructor(client, cluster, worker, ipc, options) {
|
params(url) {
|
||||||
super(client, cluster, worker, ipc, options);
|
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({
|
this.flags.push({
|
||||||
name: "font",
|
name: "font",
|
||||||
type: 3,
|
type: 3,
|
||||||
|
@ -16,16 +26,7 @@ class MotivateCommand extends ImageCommand {
|
||||||
})(),
|
})(),
|
||||||
description: "Specify the font you want to use (default: times)"
|
description: "Specify the font you want to use (default: times)"
|
||||||
});
|
});
|
||||||
}
|
return this;
|
||||||
|
|
||||||
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 description = "Generates a motivational poster";
|
static description = "Generates a motivational poster";
|
||||||
|
|
|
@ -1,16 +1,6 @@
|
||||||
import ImageCommand from "../../classes/imageCommand.js";
|
import ImageCommand from "../../classes/imageCommand.js";
|
||||||
|
|
||||||
class SlowCommand extends ImageCommand {
|
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() {
|
params() {
|
||||||
const speed = parseInt(this.type === "classic" ? this.args[0] : this.options.multiplier);
|
const speed = parseInt(this.type === "classic" ? this.args[0] : this.options.multiplier);
|
||||||
return {
|
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 description = "Makes an image sequence slower";
|
||||||
static aliases = ["slowdown", "slower", "gifspeed2"];
|
static aliases = ["slowdown", "slower", "gifspeed2"];
|
||||||
static arguments = ["{multiplier}"];
|
static arguments = ["{multiplier}"];
|
||||||
|
|
|
@ -1,17 +1,6 @@
|
||||||
import ImageCommand from "../../classes/imageCommand.js";
|
import ImageCommand from "../../classes/imageCommand.js";
|
||||||
|
|
||||||
class SnapchatCommand extends ImageCommand {
|
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) {
|
params(url) {
|
||||||
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
|
const newArgs = this.type === "classic" ? this.args.filter(item => !item.includes(url)).join(" ") : this.options.text;
|
||||||
const position = parseFloat(this.specialArgs.position);
|
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 description = "Adds a Snapchat style caption to an image";
|
||||||
static aliases = ["snap", "caption3"];
|
static aliases = ["snap", "caption3"];
|
||||||
static arguments = ["[text]"];
|
static arguments = ["[text]"];
|
||||||
|
|
|
@ -1,21 +1,22 @@
|
||||||
import ImageCommand from "../../classes/imageCommand.js";
|
import ImageCommand from "../../classes/imageCommand.js";
|
||||||
|
|
||||||
class SpeedCommand extends ImageCommand {
|
class SpeedCommand extends ImageCommand {
|
||||||
constructor(client, cluster, worker, ipc, options) {
|
params() {
|
||||||
super(client, cluster, worker, ipc, options);
|
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({
|
this.flags.push({
|
||||||
name: "multiplier",
|
name: "multiplier",
|
||||||
type: 4,
|
type: 4,
|
||||||
description: "Set the speed multiplier (default: 2)",
|
description: "Set the speed multiplier (default: 2)",
|
||||||
min_value: 1
|
min_value: 1
|
||||||
});
|
});
|
||||||
}
|
return this;
|
||||||
|
|
||||||
params() {
|
|
||||||
const speed = parseInt(this.type === "classic" ? this.args[0] : this.options.multiplier);
|
|
||||||
return {
|
|
||||||
speed: isNaN(speed) || speed < 1 ? 2 : speed
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static description = "Makes an image sequence faster";
|
static description = "Makes an image sequence faster";
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
import ImageCommand from "../../classes/imageCommand.js";
|
import ImageCommand from "../../classes/imageCommand.js";
|
||||||
|
|
||||||
class UncaptionCommand extends ImageCommand {
|
class UncaptionCommand extends ImageCommand {
|
||||||
constructor(client, cluster, worker, ipc, options) {
|
params() {
|
||||||
super(client, cluster, worker, ipc, options);
|
const tolerance = parseFloat(this.specialArgs.tolerance);
|
||||||
|
return {
|
||||||
|
tolerance: isNaN(tolerance) ? 0.95 : tolerance
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static init() {
|
||||||
|
super.init();
|
||||||
this.flags.push({
|
this.flags.push({
|
||||||
name: "tolerance",
|
name: "tolerance",
|
||||||
type: 10,
|
type: 10,
|
||||||
|
@ -10,13 +17,7 @@ class UncaptionCommand extends ImageCommand {
|
||||||
min_value: 0,
|
min_value: 0,
|
||||||
max_value: 1
|
max_value: 1
|
||||||
});
|
});
|
||||||
}
|
return this;
|
||||||
|
|
||||||
params() {
|
|
||||||
const tolerance = parseFloat(this.specialArgs.tolerance);
|
|
||||||
return {
|
|
||||||
tolerance: isNaN(tolerance) ? 0.95 : tolerance
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static description = "Removes the caption from an image";
|
static description = "Removes the caption from an image";
|
||||||
|
|
|
@ -4,27 +4,32 @@ import MusicCommand from "../../classes/musicCommand.js";
|
||||||
class HostCommand extends MusicCommand {
|
class HostCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.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.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 input = this.type === "classic" ? this.args.join(" ") : this.options.user;
|
||||||
const getUser = this.message.mentions.length >= 1 ? this.message.mentions[0] : (this.args.length !== 0 ? await this.ipc.fetchUser(this.args[0]) : null);
|
if (!input || !input.trim()) return "You need to provide who you want the host to be!";
|
||||||
let user;
|
let user;
|
||||||
|
if (this.type === "classic") {
|
||||||
|
const getUser = this.message.mentions.length >= 1 ? this.message.mentions[0] : (await this.ipc.fetchUser(input));
|
||||||
if (getUser) {
|
if (getUser) {
|
||||||
user = getUser;
|
user = getUser;
|
||||||
} else if (this.args[0].match(/^<?[@#]?[&!]?\d+>?$/) && this.args[0] >= 21154535154122752n) {
|
} else if (input.match(/^<?[@#]?[&!]?\d+>?$/) && input >= 21154535154122752n) {
|
||||||
try {
|
try {
|
||||||
user = await this.client.getRESTUser(this.args[0]);
|
user = await this.client.getRESTUser(input);
|
||||||
} catch {
|
} catch {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
} else if (this.args.join(" ") !== "") {
|
} else {
|
||||||
const userRegex = new RegExp(this.args.join("|"), "i");
|
const userRegex = new RegExp(input.split(" ").join("|"), "i");
|
||||||
const member = this.client.users.find(element => {
|
const member = this.client.users.find(element => {
|
||||||
return userRegex.test(element.username);
|
return userRegex.test(element.username);
|
||||||
});
|
});
|
||||||
user = member;
|
user = member;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
user = input;
|
||||||
|
}
|
||||||
if (!user) return "I can't find that user!";
|
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.";
|
if (user.bot) return "Setting a bot as the session host isn't a very good idea.";
|
||||||
const member = this.channel.guild ? this.channel.guild.members.get(user.id) : undefined;
|
const member = this.channel.guild ? this.channel.guild.members.get(user.id) : undefined;
|
||||||
|
@ -35,6 +40,12 @@ class HostCommand extends MusicCommand {
|
||||||
return `🔊 ${member.mention} is the new voice channel host.`;
|
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 description = "Changes the host of the current voice session";
|
||||||
static aliases = ["sethost"];
|
static aliases = ["sethost"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@ import MusicCommand from "../../classes/musicCommand.js";
|
||||||
class LoopCommand extends MusicCommand {
|
class LoopCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.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;
|
const object = this.connection;
|
||||||
object.loop = !object.loop;
|
object.loop = !object.loop;
|
||||||
players.set(this.channel.guild.id, object);
|
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 {
|
class NowPlayingCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!";
|
||||||
const player = this.connection.player;
|
const player = this.connection.player;
|
||||||
if (!player) return "I'm not playing anything!";
|
if (!player) return "I'm not playing anything!";
|
||||||
|
@ -28,7 +28,7 @@ class NowPlayingCommand extends MusicCommand {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "💬 Channel:",
|
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)}`,
|
name: `${"▬".repeat(parts)}🔘${"▬".repeat(10 - parts)}`,
|
||||||
|
|
|
@ -3,9 +3,10 @@ import MusicCommand from "../../classes/musicCommand.js";
|
||||||
|
|
||||||
class PlayCommand extends MusicCommand {
|
class PlayCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.args[0] && this.message.attachments.length <= 0) return "You need to provide what you want to play!";
|
const input = this.type === "classic" ? this.args.join(" ") : this.options.query;
|
||||||
let query = this.args.join(" ").trim();
|
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!";
|
||||||
const attachment = this.message.attachments[0];
|
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("||")) {
|
if (query.startsWith("||") && query.endsWith("||")) {
|
||||||
query = query.substring(2, query.length - 2);
|
query = query.substring(2, query.length - 2);
|
||||||
}
|
}
|
||||||
|
@ -14,13 +15,22 @@ class PlayCommand extends MusicCommand {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const url = new URL(query);
|
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 {
|
} catch {
|
||||||
const search = query.startsWith("ytsearch:") ? query : !this.args[0] && attachment ? attachment.url : `ytsearch:${query}`;
|
const search = query.startsWith("ytsearch:") ? query : !query && attachment ? attachment.url : `ytsearch:${query}`;
|
||||||
return await play(this.client, search, this.message, true);
|
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 description = "Plays a song or adds it to the queue";
|
||||||
static aliases = ["p"];
|
static aliases = ["p"];
|
||||||
static arguments = ["[url]"];
|
static arguments = ["[url]"];
|
||||||
|
|
|
@ -7,7 +7,7 @@ import MusicCommand from "../../classes/musicCommand.js";
|
||||||
class QueueCommand extends MusicCommand {
|
class QueueCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.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!";
|
if (!this.channel.permissionsOf(this.client.user.id).has("embedLinks")) return "I don't have the `Embed Links` permission!";
|
||||||
const player = this.connection;
|
const player = this.connection;
|
||||||
|
|
|
@ -5,10 +5,10 @@ import MusicCommand from "../../classes/musicCommand.js";
|
||||||
class RemoveCommand extends MusicCommand {
|
class RemoveCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.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!";
|
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!";
|
if (isNaN(pos) || pos > this.queue.length || pos < 1) return "That's not a valid position!";
|
||||||
const removed = this.queue.splice(pos, 1);
|
const removed = this.queue.splice(pos, 1);
|
||||||
const track = await Rest.decode(this.connection.player.node, removed[0]);
|
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.`;
|
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 description = "Removes a song from the queue";
|
||||||
static aliases = ["rm"];
|
static aliases = ["rm"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,25 @@ import MusicCommand from "../../classes/musicCommand.js";
|
||||||
class SeekCommand extends MusicCommand {
|
class SeekCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.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!";
|
if (this.connection.host !== this.author.id) return "Only the current voice session host can seek the music!";
|
||||||
const player = this.connection.player;
|
const player = this.connection.player;
|
||||||
const track = await Rest.decode(player.node, player.track);
|
const track = await Rest.decode(player.node, player.track);
|
||||||
if (!track.isSeekable) return "This track isn't seekable!";
|
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!";
|
if (isNaN(seconds) || (seconds * 1000) > track.length || (seconds * 1000) < 0) return "That's not a valid position!";
|
||||||
await player.seek(seconds * 1000);
|
await player.seek(seconds * 1000);
|
||||||
return `🔊 Seeked track to ${seconds} second(s).`;
|
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 description = "Seeks to a different position in the music";
|
||||||
static aliases = ["pos"];
|
static aliases = ["pos"];
|
||||||
static arguments = ["[seconds]"];
|
static arguments = ["[seconds]"];
|
||||||
|
|
|
@ -4,7 +4,7 @@ import MusicCommand from "../../classes/musicCommand.js";
|
||||||
class ShuffleCommand extends MusicCommand {
|
class ShuffleCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.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!";
|
if (this.connection.host !== this.author.id) return "Only the current voice session host can shuffle the music!";
|
||||||
const object = this.connection;
|
const object = this.connection;
|
||||||
|
|
|
@ -4,10 +4,10 @@ import MusicCommand from "../../classes/musicCommand.js";
|
||||||
class SkipCommand extends MusicCommand {
|
class SkipCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!";
|
||||||
const player = this.connection;
|
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) };
|
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!";
|
if (votes.ids.includes(this.author.id)) return "You've already voted to skip!";
|
||||||
const newObject = {
|
const newObject = {
|
||||||
|
|
|
@ -4,13 +4,13 @@ import MusicCommand from "../../classes/musicCommand.js";
|
||||||
class StopCommand extends MusicCommand {
|
class StopCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.guild.members.get(this.client.user.id).voiceState.channelID) return "I'm not in a voice channel!";
|
||||||
if (!this.connection) {
|
if (!this.connection) {
|
||||||
await manager.leave(this.channel.guild.id);
|
await manager.leave(this.channel.guild.id);
|
||||||
return "🔊 The current voice channel session has ended.";
|
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);
|
await manager.leave(this.channel.guild.id);
|
||||||
const connection = this.connection.player;
|
const connection = this.connection.player;
|
||||||
await connection.destroy();
|
await connection.destroy();
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
import MusicCommand from "../../classes/musicCommand.js";
|
||||||
|
|
||||||
class PauseCommand extends MusicCommand {
|
class ToggleCommand extends MusicCommand {
|
||||||
async run() {
|
async run() {
|
||||||
if (!this.channel.guild) return "This command only works in servers!";
|
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.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;
|
const player = this.connection.player;
|
||||||
await player.pause(!player.paused ? true : false);
|
await player.pause(!player.paused ? true : false);
|
||||||
return `🔊 The player has been ${player.paused ? "paused" : "resumed"}.`;
|
return `🔊 The player has been ${player.paused ? "paused" : "resumed"}.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static description = "Pauses/resumes the current song";
|
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 SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class BoiCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/boi.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class BoiCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/boi.ogg";
|
||||||
static description = "Plays the \"boi\" sound effect";
|
static description = "Plays the \"boi\" sound effect";
|
||||||
static aliases = ["boy", "neutron", "hugh"];
|
static aliases = ["boy", "neutron", "hugh"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import { play } from "../../utils/soundplayer.js";
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class BoomCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/boom.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class BoomCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/boom.ogg";
|
||||||
static description = "Plays the Vine boom sound effect";
|
static description = "Plays the Vine boom sound effect";
|
||||||
static aliases = ["thud", "vine"];
|
static aliases = ["thud", "vine"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import { play } from "../../utils/soundplayer.js";
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class BruhCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/bruh.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class BruhCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/bruh.ogg";
|
||||||
static description = "Plays the \"bruh\" sound effect";
|
static description = "Plays the \"bruh\" sound effect";
|
||||||
static aliases = ["bro"];
|
static aliases = ["bro"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import { play } from "../../utils/soundplayer.js";
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class DamnDanielCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/damndaniel.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class DamnDanielCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/damndaniel.ogg";
|
||||||
static description = "Plays the \"damn daniel\" sound effect";
|
static description = "Plays the \"damn daniel\" sound effect";
|
||||||
static aliases = ["daniel", "damn"];
|
static aliases = ["daniel", "damn"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import { play } from "../../utils/soundplayer.js";
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class ExplosionCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/explosion.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class ExplosionCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/explosion.ogg";
|
||||||
static description = "Plays an explosion sound effect";
|
static description = "Plays an explosion sound effect";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import { play } from "../../utils/soundplayer.js";
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class FakePingCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/ping.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class FakePingCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/ping.ogg";
|
||||||
static description = "Plays a Discord ping sound effect";
|
static description = "Plays a Discord ping sound effect";
|
||||||
static aliases = ["notification", "notif"];
|
static aliases = ["notification", "notif"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import { play } from "../../utils/soundplayer.js";
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class FartCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/fart.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class FartCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/fart.ogg";
|
||||||
static description = "Plays a fart sound effect";
|
static description = "Plays a fart sound effect";
|
||||||
static aliases = ["toot"];
|
static aliases = ["toot"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
// shoutouts to dairyorange, you're a real one
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class FartReverbCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/fart2.ogg";
|
||||||
static description = "Plays a fart sound effect with extra reverb";
|
static description = "Plays a fart sound effect with extra reverb";
|
||||||
static aliases = ["fart2"];
|
static aliases = ["fart2"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import { play } from "../../utils/soundplayer.js";
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class FBICommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/fbi.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class FBICommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/fbi.ogg";
|
||||||
static description = "Plays the \"FBI OPEN UP\" sound effect";
|
static description = "Plays the \"FBI OPEN UP\" sound effect";
|
||||||
static aliases = ["openup"];
|
static aliases = ["openup"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import { play } from "../../utils/soundplayer.js";
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class MailCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/mail.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class MailCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/mail.ogg";
|
||||||
static description = "Plays the \"You've got mail\" sound effect";
|
static description = "Plays the \"You've got mail\" sound effect";
|
||||||
static aliases = ["yougotmail", "youvegotmail", "aol"];
|
static aliases = ["yougotmail", "youvegotmail", "aol"];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
import { play } from "../../utils/soundplayer.js";
|
import SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class OofCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/oof.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class OofCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/oof.ogg";
|
||||||
static description = "Plays the Roblox \"oof\" sound";
|
static description = "Plays the Roblox \"oof\" sound";
|
||||||
static aliases = ["roblox", "commitdie"];
|
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 SoundboardCommand from "../../classes/soundboardCommand.js";
|
||||||
import MusicCommand from "../../classes/musicCommand.js";
|
|
||||||
|
|
||||||
class WinXPCommand extends MusicCommand {
|
|
||||||
async run() {
|
|
||||||
return await play(this.client, "./assets/audio/winxp.ogg", this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class WinXPCommand extends SoundboardCommand {
|
||||||
|
static file = "./assets/audio/winxp.ogg";
|
||||||
static description = "Plays the Windows XP startup sound";
|
static description = "Plays the Windows XP startup sound";
|
||||||
static aliases = ["windows", "xp"];
|
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());
|
const getResult = await database.getTag(this.channel.guild.id, this.args[1].toLowerCase());
|
||||||
if (!getResult) return "This tag doesn't exist!";
|
if (!getResult) return "This tag doesn't exist!";
|
||||||
const owners = process.env.OWNER.split(",");
|
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);
|
await database.removeTag(this.args[1].toLowerCase(), this.channel.guild);
|
||||||
return `The tag \`${this.args[1].toLowerCase()}\` has been deleted!`;
|
return `The tag \`${this.args[1].toLowerCase()}\` has been deleted!`;
|
||||||
} else if (this.args[0].toLowerCase() === "edit") {
|
} 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());
|
const getResult = await database.getTag(this.channel.guild.id, this.args[1].toLowerCase());
|
||||||
if (!getResult) return "This tag doesn't exist!";
|
if (!getResult) return "This tag doesn't exist!";
|
||||||
const owners = process.env.OWNER.split(",");
|
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);
|
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!`;
|
return `The tag \`${this.args[1].toLowerCase()}\` has been edited!`;
|
||||||
} else if (this.args[0].toLowerCase() === "own" || this.args[0].toLowerCase() === "owner") {
|
} else if (this.args[0].toLowerCase() === "own" || this.args[0].toLowerCase() === "owner") {
|
||||||
|
|
|
@ -110,7 +110,7 @@
|
||||||
"MilkyTracker",
|
"MilkyTracker",
|
||||||
"with chimps",
|
"with chimps",
|
||||||
"with the TF2 source code",
|
"with the TF2 source code",
|
||||||
"alvin the chipmunk nightcore",
|
"alvin chipmunk nightcore",
|
||||||
"Troll",
|
"Troll",
|
||||||
"ay yo the pizza here",
|
"ay yo the pizza here",
|
||||||
"100 gecs",
|
"100 gecs",
|
||||||
|
|
15
shard.js
15
shard.js
|
@ -8,13 +8,13 @@ import { fileURLToPath } from "url";
|
||||||
// fancy loggings
|
// fancy loggings
|
||||||
import { log, error } from "./utils/logger.js";
|
import { log, error } from "./utils/logger.js";
|
||||||
// initialize command loader
|
// initialize command loader
|
||||||
import { load } from "./utils/handler.js";
|
import { load, update } from "./utils/handler.js";
|
||||||
// lavalink stuff
|
// lavalink stuff
|
||||||
import { checkStatus, connect, status, connected } from "./utils/soundplayer.js";
|
import { checkStatus, connect, status, connected } from "./utils/soundplayer.js";
|
||||||
// database stuff
|
// database stuff
|
||||||
import database from "./utils/database.js";
|
import database from "./utils/database.js";
|
||||||
// command collections
|
// command collections
|
||||||
import { paths, info } from "./utils/collections.js";
|
import { paths } from "./utils/collections.js";
|
||||||
// playing messages
|
// playing messages
|
||||||
const { messages } = JSON.parse(readFileSync(new URL("./messages.json", import.meta.url)));
|
const { messages } = JSON.parse(readFileSync(new URL("./messages.json", import.meta.url)));
|
||||||
// other stuff
|
// other stuff
|
||||||
|
@ -35,23 +35,16 @@ class Shard extends BaseClusterWorker {
|
||||||
async init() {
|
async init() {
|
||||||
// register commands and their info
|
// register commands and their info
|
||||||
const soundStatus = await checkStatus();
|
const soundStatus = await checkStatus();
|
||||||
const commandArray = [];
|
|
||||||
log("info", "Attempting to load commands...");
|
log("info", "Attempting to load commands...");
|
||||||
for await (const commandFile of this.getFiles(resolve(dirname(fileURLToPath(import.meta.url)), "./commands/"))) {
|
for await (const commandFile of this.getFiles(resolve(dirname(fileURLToPath(import.meta.url)), "./commands/"))) {
|
||||||
log("log", `Loading command from ${commandFile}...`);
|
log("log", `Loading command from ${commandFile}...`);
|
||||||
try {
|
try {
|
||||||
const name = await load(this.bot, this.clusterID, this.workerID, this.ipc, commandFile, soundStatus);
|
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
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error(`Failed to register command from ${commandFile}: ${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.");
|
log("info", "Finished loading commands.");
|
||||||
|
|
||||||
await database.setup(this.ipc);
|
await database.setup(this.ipc);
|
||||||
|
|
|
@ -2,6 +2,8 @@ export const commands = new Map();
|
||||||
export const paths = new Map();
|
export const paths = new Map();
|
||||||
export const aliases = new Map();
|
export const aliases = new Map();
|
||||||
export const info = new Map();
|
export const info = new Map();
|
||||||
|
export const sounds = new Map();
|
||||||
|
export const categories = new Map();
|
||||||
|
|
||||||
class TimedMap extends Map {
|
class TimedMap extends Map {
|
||||||
set(key, value) {
|
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";
|
import { log } from "./logger.js";
|
||||||
|
|
||||||
let queryValue = 0;
|
let queryValue = 0;
|
||||||
|
@ -14,20 +14,26 @@ export async function load(client, cluster, worker, ipc, command, soundStatus, s
|
||||||
const commandArray = command.split("/");
|
const commandArray = command.split("/");
|
||||||
const commandName = commandArray[commandArray.length - 1].split(".")[0];
|
const commandName = commandArray[commandArray.length - 1].split(".")[0];
|
||||||
|
|
||||||
|
props.init();
|
||||||
|
|
||||||
paths.set(commandName, command);
|
paths.set(commandName, command);
|
||||||
commands.set(commandName, props);
|
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, {
|
info.set(commandName, {
|
||||||
category: commandArray[commandArray.length - 2],
|
category: category,
|
||||||
description: props.description,
|
description: props.description,
|
||||||
aliases: props.aliases,
|
aliases: props.aliases,
|
||||||
params: props.arguments,
|
params: props.arguments,
|
||||||
flags: propsInstance.flags ?? props.flags,
|
flags: props.flags,
|
||||||
slashAllowed: props.slashAllowed
|
slashAllowed: props.slashAllowed
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const categoryCommands = categories.get(category);
|
||||||
|
categories.set(category, categoryCommands ? [...categoryCommands, commandName] : [commandName]);
|
||||||
|
|
||||||
if (slashReload && props.slashAllowed) {
|
if (slashReload && props.slashAllowed) {
|
||||||
const commandList = await client.getCommands();
|
const commandList = await client.getCommands();
|
||||||
const oldCommand = commandList.filter((item) => {
|
const oldCommand = commandList.filter((item) => {
|
||||||
|
@ -37,7 +43,7 @@ export async function load(client, cluster, worker, ipc, command, soundStatus, s
|
||||||
name: commandName,
|
name: commandName,
|
||||||
type: 1,
|
type: 1,
|
||||||
description: props.description,
|
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;
|
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
|
// we can get a raw attachment or a URL in the interaction itself
|
||||||
if (options) {
|
if (options) {
|
||||||
if (options.image) {
|
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;
|
if (result !== false) return result;
|
||||||
} else if (options.link) {
|
} else if (options.link) {
|
||||||
const result = await getImage(options.link, options.link, video);
|
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;
|
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 (!manager) return "The sound commands are still starting up!";
|
||||||
if (!message.channel.guild) return "This command only works in servers!";
|
if (!options.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 (!options.author.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!";
|
if (!options.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);
|
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!";
|
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);
|
const player = players.get(options.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!";
|
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];
|
let node = manager.idealNodes[0];
|
||||||
if (!node) {
|
if (!node) {
|
||||||
const status = await checkStatus();
|
const status = await checkStatus();
|
||||||
|
@ -92,12 +92,12 @@ export async function play(client, sound, message, music = false) {
|
||||||
if (oldQueue && oldQueue.length !== 0 && music) {
|
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!`;
|
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 {
|
} 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;
|
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);
|
skipVotes.delete(voiceChannel.guild.id);
|
||||||
const parts = Math.floor((0 / info.length) * 10);
|
const parts = Math.floor((0 / info.length) * 10);
|
||||||
let playingMessage;
|
let playingMessage;
|
||||||
|
@ -114,7 +114,7 @@ export async function nextSong(client, message, connection, track, info, music,
|
||||||
playingMessage = players.get(voiceChannel.guild.id).playMessage;
|
playingMessage = players.get(voiceChannel.guild.id).playMessage;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
playingMessage = await client.createMessage(message.channel.id, !music ? "🔊 Playing sound..." : {
|
const content = !music ? "🔊 Playing sound..." : {
|
||||||
embeds: [{
|
embeds: [{
|
||||||
color: 16711680,
|
color: 16711680,
|
||||||
author: {
|
author: {
|
||||||
|
@ -138,7 +138,13 @@ export async function nextSong(client, message, connection, track, info, music,
|
||||||
value: `0:00/${info.isStream ? "∞" : format(info.length)}`
|
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 {
|
} catch {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
@ -147,7 +153,7 @@ export async function nextSong(client, message, connection, track, info, music,
|
||||||
connection.removeAllListeners("end");
|
connection.removeAllListeners("end");
|
||||||
await connection.play(track);
|
await connection.play(track);
|
||||||
await connection.volume(75);
|
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) => {
|
connection.once("error", async (error) => {
|
||||||
try {
|
try {
|
||||||
if (playingMessage.channel.messages.has(playingMessage.id)) await playingMessage.delete();
|
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);
|
players.delete(voiceChannel.guild.id);
|
||||||
queues.delete(voiceChannel.guild.id);
|
queues.delete(voiceChannel.guild.id);
|
||||||
logger.error(error);
|
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) => {
|
connection.on("end", async (data) => {
|
||||||
if (data.reason === "REPLACED") return;
|
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);
|
queues.set(voiceChannel.guild.id, newQueue);
|
||||||
if (newQueue.length !== 0) {
|
if (newQueue.length !== 0) {
|
||||||
const newTrack = await Rest.decode(connection.node, newQueue[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 {
|
try {
|
||||||
if (newQueue[0] !== track && playingMessage.channel.messages.has(playingMessage.id)) await playingMessage.delete();
|
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();
|
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);
|
players.delete(voiceChannel.guild.id);
|
||||||
queues.delete(voiceChannel.guild.id);
|
queues.delete(voiceChannel.guild.id);
|
||||||
skipVotes.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 {
|
try {
|
||||||
if (playingMessage.channel.messages.has(playingMessage.id)) await playingMessage.delete();
|
if (playingMessage.channel.messages.has(playingMessage.id)) await playingMessage.delete();
|
||||||
if (player && player.playMessage.channel.messages.has(player.playMessage.id)) await player.playMessage.delete();
|
if (player && player.playMessage.channel.messages.has(player.playMessage.id)) await player.playMessage.delete();
|
||||||
|
|
Loading…
Reference in a new issue