Added structures.
This commit is contained in:
parent
2073e6eb14
commit
716b402e91
5 changed files with 556 additions and 0 deletions
26
src/structures/BaseContext.js
Normal file
26
src/structures/BaseContext.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/**
|
||||||
|
* @typedef {Object} ContextData
|
||||||
|
* @property {string} name - The name of the command (must be lowercase)
|
||||||
|
* @property {string} description - A short description of the command
|
||||||
|
* @property {import('discord.js').ApplicationCommandType} type - The type of application command
|
||||||
|
* @property {boolean} [enabled] - Whether the slash command is enabled or not
|
||||||
|
* @property {boolean} [ephemeral] - Whether the reply should be ephemeral
|
||||||
|
* @property {boolean} [defaultPermission] - Whether default permission must be enabled
|
||||||
|
* @property {import('discord.js').PermissionResolvable[]} [userPermissions] - Permissions required by the user to use the command.
|
||||||
|
* @property {number} [cooldown] - Command cooldown in seconds
|
||||||
|
* @property {function(import('discord.js').ContextMenuCommandInteraction)} run - The callback to be executed when the context is invoked
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {ContextData} data - The context information
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
type: "",
|
||||||
|
enabled: "",
|
||||||
|
ephemeral: "",
|
||||||
|
options: true,
|
||||||
|
userPermissions: [],
|
||||||
|
cooldown: 0,
|
||||||
|
}
|
345
src/structures/BotClient.js
Normal file
345
src/structures/BotClient.js
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
const {
|
||||||
|
Client,
|
||||||
|
Collection,
|
||||||
|
GatewayIntentBits,
|
||||||
|
Partials,
|
||||||
|
WebhookClient,
|
||||||
|
ApplicationCommandType,
|
||||||
|
} = require("discord.js");
|
||||||
|
const path = require("path");
|
||||||
|
const { table } = require("table");
|
||||||
|
const Logger = require("../helpers/Logger");
|
||||||
|
const { recursiveReadDirSync } = require("../helpers/Utils");
|
||||||
|
const { validateCommand, validateContext } = require("../helpers/Validator");
|
||||||
|
const { schemas } = require("@src/database/mongoose");
|
||||||
|
const CommandCategory = require("./CommandCategory");
|
||||||
|
const lavaclient = require("../handlers/lavaclient");
|
||||||
|
const giveawaysHandler = require("../handlers/giveaway");
|
||||||
|
const { DiscordTogether } = require("discord-together");
|
||||||
|
|
||||||
|
module.exports = class BotClient extends Client {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
intents: [
|
||||||
|
GatewayIntentBits.Guilds,
|
||||||
|
GatewayIntentBits.GuildMessages,
|
||||||
|
GatewayIntentBits.MessageContent,
|
||||||
|
GatewayIntentBits.GuildInvites,
|
||||||
|
GatewayIntentBits.GuildMembers,
|
||||||
|
GatewayIntentBits.GuildPresences,
|
||||||
|
GatewayIntentBits.GuildMessageReactions,
|
||||||
|
GatewayIntentBits.GuildVoiceStates,
|
||||||
|
],
|
||||||
|
partials: [Partials.User, Partials.Message, Partials.Reaction],
|
||||||
|
allowedMentions: {
|
||||||
|
repliedUser: false,
|
||||||
|
},
|
||||||
|
restRequestTimeout: 20000,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.wait = require("util").promisify(setTimeout); // await client.wait(1000) - Wait 1 second
|
||||||
|
this.config = require("@root/config"); // load the config file
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import('@structures/Command')[]}
|
||||||
|
*/
|
||||||
|
this.commands = []; // store actual command
|
||||||
|
this.commandIndex = new Collection(); // store (alias, arrayIndex) pair
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Collection<string, import('@structures/Command')>}
|
||||||
|
*/
|
||||||
|
this.slashCommands = new Collection(); // store slash commands
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Collection<string, import('@structures/BaseContext')>}
|
||||||
|
*/
|
||||||
|
this.contextMenus = new Collection(); // store contextMenus
|
||||||
|
this.counterUpdateQueue = []; // store guildId's that needs counter update
|
||||||
|
|
||||||
|
// initialize webhook for sending guild join/leave details
|
||||||
|
this.joinLeaveWebhook = process.env.JOIN_LEAVE_LOGS
|
||||||
|
? new WebhookClient({ url: process.env.JOIN_LEAVE_LOGS })
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
// Music Player
|
||||||
|
if (this.config.MUSIC.ENABLED) this.musicManager = lavaclient(this);
|
||||||
|
|
||||||
|
// Giveaways
|
||||||
|
if (this.config.GIVEAWAYS.ENABLED) this.giveawaysManager = giveawaysHandler(this);
|
||||||
|
|
||||||
|
// Logger
|
||||||
|
this.logger = Logger;
|
||||||
|
|
||||||
|
// Database
|
||||||
|
this.database = schemas;
|
||||||
|
|
||||||
|
// Discord Together
|
||||||
|
this.discordTogether = new DiscordTogether(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all events from the specified directory
|
||||||
|
* @param {string} directory directory containing the event files
|
||||||
|
*/
|
||||||
|
loadEvents(directory) {
|
||||||
|
this.logger.log(`Loading events...`);
|
||||||
|
let success = 0;
|
||||||
|
let failed = 0;
|
||||||
|
const clientEvents = [];
|
||||||
|
|
||||||
|
recursiveReadDirSync(directory).forEach((filePath) => {
|
||||||
|
const file = path.basename(filePath);
|
||||||
|
try {
|
||||||
|
const eventName = path.basename(file, ".js");
|
||||||
|
const event = require(filePath);
|
||||||
|
|
||||||
|
this.on(eventName, event.bind(null, this));
|
||||||
|
clientEvents.push([file, "✓"]);
|
||||||
|
|
||||||
|
delete require.cache[require.resolve(filePath)];
|
||||||
|
success += 1;
|
||||||
|
} catch (ex) {
|
||||||
|
failed += 1;
|
||||||
|
this.logger.error(`loadEvent - ${file}`, ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
table(clientEvents, {
|
||||||
|
header: {
|
||||||
|
alignment: "center",
|
||||||
|
content: "Client Events",
|
||||||
|
},
|
||||||
|
singleLine: true,
|
||||||
|
columns: [{ width: 25 }, { width: 5, alignment: "center" }],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logger.log(`Loaded ${success + failed} events. Success (${success}) Failed (${failed})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find command matching the invoke
|
||||||
|
* @param {string} invoke
|
||||||
|
* @returns {import('@structures/Command')|undefined}
|
||||||
|
*/
|
||||||
|
getCommand(invoke) {
|
||||||
|
const index = this.commandIndex.get(invoke.toLowerCase());
|
||||||
|
return index !== undefined ? this.commands[index] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register command file in the client
|
||||||
|
* @param {import("@structures/Command")} cmd
|
||||||
|
*/
|
||||||
|
loadCommand(cmd) {
|
||||||
|
// Check if category is disabled
|
||||||
|
if (cmd.category && CommandCategory[cmd.category]?.enabled === false) {
|
||||||
|
this.logger.debug(`Skipping Command ${cmd.name}. Category ${cmd.category} is disabled`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Prefix Command
|
||||||
|
if (cmd.command?.enabled) {
|
||||||
|
const index = this.commands.length;
|
||||||
|
if (this.commandIndex.has(cmd.name)) {
|
||||||
|
throw new Error(`Command ${cmd.name} already registered`);
|
||||||
|
}
|
||||||
|
if (Array.isArray(cmd.command.aliases)) {
|
||||||
|
cmd.command.aliases.forEach((alias) => {
|
||||||
|
if (this.commandIndex.has(alias)) throw new Error(`Alias ${alias} already registered`);
|
||||||
|
this.commandIndex.set(alias.toLowerCase(), index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.commandIndex.set(cmd.name.toLowerCase(), index);
|
||||||
|
this.commands.push(cmd);
|
||||||
|
} else {
|
||||||
|
this.logger.debug(`Skipping command ${cmd.name}. Disabled!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slash Command
|
||||||
|
if (cmd.slashCommand?.enabled) {
|
||||||
|
if (this.slashCommands.has(cmd.name)) throw new Error(`Slash Command ${cmd.name} already registered`);
|
||||||
|
this.slashCommands.set(cmd.name, cmd);
|
||||||
|
} else {
|
||||||
|
this.logger.debug(`Skipping slash command ${cmd.name}. Disabled!`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all commands from the specified directory
|
||||||
|
* @param {string} directory
|
||||||
|
*/
|
||||||
|
loadCommands(directory) {
|
||||||
|
this.logger.log(`Loading commands...`);
|
||||||
|
const files = recursiveReadDirSync(directory);
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const cmd = require(file);
|
||||||
|
if (typeof cmd !== "object") continue;
|
||||||
|
validateCommand(cmd);
|
||||||
|
this.loadCommand(cmd);
|
||||||
|
} catch (ex) {
|
||||||
|
this.logger.error(`Failed to load ${file} Reason: ${ex.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.success(`Loaded ${this.commands.length} commands`);
|
||||||
|
this.logger.success(`Loaded ${this.slashCommands.size} slash commands`);
|
||||||
|
if (this.slashCommands.size > 100) throw new Error("A maximum of 100 slash commands can be enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all contexts from the specified directory
|
||||||
|
* @param {string} directory
|
||||||
|
*/
|
||||||
|
loadContexts(directory) {
|
||||||
|
this.logger.log(`Loading contexts...`);
|
||||||
|
const files = recursiveReadDirSync(directory);
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const ctx = require(file);
|
||||||
|
if (typeof ctx !== "object") continue;
|
||||||
|
validateContext(ctx);
|
||||||
|
if (!ctx.enabled) return this.logger.debug(`Skipping context ${ctx.name}. Disabled!`);
|
||||||
|
if (this.contextMenus.has(ctx.name)) throw new Error(`Context already exists with that name`);
|
||||||
|
this.contextMenus.set(ctx.name, ctx);
|
||||||
|
} catch (ex) {
|
||||||
|
this.logger.error(`Failed to load ${file} Reason: ${ex.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const userContexts = this.contextMenus.filter((ctx) => ctx.type === ApplicationCommandType.User).size;
|
||||||
|
const messageContexts = this.contextMenus.filter((ctx) => ctx.type === ApplicationCommandType.Message).size;
|
||||||
|
|
||||||
|
if (userContexts > 3) throw new Error("A maximum of 3 USER contexts can be enabled");
|
||||||
|
if (messageContexts > 3) throw new Error("A maximum of 3 MESSAGE contexts can be enabled");
|
||||||
|
|
||||||
|
this.logger.success(`Loaded ${userContexts} USER contexts`);
|
||||||
|
this.logger.success(`Loaded ${messageContexts} MESSAGE contexts`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register slash command on startup
|
||||||
|
* @param {string} [guildId]
|
||||||
|
*/
|
||||||
|
async registerInteractions(guildId) {
|
||||||
|
const toRegister = [];
|
||||||
|
|
||||||
|
// filter slash commands
|
||||||
|
if (this.config.INTERACTIONS.SLASH) {
|
||||||
|
this.slashCommands
|
||||||
|
.map((cmd) => ({
|
||||||
|
name: cmd.name,
|
||||||
|
description: cmd.description,
|
||||||
|
type: ApplicationCommandType.ChatInput,
|
||||||
|
options: cmd.slashCommand.options,
|
||||||
|
}))
|
||||||
|
.forEach((s) => toRegister.push(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter contexts
|
||||||
|
if (this.config.INTERACTIONS.CONTEXT) {
|
||||||
|
this.contextMenus
|
||||||
|
.map((ctx) => ({
|
||||||
|
name: ctx.name,
|
||||||
|
type: ctx.type,
|
||||||
|
}))
|
||||||
|
.forEach((c) => toRegister.push(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register GLobally
|
||||||
|
if (!guildId) {
|
||||||
|
await this.application.commands.set(toRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register for a specific guild
|
||||||
|
else if (guildId && typeof guildId === "string") {
|
||||||
|
const guild = this.guilds.cache.get(guildId);
|
||||||
|
if (!guild) {
|
||||||
|
this.logger.error(`Failed to register interactions in guild ${guildId}`, new Error("No matching guild"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await guild.commands.set(toRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw an error
|
||||||
|
else {
|
||||||
|
throw new Error("Did you provide a valid guildId to register interactions");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.success("Successfully registered interactions");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} search
|
||||||
|
* @param {Boolean} exact
|
||||||
|
*/
|
||||||
|
async resolveUsers(search, exact = false) {
|
||||||
|
if (!search || typeof search !== "string") return [];
|
||||||
|
const users = [];
|
||||||
|
|
||||||
|
// check if userId is passed
|
||||||
|
const patternMatch = search.match(/(\d{17,20})/);
|
||||||
|
if (patternMatch) {
|
||||||
|
const id = patternMatch[1];
|
||||||
|
const fetched = await this.users.fetch(id, { cache: true }).catch(() => {}); // check if mentions contains the ID
|
||||||
|
if (fetched) {
|
||||||
|
users.push(fetched);
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if exact tag is matched in cache
|
||||||
|
const matchingTags = this.users.cache.filter((user) => user.tag === search);
|
||||||
|
if (exact && matchingTags.size === 1) users.push(matchingTags.first());
|
||||||
|
else matchingTags.forEach((match) => users.push(match));
|
||||||
|
|
||||||
|
// check matching username
|
||||||
|
if (!exact) {
|
||||||
|
this.users.cache
|
||||||
|
.filter(
|
||||||
|
(x) =>
|
||||||
|
x.username === search ||
|
||||||
|
x.username.toLowerCase().includes(search.toLowerCase()) ||
|
||||||
|
x.tag.toLowerCase().includes(search.toLowerCase())
|
||||||
|
)
|
||||||
|
.forEach((user) => users.push(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get bot's invite
|
||||||
|
*/
|
||||||
|
getInvite() {
|
||||||
|
return this.generateInvite({
|
||||||
|
scopes: ["bot", "applications.commands"],
|
||||||
|
permissions: [
|
||||||
|
"AddReactions",
|
||||||
|
"AttachFiles",
|
||||||
|
"BanMembers",
|
||||||
|
"ChangeNickname",
|
||||||
|
"Connect",
|
||||||
|
"DeafenMembers",
|
||||||
|
"EmbedLinks",
|
||||||
|
"KickMembers",
|
||||||
|
"ManageChannels",
|
||||||
|
"ManageGuild",
|
||||||
|
"ManageMessages",
|
||||||
|
"ManageNicknames",
|
||||||
|
"ManageRoles",
|
||||||
|
"ModerateMembers",
|
||||||
|
"MoveMembers",
|
||||||
|
"MuteMembers",
|
||||||
|
"PrioritySpeaker",
|
||||||
|
"ReadMessageHistory",
|
||||||
|
"SendMessages",
|
||||||
|
"SendMessagesInThreads",
|
||||||
|
"Speak",
|
||||||
|
"ViewChannel",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
75
src/structures/Command.js
Normal file
75
src/structures/Command.js
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Validation
|
||||||
|
* @property {function} callback - The condition to validate
|
||||||
|
* @property {string} message - The message to be displayed if callback condition is not met
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} SubCommand
|
||||||
|
* @property {string} trigger - subcommand invoke
|
||||||
|
* @property {string} description - subcommand description
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {"ADMIN"|"ANIME"|"AUTOMOD"|"ECONOMY"|"FUN"|"IMAGE"|"INFORMATION"|"INVITE"|"MODERATION"|"ERELA_JS"|"NONE"|"OWNER"|"SOCIAL"|"SUGGESTION"|"TICKET"|"UTILITY"} CommandCategory
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} InteractionInfo
|
||||||
|
* @property {boolean} enabled - Whether the slash command is enabled or not
|
||||||
|
* @property {boolean} ephemeral - Whether the reply should be ephemeral
|
||||||
|
* @property {import('discord.js').ApplicationCommandOptionData[]} options - command options
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} CommandInfo
|
||||||
|
* @property {boolean} enabled - Whether the command is enabled or not
|
||||||
|
* @property {string[]} [aliases] - Alternative names for the command (all must be lowercase)
|
||||||
|
* @property {string} [usage=""] - The command usage format string
|
||||||
|
* @property {number} [minArgsCount=0] - Minimum number of arguments the command takes (default is 0)
|
||||||
|
* @property {SubCommand[]} [subcommands=[]] - List of subcommands
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} CommandData
|
||||||
|
* @property {string} name - The name of the command (must be lowercase)
|
||||||
|
* @property {string} description - A short description of the command
|
||||||
|
* @property {number} cooldown - The command cooldown in seconds
|
||||||
|
* @property {CommandCategory} category - The category this command belongs to
|
||||||
|
* @property {import('discord.js').PermissionResolvable[]} [botPermissions] - Permissions required by the client to use the command.
|
||||||
|
* @property {import('discord.js').PermissionResolvable[]} [userPermissions] - Permissions required by the user to use the command
|
||||||
|
* @property {Validation[]} [validations] - List of validations to be run before the command is executed
|
||||||
|
* @property {CommandInfo} command - A short description of the command
|
||||||
|
* @property {InteractionInfo} slashCommand - A short description of the command
|
||||||
|
* @property {function(import('discord.js').Message, string[], object)} messageRun - The callback to be executed when the command is invoked
|
||||||
|
* @property {function(import('discord.js').ChatInputCommandInteraction, object)} interactionRun - The callback to be executed when the interaction is invoked
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for command data
|
||||||
|
* @type {CommandData}
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
cooldown: 0,
|
||||||
|
isPremium: false,
|
||||||
|
category: "NONE",
|
||||||
|
botPermissions: [],
|
||||||
|
userPermissions: [],
|
||||||
|
validations: [],
|
||||||
|
command: {
|
||||||
|
enabled: true,
|
||||||
|
aliases: [],
|
||||||
|
usage: "",
|
||||||
|
minArgsCount: 0,
|
||||||
|
subcommands: [],
|
||||||
|
},
|
||||||
|
slashCommand: {
|
||||||
|
enabled: true,
|
||||||
|
ephemeral: false,
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
|
messageRun: (message, args, data) => {},
|
||||||
|
interactionRun: (interaction, data) => {},
|
||||||
|
};
|
99
src/structures/CommandCategory.js
Normal file
99
src/structures/CommandCategory.js
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
const config = require("@root/config");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
ADMIN: {
|
||||||
|
name: "Admin",
|
||||||
|
image: "https://icons.iconarchive.com/icons/dakirby309/simply-styled/256/Settings-icon.png",
|
||||||
|
emoji: "⚙️",
|
||||||
|
},
|
||||||
|
AUTOMOD: {
|
||||||
|
name: "Automod",
|
||||||
|
enabled: config.AUTOMOD.ENABLED,
|
||||||
|
image: "https://icons.iconarchive.com/icons/dakirby309/simply-styled/256/Settings-icon.png",
|
||||||
|
emoji: "🤖",
|
||||||
|
},
|
||||||
|
ANIME: {
|
||||||
|
name: "Anime",
|
||||||
|
image: "https://wallpaperaccess.com/full/5680679.jpg",
|
||||||
|
emoji: "🎨",
|
||||||
|
},
|
||||||
|
ECONOMY: {
|
||||||
|
name: "Economy",
|
||||||
|
enabled: config.ECONOMY.ENABLED,
|
||||||
|
image: "https://icons.iconarchive.com/icons/custom-icon-design/pretty-office-11/128/coins-icon.png",
|
||||||
|
emoji: "🪙",
|
||||||
|
},
|
||||||
|
FUN: {
|
||||||
|
name: "Fun",
|
||||||
|
image: "https://icons.iconarchive.com/icons/flameia/aqua-smiles/128/make-fun-icon.png",
|
||||||
|
emoji: "😂",
|
||||||
|
},
|
||||||
|
GIVEAWAY: {
|
||||||
|
name: "Giveaway",
|
||||||
|
enabled: config.GIVEAWAYS.ENABLED,
|
||||||
|
image: "https://cdn-icons-png.flaticon.com/512/4470/4470928.png",
|
||||||
|
emoji: "🎉",
|
||||||
|
},
|
||||||
|
IMAGE: {
|
||||||
|
name: "Image",
|
||||||
|
enabled: config.IMAGE.ENABLED,
|
||||||
|
image: "https://icons.iconarchive.com/icons/dapino/summer-holiday/128/photo-icon.png",
|
||||||
|
emoji: "🖼️",
|
||||||
|
},
|
||||||
|
INVITE: {
|
||||||
|
name: "Invite",
|
||||||
|
enabled: config.INVITE.ENABLED,
|
||||||
|
image: "https://cdn4.iconfinder.com/data/icons/general-business/150/Invite-512.png",
|
||||||
|
emoji: "📨",
|
||||||
|
},
|
||||||
|
INFORMATION: {
|
||||||
|
name: "Information",
|
||||||
|
image: "https://icons.iconarchive.com/icons/graphicloads/100-flat/128/information-icon.png",
|
||||||
|
emoji: "🪧",
|
||||||
|
},
|
||||||
|
MODERATION: {
|
||||||
|
name: "Moderation",
|
||||||
|
enabled: config.MODERATION.ENABLED,
|
||||||
|
image: "https://icons.iconarchive.com/icons/lawyerwordpress/law/128/Gavel-Law-icon.png",
|
||||||
|
emoji: "🔨",
|
||||||
|
},
|
||||||
|
MUSIC: {
|
||||||
|
name: "Music",
|
||||||
|
enabled: config.MUSIC.ENABLED,
|
||||||
|
image: "https://icons.iconarchive.com/icons/wwalczyszyn/iwindows/256/Music-Library-icon.png",
|
||||||
|
emoji: "🎵",
|
||||||
|
},
|
||||||
|
OWNER: {
|
||||||
|
name: "Owner",
|
||||||
|
image: "https://www.pinclipart.com/picdir/middle/531-5318253_web-designing-icon-png-clipart.png",
|
||||||
|
emoji: "🤴",
|
||||||
|
},
|
||||||
|
SOCIAL: {
|
||||||
|
name: "Social",
|
||||||
|
image: "https://icons.iconarchive.com/icons/dryicons/aesthetica-2/128/community-users-icon.png",
|
||||||
|
emoji: "🫂",
|
||||||
|
},
|
||||||
|
STATS: {
|
||||||
|
name: "Statistics",
|
||||||
|
enabled: config.STATS.ENABLED,
|
||||||
|
image: "https://icons.iconarchive.com/icons/graphicloads/flat-finance/256/dollar-stats-icon.png",
|
||||||
|
emoji: "📈",
|
||||||
|
},
|
||||||
|
SUGGESTION: {
|
||||||
|
name: "Suggestion",
|
||||||
|
enabled: config.SUGGESTIONS.ENABLED,
|
||||||
|
image: "https://cdn-icons-png.flaticon.com/512/1484/1484815.png",
|
||||||
|
emoji: "📝",
|
||||||
|
},
|
||||||
|
TICKET: {
|
||||||
|
name: "Ticket",
|
||||||
|
enabled: config.TICKET.ENABLED,
|
||||||
|
image: "https://icons.iconarchive.com/icons/custom-icon-design/flatastic-2/512/ticket-icon.png",
|
||||||
|
emoji: "🎫",
|
||||||
|
},
|
||||||
|
UTILITY: {
|
||||||
|
name: "Utility",
|
||||||
|
image: "https://icons.iconarchive.com/icons/blackvariant/button-ui-system-folders-alt/128/Utilities-icon.png",
|
||||||
|
emoji: "🛠",
|
||||||
|
},
|
||||||
|
};
|
11
src/structures/index.js
Normal file
11
src/structures/index.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
const BotClient = require("./BotClient");
|
||||||
|
const Command = require("./Command");
|
||||||
|
const CommandCategory = require("./CommandCategory");
|
||||||
|
const BaseContext = require("./BaseContext");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
BaseContext,
|
||||||
|
BotClient,
|
||||||
|
Command,
|
||||||
|
CommandCategory,
|
||||||
|
};
|
Loading…
Reference in a new issue