Creating a Simple Discord Bot With Discord.js

In this post, I will walk you through the steps to create a simple bot for your Discord server using the discord.js module. discord.js is a node.js module that allows you to easily communicate with the Discord API. More information can be found on the discord.js website which touts the module as being very usable and consistent while also providing 100% coverage of the Discord API.

There are quite a few tutorials out there on making Discord bots but I ended up using a few different sources, from blog posts to StackExchange questions, to get my simple bot up and running. Therefore, I decided to congregate my findings into a single comprehensive post.

Intent

My intent was to create a bot that did anything just to get the hang of working with the Discord API. Being a big fan of Mount & Blade: Warband (it is the most played game in my Steam library) I decided to create a bot that would announce the number of days until the release of its sequel, Mount & Blade II: Bannerlord.

For those unaware, within the Mount & Blade community, the release date is somewhat of a meme. The game was announced in 2012 and has been in development ever since. Only recently was a soft release date of “March 2020” announced. Prior to the announcement of the release date, community members would joke about waiting for the game to be released, similar to what’s done with Half-Life 3.

Creating the Bot

1. Downloading node.js

Node.js is a powerful JavaScript runtime designed to build highly scalable network applications. It is a server-side platform built on Google Chrome’s V8 Engine. The framework can be downloaded here which should allow you to install node.js and run its default package manager, npm, from the terminal in your environment (Windows, Linux, or MacOS).

2. Create Bot Directory/Files

To keep things organized we’ll create a single folder to hold all of the files for our bot; three files in total. Choose a name and location for your bot’s directory, I chose the name BannerBot for pretty much everything in this project. We need 3 files for this bot: auth.json, bannerbot.json, and bannerbot.js.

3. Installing Dependencies

The bot we’re going to create depends on discord.js (described above) and winston. winston is a universal logging library that supports multiple transports (i.e. storage devices to write logs to). However, winston can be excluded from the dependency list, if you wish, since we will be outputting our logging information to the console which can be done with JavaScript’s console.log(…) method.

To install these dependencies, open up your terminal and execute the following command:

npm install winston discord.js

NOTE: Before installing the dependencies make sure that you’re in the directory where you intend to store the bot’s files.

4. Creating the Bot

To run the bot you will need a few tokens from Discord which allow you to use Discord’s API. You will need to start by creating an application on your Discord developer page:

https://discordapp.com/developers/applications/

On this page, select New Application and name your application, I called mine BannerBot. (Although my brother thought this was a bot I would be using to ban people when I’d first added it to my Discord server, so name responsibly.)

Once you have an application setup, you should be able to select the Bot option on the right-hand menu:

5. Authorization Tokens

To use discord.js’s hooks into the Discord API we will need to obtain the bot’s token. This token is, by default, hidden since it is supposed to be private to the developer. This should be kept a secret from everyone except for yourself, because of this we will actually keep the token in a file separate from the bot’s logic which you should safeguard.

The key we’re interested in is found on the Bot tab in the right-hand menu under the bot’s username:

From here go ahead and click Copy or reveal the token and copy it with keyboard/mouse.

6. Add the Bot to Your Server

Now, the bot must be added to your Discord server. To do so, you will need the client ID from your Discord dashboard. Below you can see where your client ID is located.

The following URL can be used to add the bot to your server(s)

https://discordapp.com/oauth2/authorize?&client_id=CLIENTID&scope=bot&permissions=8

where CLIENTID is replaced by the client ID you copied above. If the bot is successfully added there should be a message in your Discord server (by default) and it should show up as a user on the right-hand side of the server.

7. Bot Logic and JSON Config Files

Below, the file structure defined in section 2 will be explained and the three files we need will be created and completed.

auth.json: this file holds the token for our bot which is supposed to be private. The contents of the file should be:

{
     "token" : "YOUR TOKEN HERE"
}

bannerbot.json: contains the configuration of the Discord bot. The content of mine is below, yours might look a little different.

{
	"name": "bannerbot",
	"version": "1.0.0",
	"description": "M&B Bannerlord Countdown",
	"main": "bannerbot.js",
	"author": "A. Morast",
	"dependencies": {}
}

bannerbot.js is the bread and butter of the bot. This file contains the JavaScript logic that lets the bot login to Discord, find the difference between today and the Bannerlord release date (on the right occasion), and send the message to a particular Discord chat channel. The start of the file should look something like this:

require('discord.js');
var auth = require('./auth.json');
var logger = require('winston');
var client = new Discord.Client( {token:auth.token, autorun: true } );

const deployGuildID = "SERVER ID";
const deployGeneralID = "TEXT CHANNELD ID";

// add the console as a transport
logger.remove(logger.transports.Console);
logger.add(new logger.transports.Console, {colorize:true});
logger.level = 'debug';

Here you will need to replace the SERVER ID and TEXT CHANNEL ID strings with the actual IDs of your server and desired text channel. These can be obtained by right-clicking on the server and channel names in Discord, respectively. At the bottom of the right-click menu is the option Copy ID, this will copy the ID to the clipboard so you can replace these strings in the code above.

Other than that, this chunk of code is just setup. It loads the few libraries we need as well as grabbing our authentication token for the bot. Then it configures the logger by adding the Console transport. As previously mentioned the logger can be skipped/replaced.

Next, we will need to define some callbacks for when certain events happen with the Discord client object.

client.on('ready', function(evt) {
    logger.info('Connected');
    logger.info('Logged in as: ');
    logger.info(client.username + ' - (' + client.id + ')');
    var dayMilliseconds = 1000 * 60 * 60 * 24;
    setInterval(function() {
        sendBannerDate();
    }, dayMilliseconds);
})

client.on('message', msg => {
    message = msg.content;
    if(message.substring(0, 1) == '!') {
	var args = message.substring(1).split(' ');
	var cmd = args[0];
	args = args.splice(1);
	switch(cmd) {
	    case 'when':
		sendBannerDate();
		break;
            // add more cases here for other commands starting with '!'
        }
    }
});

This chunk of code defines what to do when the client is ready (logged in and set up) and a message is received in the Discord server where the bot is running.

When the bot first becomes ready we are going to log something to know that we’re ready and then set up a function that gets called every 24 hours. This function calls a separate function to print the days until Bannerlord is released (defined later).

The next callback, message, is called whenever a message is sent in the Discord server where the bot is installed. This function is going to find messages that start with an exclamation point and performs an action depending on the following text. In this case if a user types !when into a text chat the bot will respond with the number of days until the release date.

Next, we need a function to actually send the message. Note that this will only send the message to the server/channel combination defined in the variables above, not in the server/channel that the message is typed.

function sendBannerDate() {
    var today = new Date();
    var release = new Date('03/01/2020');
    var diffTime = Math.abs(release - today);
    var diffDays = Math.ceil(diffTime / (1000  * 60 * 60 * 24));
	
    var guild = client.guilds.get(deployGeneralID );
    if(guild && guild.channels.get(deployGeneralID)) {
        guild.channels.get(deployGeneralID).send(diffDays + " days until Bannerlord.");
    }
}

This logic calculates the time (in days) between the current date and March 1st, 2020, the ‘release date’ of Bannerlord. Then, “<number_days> days until Bannerlord.” is printed to the designated chat.

Lastly, we need to have the bot actually log in to Discord to start listening for and printing messages. This is done via

// login to Discord
client.login(auth.token);

That should be everything we need to get the bot up and running. The full code can be found at the bottom of this post.

8. Run the Bot

Now that we have the logic in place the configuration files set up it’s time to run our bot. To do so, open a terminal on your system of choice, navigate to the bot’s directory, and type

node ./bannerbot.js

This should fire up the bot and display a few log messages once the bot is ready. Now you should be able to type !when in your Discord server to see the number of days until Bannerlord’s release.

A couple of ways to extend the bot is to add additional switch statement cases for different commands preceeded by an exclamation point and to more intelligently decide where to print the bot’s messages.

Cheers!

9. Full Code

require('discord.js');
var auth = require('./auth.json');
var logger = require('winston');
var client = new Discord.Client( {token:auth.token, autorun: true } );

const deployGuildID = "SERVER ID";
const deployGeneralID = "TEXT CHANNELD ID";

// add the console as a transport
logger.remove(logger.transports.Console);
logger.add(new logger.transports.Console, {colorize:true});
logger.level = 'debug';

client.on('ready', function(evt) {
    logger.info('Connected');
    logger.info('Logged in as: ');
    logger.info(client.username + ' - (' + client.id + ')');
     var dayMilliseconds = 1000 * 60 * 60 * 24;
	setInterval(function() {
		sendBannerDate();
	}, dayMilliseconds);
})

client.on('message', msg => {
	message = msg.content;
	if(message.substring(0, 1) == '!') {
		var args = message.substring(1).split(' ');
		var cmd = args[0];
		args = args.splice(1);
		switch(cmd) {
			case 'when':
				sendBannerDate();
				break;
	}
});

function sendBannerDate() {
	var today = new Date();
	var release = new Date('03/01/2020');
	var diffTime = Math.abs(release - today);
	var diffDays = Math.ceil(diffTime / (1000  * 60 * 60 * 24));
	
	var guild = client.guilds.get(deployGeneralID );
	if(guild && guild.channels.get(deployGeneralID)) {
		guild.channels.get(deployGeneralID).send(diffDays + " days until Bannerlord.");
	}
}

// login to Discord
client.login(auth.token);

Leave a Reply

Your email address will not be published. Required fields are marked *