Customization Guide
In this guide you will learn how to customize your bot to change the features or add new ones.
Project Structure
Everything in the bot is contained within a src
folder, this contains all of the source code for the bot. The src
folder is then divided into several folders:
📦src // Main Source File
┣ 📂commands // Source for all commands
┃ ┣ 📜config.ts
┃ ┣ 📜gCreate.ts
┃ ┣ 📜gEnd.ts
┃ ┗ 📜gReRoll.ts
┣ 📂database // Database Management
┃ ┣ 📂data // Actual Database
┃ ┃ ┣ 📜database.db
┃ ┃ ┣ 📜database.db-shm
┃ ┃ ┗ 📜database.db-wal
┃ ┣ 📜dbManager.ts
┃ ┣ 📜guildManager.ts
┃ ┗ 📜gwManager.ts
┣ 📂events // Event manager
┃ ┣ 📜guildCreate.ts
┃ ┣ 📜interactionCreate.ts
┃ ┗ 📜ready.ts
┣ 📂handlers // Starting routines
┃ ┣ 📜Command.ts
┃ ┗ 📜Event.ts
┣ 📜functions.ts // Utility Functions
┣ 📜index.ts // Initial File
┗ 📜types.d.ts
Editing Existing Commands
Commands in the bot are stored in the 📂src/commands
folder. Each command is implemented as a separate file, following the structure of Discord.js interactions.
Step 1: Locate the Command File
For example, the gCreate
command (used for starting a giveaway) is in src/commands/gCreate.ts
. Open this file to view and modify the command's logic.
Step 2: Modify the Command Logic
Commands are typically structured like this:
import {
SlashCommandBuilder,
} from "discord.js";
import { SlashCommand } from "../types";
import GuildManager from "../database/guildManager";
import GiveawayManager from "../database/gwManager";
const command: SlashCommand = {
command: new SlashCommandBuilder()
.setName("gend")
.setDescription("End a giveaway early")
.addStringOption((option) =>
option
.setName("messageid")
.setDescription("The message ID of the giveaway")
.setRequired(true)
)
.addBooleanOption((option) =>
option
.setName("selectwinners")
.setDescription("Whether to select winners or not")
.setRequired(false)
),
execute: async (interaction) => {
const giveawayId = interaction.options.getString("messageid");
const selectWinners =
interaction.options.getBoolean("selectwinners") || false;
const gw = new GiveawayManager();
const guild = new GuildManager();
const giveaway = gw.fetchGiveaway(giveawayId!);
if (!giveaway) {
return interaction.reply("Invalid giveaway ID");
}
// Your custom giveaway ending logic
await interaction.reply("Giveaway ended!");
},
};
export default command;
To customize:
- Modify the command description or options.
- Update the logic inside the
execute
function to change how the command behaves.
Example: Adding a Winner Count Option
To add an option for specifying the number of winners:
- Add the new option to the command:
.addNumberOption((option) =>
option.setName("winners").setDescription("Number of winners").setRequired(false)
);
- Update the logic in the
execute
function:
const winners = interaction.options.getNumber("winners") || 1; // Default to 1 winner
await interaction.reply(
`🎉 Giveaway for **${prize}** started! Duration: ${duration} minutes, Winners: ${winners}.`
);
Creating New Commands
Adding new commands to the bot is easy! Follow these steps:
Step 1: Create a New Command File
- Go to the
src/commands
folder. - Create a new file with a descriptive name, such as
gStatus.ts
.
Step 2: Define the Command Structure
Use the following template for a new command:
import {
SlashCommandBuilder,
} from "discord.js";
import { SlashCommand } from "../types";
const command: SlashCommand = {
command: new SlashCommandBuilder()
.setName("gstatus")
.setDescription("Check the status of currently running giveaways")
execute: async (interaction) => {
// Your Logic Here
await interaction.reply("Here are the currently active giveaways...");
}
}
export default command;
Step 3: Implement the Logic
For example, if you want to list active giveaways:
import GiveawayManager from "../database/gwManager";
const gwManager = new GiveawayManager(); // You must make a new instance of the class
export async function execute(interaction: CommandInteraction) {
const giveaways = await gwManager.getActiveGiveaways(); // Custom function in `gwManager.ts`
if (giveaways.length === 0) {
return interaction.reply("No active giveaways found.");
}
const giveawayList = giveaways
.map((gw) => `🎁 **${gw.prize}** - Ends in ${gw.duration} minutes.`)
.join("\n");
await interaction.reply(`Active Giveaways:\n${giveawayList}`);
}
Step 4: Register the Command
The command will be automatically registered using the command handler!
Extending Functionality
To extend the bot's capabilities, you can customize database logic, add utilities, or modify existing events.
Extending Database Logic
- Location:
src/database
- Example: Add a new function in
gwManager.ts
to fetch giveaways by guild:
export async function getGiveawaysByGuild(guildId: string) {
return this.selectAll("SELECT * FROM giveaways WHERE guildId = ?").all(guildId);
}
- Use this new function in a command or event to add guild-specific features.
Adding Utilities
- Location:
src/functions.ts
- Example: Create a utility to format timestamps:
export function formatTime(timestamp: number): string {
const date = new Date(timestamp);
return date.toLocaleString();
}
- Use this utility in commands or database queries.
Enhancing Events
- Location:
src/events
- Example: Add a new event in
guildCreate.ts
to initialize guild settings:
import { Guild } from "discord.js";
import { BotEvent } from "../types";
import { color } from "../functions";
import GuildManager from "../database/guildManager";
const database = new GuildManager();
const event: BotEvent = {
name: "guildCreate",
execute: (guild: Guild) => {
database.createGuild(guild.id);
console.log(
color(
"text",
`🌠 Successfully created guild ${color("variable", guild.name)}`
)
);
},
};
export default event;
Handlers in the Bot
Handlers in the bot are responsible for organizing and automating the process of loading commands and events. By using handlers, you ensure that the bot dynamically reads all commands and events from their respective directories, making it easy to add new functionality without manually modifying the core bot file.
Command Handler
The command handler is responsible for registering and managing all the commands in the bot. It dynamically loads all command files from the 📂src/commands
directory and registers them with Discord.
How It Works
Here’s an example implementation of the command handler:
import { Client, Routes, SlashCommandOptionsOnlyBuilder } from "discord.js";
import { REST } from "@discordjs/rest";
import { readdirSync } from "fs";
import { join } from "path";
import { color } from "../functions";
import { SlashCommand } from "../types";
module.exports = (client: Client) => {
const slashCommands: SlashCommandOptionsOnlyBuilder[] = [];
let slashCommandsDir = join(__dirname, "../commands");
// Dynamically read all files in the commands folder
readdirSync(slashCommandsDir).forEach((file) => {
if (!file.endsWith(".js")) return; // Ensure only JS files are loaded
let command: SlashCommand =
require(`${slashCommandsDir}/${file}`).default;
// Add the command to the slashCommands array for registration
slashCommands.push(command.command);
// Map the command to the client's collection for later use
client.slashCommands.set(command.command.name, command);
});
// Register the commands with Discord using the REST API
const rest = new REST({ version: "10" }).setToken(process.env.TOKEN);
rest.put(Routes.applicationCommands(process.env.CLIENT_ID), {
body: slashCommands.map((command) => command.toJSON()),
})
.then((data: any) => {
console.log(
color(
"text",
`🔥 Successfully loaded ${color(
"variable",
data.length
)} slash command(s)`
)
);
})
.catch((e) => {
console.log(e);
});
};
Adding a New handler
If you want a function to be ran on bot load, you can create it as a new handler.
- Create a file
Logging.ts
in the📂src/handlers
folder.
import { Client } from "discord.js";
import { readdirSync } from "fs";
import { join } from "path";
import { color } from "../functions";
import { BotEvent } from "../types";
module.exports = (client: Client) => {
let eventsDir = join(__dirname, "../events/logging");
let num = 0;
readdirSync(eventsDir).forEach((file) => {
if (!file.endsWith(".js")) return;
let event: BotEvent = require(`${eventsDir}/${file}`).default;
event.once
? client.once(event.name, (...args) => event.execute(...args))
: client.on(event.name, (...args) => event.execute(...args));
num++;
});
console.log(
color(
"text",
`🌠 Successfully loaded ${color("variable", num)} logging event(s)`
)
);
};
-
The event handler will automatically load any logging events in the
📂src/events/logging
folder and register them. -
You can now create new logging events in the
📂src/events/logging
folder and they will be automatically loaded by the handler
You can use handlers for more complicated functions but this is a good starting point.
Registering Commands with Discord
After editing or adding commands, don’t forget to re-load your discord bot to view the new commands:
npm run build
npm run start
This updates the bot’s commands on Discord.
Testing Your Changes
Once satisfied, build and start the bot in production mode:
npm run build
npm start
By following this guide, you can easily customize the Giveaway Bot template to meet your needs, add new features, or improve existing ones. Have fun coding! 🎉