This Discord bot is designed to be an easy and customizable solution for your servers. Ideal for groups of friends, the bot offers a variety of fun and useful commands that enhance chat experience and community interaction.
.env
and src/config.ts
file.To install and run the bot locally, follow these steps:
Install Node.js and npm from here.
Clone the repository to your local machine:
git clone https://github.com/Sebana02/Sparky.git
Navigate to the project directory:
cd Sparky
Install the dependencies by running:
npm install
Create a .env
file in the root of the project with the following information:
TOKEN=your_discord_bot_token_here
If you don't have a Discord bot token, you can follow this guide to create one.
You can configure other settings in the .env
and src/config.ts
files. For more details, check the Configuration section.
Invite the bot to your server by following this guide.
To start the bot:
npm run start
Alternatively, you can start the bot in development mode:
npm run dev
This will start the bot in development mode. The bot will automatically reload when you save changes to the code.
The bot should now be running and connected to your Discord server! You can now use the bot by typing /
in the chat to see a list of available commands.
To shut down the bot, press Ctrl + C
in the terminal where the bot is running.
The bot has the following configurations through the .env
file, located on the root of the project, although only the TOKEN
is required to run the bot:
Variable | Description |
---|---|
TOKEN |
Discord authentication token (Required). |
TENOR_API_KEY |
API key for the Tenor GIF API (required for GIF commands). You can get one here. |
FFMPEG_PATH |
Path to the ffmpeg binary (if not in PATH variable). Alternative to the pre-installed ffmpeg which is known to be unstable. You can get ffmpeg here. |
Here is an example of a fully configured .env
file:
TOKEN=your_discord_bot_token_here
TENOR_API_KEY=your_tenor_api_key_here
FFMPEG_PATH=path_to_your_ffmpeg_binary_here
You can also configure the bot's behavior in the src/config.ts
file. This file contains various settings that control how the bot operates and general application settings. Here are some of the key settings you can configure:
import { IUserConfig } from './interfaces/config.interface.js';
export const userConfig: IUserConfig = {
locale: 'en_US', // Language of the bot (default: 'en_US -> English')
logPath: 'bot.log', // Path to the log file (default: '.log')
// Guild configuration
guildConfig: {
guildId: 'your_guild_id', // Guild ID where the bot will be used (default: 'None')
ignoreChannels: ['channel_id_1', 'channel_id_2'], // Channel IDs to ignore commands from (default: 'None')
ignoreRoles: ['role_id_1', 'role_id_2'], // Roles to ignore commands from (default: 'None')
welcomeChannelId: 'your_welcome_channel_id', // Welcome channel ID (default: 'None')
djRoleId: 'your_dj_role_id', // DJ role ID (default: 'None')
},
// Client configuration
clientConfig: {
setAFK: false, // Set the bot as AFK (default: false)
setUsername: 'Sparky', // Set the bot's username (default: 'None')
// Add any additional client configuration settings here
},
};
Check the config.interface.ts file for more details on the available configuration options.
Both .env
and src/config.ts
files are not provided in the repository, so you will need to create them manually. The bot will not work without the .env
file, but it will work without the src/config.ts
file. If you don't create it, the bot will use the default values. This is the final structure your project should have:
Sparky
โโโ .env <--- .env file
โโโ src/
โ โโโ commands/
โ โโโ events/
โ โโโ interfaces/
โ โโโ ...
โ โโโ config.ts <--- src/config.ts file
โ โโโ bot.ts
โโโ ...
The bot can be invoked using Discord's slash commands. Sparky offers a variety of commands to interact with it and enhance the chat experience.
These commands are divided into categories based on their functionality, including fun, games, information, moderation, music, and utility.
These commands are designed to add fun and entertainment to the chat experience. They include GIFs, memes, and interactive actions like hugs, pokes, and slaps.
Command | Description | Example | Category | File |
---|---|---|---|---|
/cat |
Sends a random cat GIF | /cat |
GIFs | cat.ts |
/dog |
Sends a random dog GIF | /dog |
GIFs | dog.ts |
/gif <category> |
Sends a random GIF based on the specified category . |
/gif weird |
GIFs | gif.ts |
/hug <user> |
Sends a GIF giving a hug to a specified user . |
/hug @Dave |
GIFs | hug.ts |
/meme |
Sends a random meme GIF. | /meme |
GIFs | meme.ts |
/poke <user> |
Sends a GIF poking a specified user . |
/poke @Dave |
GIFs | poke.ts |
/shutup <user> |
Sends a GIF telling the mentioned user to shut up. |
/shutup @Dave |
GIFs | shut-up.ts |
/slap <user> |
Sends a GIF slapping a specified user . |
/slap @Dave |
GIFs | slap.ts |
/coinflip |
Flips a coin and returns heads or tails. | /coinflip |
None | coin-flip.ts |
/8ball <question> |
Answers a question with a random 8-ball response. |
/8ball Will I win the lottery? |
None | 8ball.ts |
These commands are designed to engage users with fun and interactive games. Users can play hangman, rock-paper-scissors, and tic-tac-toe among other games.
Command | Description | Example | Category | File |
---|---|---|---|---|
/hangman <gamemode> |
Starts a game of hangman. If random gamemode is selected, bot will choose the word. If custom gamemode is selected, one of the players will choose the word. |
/hangman random |
None | hangman.ts |
/rps <opponent> |
Plays a game of rock-paper-scissors against the specified opponent . |
/rps @Dave |
None | rps.ts |
/tictactoe <opponent> |
Starts a game of tic-tac-toe with a specified opponent . |
/tictactoe @Dave |
None | tictactoe.ts |
/trivia <playlist> |
Starts a game of musical trivia with your playlist songs. |
/trivia your_playlist_link_here |
None | trivia.ts |
These commands provide quick insights and information to users, including the bot's uptime and Wikipedia searches.
Command | Description | Example | Category | File |
---|---|---|---|---|
/help |
Displays a list of available commands. | /help |
None | help.ts |
/uptime |
Displays the bot's uptime | /uptime |
None | uptime.ts |
/wikisearch <query> |
Searches Wikipedia for the specified query |
/wikisearch Discord |
None | wiki-search.ts |
These commands help maintain order and control in the server by providing tools for managing users, roles, and channels.
Command | Description | Example | Category | File |
---|---|---|---|---|
/hidechannel [channel] |
Hides the specified channel from view for users, making it inaccessible until unhidden. If no channel is specified, it hides the channel where the command is used. It can be used both on text and voice channels. |
/hidechannel general |
Channel | hide-channel.ts |
/showchannel [channel] |
Unhides the specified channel , making it visible again to users who have access. If no channel is specified, it unhides the channel where the command is used. It can be used both on text and voice channels. |
/showchannel general |
Channel | show-channel.ts |
/mutechannel [channel] |
Mutes the specified channel , preventing users from sending messages in that channel. If no channel is specified, it mutes the channel where the command is used. It can be used both on text and voice channels. |
/mutechannel general |
Channel | mute-channel.ts |
/unmutechannel [channel] |
Unmutes the specified channel , allowing users to send messages once more. If no channel is specified, it unmutes the channel where the command is used. It can be used both on text and voice channels. |
/unmutechannel general |
Channel | unmute-channel.ts |
/purge [amount] |
Deletes a specified amount of messages in the channel, helping to clean up chat clutter. |
/purge 10 |
Channel | purge.ts |
/ban <user> |
Bans a specified user from the server, preventing them from joining or interacting with the server. |
/ban @Dave |
User | ban.ts |
/unban <user> |
Unbans a specified user from the server, allowing them to rejoin and interact with the community. |
/unban @Dave |
User | unban.ts |
/bannedlist |
Displays a list of banned users, providing insight into who is currently banned from the server. | /bannedlist |
User | banned-list.ts |
/kick <user> |
Kicks a specified user from the server, temporarily removing them from the community. |
/kick @Dave |
User | kick.ts |
/mute <user> |
Mutes a specified user in the server, preventing them from speaking in voice channels or sending messages in text channels. |
/mute @Dave |
User | mute.ts |
/unmute <user> |
Unmutes a specified user , allowing them to speak in voice channels and send messages again. |
/unmute @Dave |
User | unmute.ts |
/mutedlist |
Displays a list of muted users, showing who is currently unable to send messages or speak. | /mutedlist |
User | muted-list.ts |
/setnickname <user> <nickname> |
Sets a nickname for a specified user , allowing for personalized identification within the server. |
/setnickname @Dave IamNotDave |
User | set-nickname.ts |
/resetnickname <user> |
Resets the nickname for a specified user to their original username, removing any custom nickname they had. |
/resetnickname @Dave |
User | reset-nickname.ts |
/timeout <user> <reason> <duration> |
Times out a specified user for a reason , for duration minutes, preventing them from sending messages or speaking during that time. |
/timeout @Dave 10 |
User | timeout.ts |
/warn <user> <reason> |
Issues a warning to a specified user , providing a reason for the warning to maintain accountability. |
/warn @Dave Too many infractions |
User | warn.ts |
These commands are designed to control the music player and queue. Users can play, pause, skip, and manage the music queue with these commands.
Command | Description | Example | Category | File |
---|---|---|---|---|
/back |
Plays the previous song in the queue. | /back |
Playback | back.ts |
/clear |
Clears the music queue. | /clear |
Queue | clear.ts |
/loop <mode> |
Loops the current song or queue. Mode can be song , queue ,autoplay or off . |
/loop song |
Playback | loop.ts |
/lyrics |
Fetches and displays the lyrics of the currently playing song. | /lyrics |
Insight | lyrics.ts |
/nowplaying |
Displays information about the currently playing song and the queue. | /nowplaying |
Insight | now-playing.ts |
/pause |
Pauses the currently playing song. | /pause |
Playback | pause.ts |
/play <query> |
Plays a song or playlist from YouTube or a supported URL, including Spotify, Souncloud and other sources. Query can be a URL, a song's name or even an author |
/play greedy |
Playback | play.ts |
/playnext <query> |
Adds a song to the queue to play after the current song. | /playnext Paramore |
Playback | play-next.ts |
/queue |
Shows the current music queue. | /queue |
Queue | queue.ts |
/resume |
Resumes a paused song. | /resume |
Playback | resume.ts |
/save |
Saves the currently playing song to your DMs | /save |
Insight | save.ts |
/shuffle |
Shuffles the songs in the current queue. | /shuffle |
Queue | shuffle.ts |
/skip |
Skips the current song. | /skip |
Playback | skip.ts |
/stop |
Stops the music and clears the queue. | /stop |
Playback | stop.ts |
/volume <level> |
Adjusts the volume of the music player to the specified level (0-100). |
/volume 50 |
Playback | volume.ts |
These commands provide useful tools for managing polls, reminders, and checking the bot's response time.
Command | Description | Example | Category | File |
---|---|---|---|---|
/disconnect |
Disconnects the bot from the voice channel. | /disconnect |
None | disconnect.ts |
/ping |
Checks the bot's response time and latency. | /ping |
None | ping.ts |
/poll <question> <possible answers> <time> |
Creates a poll with the specified question for users to vote on during specified time . |
/poll What's your favorite food? Pizza,Salad,Sushi |
None | poll.ts |
/remind <time> <reminder> |
Sets a reminder for the specified time duration. |
/remind 10m I am a reminder |
None | remind.ts |
Any new command must be created in the commands
folder, as this is where the bot will search for commands. The folder structure can be organized as needed, but it is recommended to create a subfolder for each command category.
Each command must be a .ts
file and must export an ICommand
object with the following properties:
data
(SlashCommandBuilder
):
The Discord command.
voiceChannel
(optional, boolean, default: false
):
Indicates whether the command requires the user to be in a voice channel.
blockedInDMs
(optional, boolean, default: false
):
Indicates whether the command is blocked in DMs.
execute(
client
,
interaction
, ...args)
(async function):
The function executed when the command is invoked
Here is a basic command that replies with a greeting:
import { ICommand } from '@interfaces/command.interface.js';
import { ChatInputCommandInteraction, Client, SlashCommandBuilder } from 'discord.js';
export const command: ICommand = {
data: new SlashCommandBuilder().setName('greetings').setDescription('Greets the user'),
voiceChannel: false,
blockedInDMs: false,
execute: async (client: Client, inter: ChatInputCommandInteraction): Promise<void> => {
await inter.reply('Hello! How can I help you today?');
},
};
The bot uses events to listen for specific actions or triggers and execute functions when those events occur. Events are used to handle various actions, such as when the bot is ready, a user joins the server, or an error occurs. Events are divided into categories based on their emitter, including the client, music player, and process.
The bot uses several events to handle various actions and triggers. These events are divided into categories based on their emitter, including the client, music player, and process.
These events are emitted by the Discord client and are related to the bot's connection and status.
Event | Description | File |
---|---|---|
clientReady |
Emitted when the bot is ready to start receiving commands. | ready.ts |
interactionCreate |
Emitted when an interaction is created. | interaction-create.ts |
guildMemberAdd |
Emitted when a new member joins the server. | guild-member-add.ts |
These events are emitted by the music player and are related to the music player's status and actions.
Event | Description | File |
---|---|---|
emptyQueue |
Emitted when the queue is empty. | empty-queue.ts |
emptyChannel |
Emitted when the bot leaves the voice channel. | empty-channel.ts |
error |
Emitted when an error occurs. | error.ts |
playerError |
Emitted when an error occurs in the player. | player-error.ts |
playerStart |
Emitted when the player starts playing a song. | player-start.ts |
These events are emitted by the process and are related to the node process status.
Event | Description | File |
---|---|---|
exit |
Emitted when the process is about to exit. | exit.ts |
SIGINT |
Emitted when the process receives a SIGINT signal. | SIGINT.ts |
unhandledRejection |
Emitted when an unhandled promise rejection occurs. | unhandled-rejection.ts |
uncaughtException |
Emitted when an uncaught exception occurs. | uncaught-exception.ts |
Any new events must be created in the events
folder as it is the path where the bot will look for events. Inside the folder, any substructure can be followed, as the bot will search for events recursively, although it is recommended to create a folder for each category of events.
'Events' must be .ts
files and must export a IEvent object with the following parameters:
name
(string):
The name of the event to listen to. It must match the name of the event emitted by the emitter (see documentation for each emitter).
emitter
(Emitter):
The emitter of the event. It can take values from the Emitter
enum, which is in the same file as the IEvent
interface. The possible values are:
Process
: Corresponds to the Node process
.Client
: Corresponds to the Discord client
.Music
: Corresponds to the Discord player library
.execute(
client
, ...args)
(async function):
The function executed when the event is triggered.
Here is a basic example of an event that logs when the bot is ready:
import { IEvent, Emitter } from '@interfaces/event.interface.js';
import { Client } from 'discord.js';
export const event: IEvent = {
name: 'ready',
emitter: Emitter.Client,
execute: async (client: Client): Promise<void> => {
console.log(`Logged in as ${client.user.tag}!`);
},
};
In the utils
folder, you can find a series of utility classes that can be used throughout the bot. These functions are designed to help with common tasks and can be used in any part of the bot:
Utility | Description | File |
---|---|---|
CommandErrorHandler |
Wrapper class to handle errors in commands. | error-handler.ts |
EventErrorHandler |
Wrapper class to handle errors occurring in events. | error-handler.ts |
InteractionUtils |
Wrapper class to simplify interaction management. | interaction-utils.ts |
GifUtils |
Utility class to retrieve and send GIFs. | gif-utils.ts |
LanguageUtils |
Functions to retrieve literals from the selected language. | language-utils.ts |
EmbedPresets |
Functions to create embed presets and use them anywhere. | embed-presets.ts |
EmbedUtils |
Functions to create and manage embeds for various purposes. | embed-utils.ts |
The bot includes a logging system that saves logs to a file. The logs are stored in a .log
file in the project root by default, but you can change the file path in the .env
file.
It includes the following log levels:
[30/10/2024, 15:45:17] [info] Loading commands...
[29/10/2024, 15:24:53] [warn] Could not find literal at path "ping.a"
[29/10/2024, 13:56:20] [error] Could not load event "ready"
The logger object is stored in the process object as a global variable so you can use it anywhere in the bot. To log a message, use the following syntax:
// Log an info message
globalThis.logger.info('Loading commands...'); // or
logger.info('Loading commands...');
// Log a warning message
globalThis.logger.warn('Could not find literal at path "ping.a"'); // or
logger.warn('Could not find literal at path "ping.a"');
// Log an error message
globalThis.logger.error('Could not load event "ready"'); // or
logger.error('Could not load event "ready"');
The bot is designed to support multiple languages, allowing users to interact with the bot in their preferred language.
In order to change the bot's language, you need to modify the locale
variable in the src/config.ts
file, using one of the supported languages, which are stored in folders in the locales
directory. Simply copy the name of the desired language folder and set it as the locale
value. The bot will automatically load the corresponding language strings. By default, the bot uses English.
Feel free to add your language by following the instructions below!
To add a new language to the bot, follow these steps:
Create a new folder
: in the locales
directory with the name of the language you want to add, using the IETF BCP 47 format for the language code (e.g., en_US
for English, United States). A list of available language codes can be found in locales.json
Add JSON files
: inside the new folder with every key-value pair, you can follow the structure of the existing languages or follow your own structure, but you have to make sure to include every key-value pair or else some parts may not work. It is recommended to copy the English language files and translate the values to your language.
Set the locale
: in the src/config.ts
file to the name of the new language folder you created. This property will only accept keys included in the locales.json file.
Access literals
: These JSON files will be loaded into the global variable globalThis.literals
. Each key is loaded as a result of concatenating the path of the JSON's structure with .
. The type of the value is determined by the type of the value in the JSON file, and includes strings, numbers, arrays, and functions (for placeholders). Placeholders are represented by ordered numbers inside curly braces (e.g., {0}
, {1}
). If a value in the JSON file contains placeholders, it will be wrapped in a function that replaces the placeholders with the provided values when called.
For example, this JSON:
{
"poll": {
"time": 50,
"question": "What's your favorite food?",
"answers": ["Pizza", "Salad", "Sushi"],
"message": "{0} has started a poll"
}
}
Will be accessed in the bot like this:
globalThis.literals.poll.time; // 50
globalThis.literals.poll.question; // "What's your favorite food?"
globalThis.literals.poll.answers; // ["Pizza", "Salad", "Sushi"]
const message = globalThis.literals.poll.message; // function(message: string) { return `${message} has started a poll`; }
console.log(message('Dave')); // "Dave has started a poll"
Else, you can use the LanguageUtils
functions to retrieve literals from the selected language. This is preferred as it will handle the path concatenation for you and will return the correct type of the value, apart from throwing an error if the literal is not found or if the type is incorrect.
import { fetchFunction, fetchString, fetchNumber, fetchArray } from 'utils/language-utils.js';
const time = fetchNumber('poll.time'); // 50
const question = fetchString('poll.question'); // "What's your favorite food?"
const answers = fetchArray('poll.answers'); // ["Pizza", "Salad", "Sushi"]
const message = fetchFunction('poll.message'); // function(message: string) { return `${message} has started a poll`; }
console.log(message('Dave')); // "Dave has started a poll"
As a recommendation, it is better to fetch the literals that will be used in a command/event at the beginning of the file and store them in a variable to avoid multiple calls to the fetch
functions.
IMPORTANT: If you fail to see some literal in your language and it happens to be in US English, it means that the key is missing in your language files. You can add it by copying the key from the US English file and translating the value to your language.
The bot is designed to handle errors and unexpected behavior gracefully. If an error occurs, the bot will log the error and send a message to the user indicating that an error occurred. The bot will continue to run and respond to commands and events, even if an error occurs.
If you encounter any issues while running the bot, here are some common troubleshooting steps:
npm update
.Feel free to contribute by submitting issues or pull requests! All contributions are welcome and appreciated.
This project is licensed under the MIT License. See the LICENSE file for details.