Event handlingโ
This page requires a valid main file, at least one command from creating commands, and the command handler in place. It applies to both slash commands and message commands.
Before you continueโ
Assuming you've followed the guide so far, your project directory should look something like this:
discord-bot/
โโโ node_modules/
โโโ src/
โ โโโ commands/
โ โ โโโ music/
โ โ โโโ play.js
โ โโโ config.js
โ โโโ index.js
โโโ package-lock.json
โโโ package.json
Loading event filesโ
Remove any existing client.on() calls from index.js. Then add the following event loader right after the command-loading section:
const loadEvents = (folderPath) => {
const eventFiles = fs.readdirSync(folderPath);
for (const file of eventFiles) {
const filePath = path.join(folderPath, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
loadEvents(filePath);
} else if (file.endsWith(".js")) {
const event = require(filePath);
if (event.once) {
if (filePath.includes(`${path.sep}magmastream${path.sep}`)) {
client.manager.on(event.name, (...args) => event.execute(client, ...args));
} else {
client.once(event.name, (...args) => event.execute(client, ...args));
}
} else {
if (filePath.includes(`${path.sep}magmastream${path.sep}`)) {
client.manager.on(event.name, (...args) => event.execute(client, ...args));
} else {
client.on(event.name, (...args) => event.execute(client, ...args));
}
}
console.log(`[INFO] Loaded event: ${event.name}`);
}
}
};
const eventsPath = path.join(__dirname, "events");
loadEvents(eventsPath);
This uses the same recursive pattern as the command loader. Files inside an events/magmastream/ subfolder are registered on client.manager; all others are registered on client.
You can review the complete index.js on the GitHub repository here .
Event file structureโ
Create an events/ folder inside src/ with two subfolders: discord/ and magmastream/.
Select the tab below for the events relevant to your setup.
- Discord events
- MagmaStream events
Create raw.js, ready.js, and interactionCreate.js inside events/discord/. If you are using message commands, also create messageCreate.js.
- events/discord/ready.js
- events/discord/interactionCreate.js
- events/discord/raw.js
- events/discord/messageCreate.js
const { Events } = require("discord.js");
module.exports = {
name: Events.ClientReady,
once: true,
async execute(client) {
await client.manager.init({ clientId: client.user.id });
console.log(`[INFO] Ready! Logged in as ${client.user.tag}`);
},
};
const { Events, MessageFlags } = require("discord.js");
module.exports = {
name: Events.InteractionCreate,
async execute(client, interaction) {
if (!interaction.isChatInputCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) {
console.error(`No command matching ${interaction.commandName} was found.`);
return;
}
try {
await command.execute(client, interaction);
} catch (error) {
console.error(error);
if (interaction.replied || interaction.deferred) {
await interaction.followUp({ content: "There was an error while executing this command!", flags: MessageFlags.Ephemeral });
} else {
await interaction.reply({ content: "There was an error while executing this command!", flags: MessageFlags.Ephemeral });
}
}
},
};
const { Events } = require("discord.js");
module.exports = {
name: Events.Raw,
async execute(client, data) {
// Required by MagmaStream when not using a provided wrapper
await client.manager.updateVoiceState(data);
},
};
const { Events } = require("discord.js");
const config = require("../../config.js");
module.exports = {
name: Events.MessageCreate,
async execute(client, message) {
if (message.author.bot) return;
if (!message.content.startsWith(config.prefix)) return;
const args = message.content.slice(config.prefix.length).trim().split(/ +/);
const commandName = args.shift().toLowerCase();
const command = client.commands.get(commandName);
if (!command) return;
try {
await command.message(client, message, args);
} catch (error) {
console.error(error);
await message.reply(`An error occurred while executing the command: ${error.message}`);
}
},
};
Create nodeConnect.js, trackStart.js, and queueEnd.js inside events/magmastream/.
- events/magmastream/nodeConnect.js
- events/magmastream/trackStart.js
- events/magmastream/queueEnd.js
const { ManagerEventTypes } = require("magmastream");
module.exports = {
name: ManagerEventTypes.NodeConnect,
execute(client, node) {
console.log(`[NODECONNECT] Connected to node ${node.options.identifier}`);
},
};
const { ManagerEventTypes } = require("magmastream");
module.exports = {
name: ManagerEventTypes.TrackStart,
async execute(client, player, track) {
const channel = client.channels.cache.get(player.textChannelId);
if (!channel) return;
channel
.send(`Now playing: \`${track.title}\`, requested by \`${track.requester.username}\`.`)
.catch((error) => console.log(`[TRACKSTART] Failed to send message to channel: ${player.textChannelId}`));
},
};
const { ManagerEventTypes } = require("magmastream");
module.exports = {
name: ManagerEventTypes.QueueEnd,
async execute(client, player, track) {
const channel = client.channels.cache.get(player.textChannelId);
if (!channel) return;
channel
.send("Queue has ended!")
.catch((error) => console.log(`[QUEUEEND] Failed to send message to channel: ${player.textChannelId}`));
},
};
Your project directory should now look like this:
discord-bot/
โโโ node_modules/
โโโ src/
โ โโโ commands/
โ โ โโโ music/
โ โ โโโ play.js
โ โโโ events/
โ โ โโโ discord/
โ โ โ โโโ interactionCreate.js
โ โ โ โโโ messageCreate.js
โ โ โ โโโ raw.js
โ โ โ โโโ ready.js
โ โ โโโ magmastream/
โ โ โโโ nodeConnect.js
โ โ โโโ queueEnd.js
โ โ โโโ trackStart.js
โ โโโ config.js
โ โโโ index.js
โโโ package-lock.json
โโโ package.json
Next stepsโ
Add more events by creating new files in the relevant subfolder. Next, create a deployment script to register your slash commands with Discord.
Resulting codeโ
You can review the complete example on the GitHub repository here .