Skip to content

Instantly share code, notes, and snippets.

@zedxos
Created October 27, 2020 11:31
Show Gist options
  • Save zedxos/c5fcf33a30213e0a08db4f46498816d4 to your computer and use it in GitHub Desktop.
Save zedxos/c5fcf33a30213e0a08db4f46498816d4 to your computer and use it in GitHub Desktop.
Discord.js Multiple folder command handler
/**
* @author Anish Shobith
* @license MIT
* @file index.js
*/
// Requring the packages and modules required
// All the methods used here are destructing.
const { Client, Collection } = require("discord.js");
const { readdirSync } = require("fs");
const { sep } = require("path");
const { success, error, warning } = require("log-symbols"); // npm i log-symbols or yarn add log-symbols
// we require the config file
const config = require("./config");
// Creating a instance of Client.
const bot = new Client();
// Attaching Config to bot so it can be accessed anywhere.
bot.config = config;
// Creating command and aliases collection.
["commands", "aliases"].forEach(x => bot[x] = new Collection());
// A function to load all the commands.
const load = (dir = "./commands/") => {
readdirSync(dir).forEach(dirs => {
// we read the commands directory for sub folders and filter the files with name with extension .js
const commands = readdirSync(`${dir}${sep}${dirs}${sep}`).filter(files => files.endsWith(".js"));
// we use for loop in order to get all the commands in sub directory
for (const file of commands) {
// We make a pull to that file so we can add it the bot.commands collection
const pull = require(`${dir}/${dirs}/${file}`);
// we check here if the command name or command category is a string or not or check if they exist
if (pull.help && typeof (pull.help.name) === "string" && typeof (pull.help.category) === "string") {
if (bot.commands.get(pull.help.name)) return console.warn(`${warning} Two or more commands have the same name ${pull.help.name}.`);
// we add the the comamnd to the collection, Map.prototype.set() for more info
bot.commands.set(pull.help.name, pull);
// we log if the command was loaded.
console.log(`${success} Loaded command ${pull.help.name}.`);
}
else {
// we check if the command is loaded else throw a error saying there was command it didn't load
console.log(`${error} Error loading command in ${dir}${dirs}. you have a missing help.name or help.name is not a string. or you have a missing help.category or help.category is not a string`);
// we use continue to load other commands or else it will stop here
continue;
}
// we check if the command has aliases, is so we add it to the collection
if (pull.help.aliases && typeof (pull.help.aliases) === "object") {
pull.help.aliases.forEach(alias => {
// we check if there is a conflict with any other aliases which have same name
if (bot.aliases.get(alias)) return console.warn(`${warning} Two commands or more commands have the same aliases ${alias}`);
bot.aliases.set(alias, pull.help.name);
});
}
}
});
};
// we call the function to all the commands.
load();
/**
* Ready event
* @description Event is triggred when bot enters ready state.
*/
bot.on("ready", () => {
console.log("I am online");
});
/**
* Message event
* @param message - The message parameter for this event.
*/
bot.on("message", async message => {
const prefix = bot.config.prefix;
const args = message.content.slice(prefix.length).trim().split(/ +/g);
const cmd = args.shift().toLowerCase();
let command;
if (message.author.bot || !message.guild) return;
// If the message.member is uncached, message.member might return null.
// This prevents that from happening.
// eslint-disable-next-line require-atomic-updates
if (!message.member) message.member = await message.guild.fetchMember(message.author);
if (!message.content.startsWith(prefix)) return;
if (cmd.length === 0) return;
if (bot.commands.has(cmd)) command = bot.commands.get(cmd);
else if (bot.aliases.has(cmd)) command = bot.commands.get(bot.aliases.get(cmd));
if (command) command.run(bot, message, args);
});
// Here we login the bot with the porvided token in the config file, as login() returns a Promise we catch the error.
bot.login(bot.config.token).catch(console.error());
module.exports = {
prefix: "",
owners: [""],
token: "",
};
const { RichEmbed } = require("discord.js");
const { readdirSync } = require("fs");
module.exports.run = (bot, message, args) => {
const embed = new RichEmbed()
.setColor("#2C2F33")
.setAuthor(`${bot.user.username} Help`, bot.user.displayAvatarURL)
.setFooter(`Requested by ${message.author.tag} at`, message.author.displayAvatarURL)
.setTimestamp();
if (args[0]) {
let command = args[0];
let cmd;
if (bot.commands.has(command)) {
cmd = bot.commands.get(command);
}
else if (bot.aliases.has(command)) {
cmd = bot.commands.get(bot.aliases.get(command));
}
if(!cmd) return message.channel.send(embed.setTitle("Invalid Command.").setDescription(`Do \`${bot.config.prefix}help\` for the list of the commands.`));
command = cmd.help;
embed.setTitle(`${command.name.slice(0, 1).toUpperCase() + command.name.slice(1)} command help`);
embed.setDescription([
`❯ **Command:** ${command.name.slice(0, 1).toUpperCase() + command.name.slice(1)}`,
`❯ **Description:** ${command.description || "No Description provided."}`,
`❯ **Usage:** ${command.usage ? `\`${bot.config.prefix}${command.name} ${command.usage}\`` : "No Usage"} `,
`❯ **Aliases:** ${command.aliases ? command.aliases.join(", ") : "None"}`,
`❯ **Category:** ${command.category ? command.category : "General" || "Misc"}`,
].join("\n"));
return message.channel.send(embed);
}
const categories = readdirSync("./commands/");
embed.setDescription([
`Available commands for ${bot.user.username}.`,
`The bot prefix is **${bot.config.prefix}**`,
"`<>`means needed and () it is optional but don't include those",
].join("\n"));
categories.forEach(category => {
const dir = bot.commands.filter(c => c.help.category.toLowerCase() === category.toLowerCase());
const capitalise = category.slice(0, 1).toUpperCase() + category.slice(1);
try {
if (dir.size === 0) return;
if (bot.config.owners.includes(message.author.id)) embed.addField(`❯ ${capitalise}`, dir.map(c => `\`${c.help.name}\``).join(", "));
else if (category !== "Developer") embed.addField(`❯ ${capitalise}`, dir.map(c => `\`${c.help.name}\``).join(", "));
}
catch (e) {
console.log(e);
}
});
return message.channel.send(embed);
};
module.exports.help = {
name: "help",
aliases: ["h"],
description: "Help command to show the commands",
usgae: "help (command name)",
category: "Misc",
};
/**
* @author Anish Shobith
* @file commandfileexample.js
* @licence MIT
*/
module.exports.run = async (bot, message, args) => {
// Do Some stuff
};
// Help Object
module.exports.help = {
name: "",
description: "",
usage: "",
category: "",
aliases: [""]
};
const { readdirSync } = require("fs");
const { join } = require("path");
module.exports.run = (bot, message, args) => {
if (!bot.config.owners.includes(message.author.id)) return;
if (!args[0]) return message.channel.send("Please provide a command to reload!");
const commandName = args[0].toLowerCase();
const command = bot.commands.get(commandName) || bot.commands.get(bot.aliases.get(commandName));
if (!command) return message.channel.send("That command doesn't exist. Try again.");
readdirSync(join(__dirname, "..")).forEach(f => {
const files = readdirSync(join(__dirname, "..", f));
if (files.includes(`${commandName}.js`)) {
const file = `../${f}/${commandName}.js`;
try {
delete require.cache[require.resolve(file)];
bot.commands.delete(commandName);
const pull = require(file);
bot.commands.set(commandName, pull);
return message.channel.send(`Successfully reloaded ${commandName}.js!`);
}
catch (err) {
message.channel.send(`Could not reload: ${args[0].toUpperCase()}\``);
return console.log(err.stack || err);
}
}
});
};
module.exports.help = {
name: "reload",
aliases: [""],
description: "",
usage: "",
category: "Developer",
};
@adrianumb
Copy link

why when I try to run the terminal for this cmd it says reload.js | ❌ -> Missing a help.name, or help.name is not a string.

@ducksquaddd
Copy link

why when I try to run the terminal for this cmd it says reload.js | ❌ -> Missing a help.name, or help.name is not a string.

Because the name: "name" either does not exist or does not have "" around it

@agiltriono
Copy link

agiltriono commented Oct 2, 2021

I has been tested this script on node 14.x.x > 16.x.x its running completely but some of base code need to redesign cause this command.help.name are returning all command value.
So i do console logging the method and the yhe return value says it was a from exported command.
While used the command its return this.
help : { name : "hello", aliases: "hai", description: "no desc" } run : Async function anonymous

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment