I Deployed My First Discord Bot!

I wrote and developed my first Discord Bot with Python. I successfully deployed it on Heroku, making sure that it runs all-day long, without me having to run the script on my own computer. In this blog, I tell you about what my bot does and how I did it.

I took up a weekend project to build my own Discord bot with Python. If you dont know what Discord is, it is an instant messaging and VoIP application that enables users to create guilds(commonly known as servers) and allows them to have multiple voice channels in them as well. As a gamer, reliable communication while in-game is key to ensuring a win. And Discord's services offer reliable comms for my team, making it easier for me carry my team to victory.

Among Discord's bag of tricks, one of my favorite is that it allows users to add Bots to the guild. A Bot is basically a computer program that is built to perform actions assigned to them by its developer. For example, the Rhythm Bot allows a user to play songs in the voice channel that he is currently in. These Bots are invoked by a pre-assigned command, followed by arguments. There are a plethora of Bots that you can find online that do just about everything you command it to. Infact, when I was searching for the right Bot for me, I was faced with the problem of too many choices. Instead, I chose to build my own Bot.

About my Discord Bot.

One of the most common things that you'd get to read about my guild's conversations is that we deerank a lot in our games. The opponent team always has someone who's cheating (we're just really bad). Keeping with this trend, I named my bot as DeeRank.

The next thing I had to focus on is what DeeRank would be able to do for you(the user). After some thinking, googling and asking around, I came up with a short list of things I'd program it to do.
To speak to DeeRank, you'd have to precede the command with > symbol.
Here's a list of the Bot's functionalities:

  1. Commands only for Admin
    • kick
    • ban
    • leave
  2. Commands for Everyone
    • 8ball
    • dad_joke
    • df
    • memez
DeeRank has got quite the potty mouth and wouldn't handle mistakes very well. Just keep that in mind if you plan on adding it to your guild.

A Close Look At The Bot's Code.

  • Entry Point

    Discord has made it very simple to interact with their API by publishing the discord.py package. The discord.py package is a Python wrapper for Discord's API. The package provides all the extensions and functions needed to write commands that can be issued to the Bot. This is imported from discord.ext.

    The first step is to create an instance of the discord bot. Over here, my Bot is named as deerank and this serves as the client which interacts with the discord API. The commands_prefix parameter if to specify what the prefix is to be used when the Bot is invoked by a user.

    A very useful feature of discord.py is that it allows for the usage of Cogs. Each cog is a Python class that subclasses commands.Cog and allows me to organise a collection of commands, listeners, and some state into one class. Cogs are thus classes which need to be loaded to be used and unloaded to be removed from the Bot's functionality. The load and unload function enables this functionality.

    To run the program, the Bot needs to get authorisation from discord, to be able to interact with the API. For this, it has to connect to the discord server's using it's own Token. The Token, I stored in another file, to keep it hidden. The file reading code is to read the file and retrieve this Token before it runs the program.

  • Commands For The Admin

    DeeRank has some Administrator functionalities and these commands can be invoked only by the admin of the guild to avoid any conflicts and abuse of these Bot commands.
    Command handlers as functions are responsible for executing commands issued to the Bot. @commands.command() of the commands extension from discord.py provides support for this.
    The Bot is able to read the commands issued to it due to the context of the message being fed to it as a parameter of this command. This parameter is ctx. The context parameter is essential for functionality, as it allows for Bot to interact with the guild. With ctx, the Bot sends messages to the server and that channel with ctx.send(). Through ctx, the Bot is able to extract valurable information such as, the user who issued the command, the guild that the user belongs to, the userID, etc..

    1. >kick

      Parameters: {member: Required}

      With this, the admin can kick a member out of the guild. When a user issues this command, the bot first authenticates and makes sure that the issuer is the admin of the guild. If not, the Bot replies with a message asking the user to contact the admin to issue the command. The bot verifies this by checking whether the issuer's ID and the guild's ID is the same or no. On the other hand, if the admin is the one who issued to command, then the Bot immediately kicks the member out of the guild and follows with a cheeky message saying that the player has been DeeRanked. In case the Bot encounters any errors while carrying out this command, it invokes the kick_error() error handler. This error handler is responsible for checking whether it is a known or unknown error. The two known probable errors here are: commands.BadArgument and commands.MissingRequiredArgument.
      The commands.BadArgument is matched when the command parameter doesn't contain the name of a person in the guild.
      The commands.MissingRequiredArgument is matched when the issuer forgets to include the name of the member they wish to kick from the guild.
      If it isn't among these two, the Bot logs the error for me and reports the same.

    2. >ban

      Parameters: {member: Required}

      This command invokes the Bot to ban a member from the guild, disallowing them to join the guild again. The functionality and the code of this command is almost entirely the same as that of >kick command. The only difference is that, the Bot executes the member.ban() command instead of the member.kick command.

    3. >leave

      Parameters: {None}

      When this command is issued by the admin of the guild, it forces the bot to go offline, making it unavailable to accept commands from users.

  • Commands For Everyone

    These are the few commands that can be run by anyone, regardless of their role in the guild. Each command has it's own error handling listeners and functions just like those of the admin's commands.

    1. >8ball

      Parameters: {question: Required}

      If you aren't familiar with the magic 8 ball, it is a "fortune" teller which will give out a random output when shook. With this command, the Bot mimics 8ball's functionality, by spitting out a random output from a list of 20 predetermined outputs. The outputs are saved in the list responses and uses the random.choice function to get a random output. The async with ctx.channel.typing() makes the bot appear in the discord app as if it is typing, thus, mimicing a user while he/she is constructing his message. This way the bot provides feedback to the user while it is carrying out the command.

    2. >df

      Parameters: {member: required}

      I spent some time in gathering making a list of shakespearen english insults.. The Bot, when commanded, would pick out a random insult from this list and direct this insult towards that member that was mentioned in the command. I stuck to shaespearen insults as a throwback to my school days, when we had shakespear's "As You Like It" play as a part of my curriculum. And also, they're absolutely hilarious.

    3. >memez

      Parameters: {subreddit: Optional}

      To get memes from reddit, I used the praw library, which is the Python Reddit API Wrapper. The user can choose to give a specific subreddit that they wish to retrieve a meme from. If not, the Bot has a list of predefined subreddits and it chooses one a random, to fetch a meme from.

    4. >dad_joke

      Parameters: {None}

      All of us hate that we laugh at the lamest dad jokes. I wanted my Bot to have the functionality of lightening up someone's day by giving out dad jokes whenever they wanted. With this, the Bot presents the user with a dad joke that it retrieved from the internet. To retrieve a dad joke, the Bot accesses any one of the two APIs that I found online. With the requests library of Python, the Bot is able to retrieve JSON data from these APIs and extract it's contents. As the API from rapidapi.com allows for only 50 requests per day, I added in the icanhazdadjoke API too. This way, the Bot can always ensure that the user gets their new favorite dad joke and isn't let down.

Deploying The Bot!

To have DeeRank running 24x7, I couldn't keep the script running all the time on my computer. For this reason, I needed to deploy it on a server. To make this possible, I chose to host my Discord Bot on Heroku.

Heroku is a cloud platform that lets you build, deliver, monitor and scalre apps. Heroku provides us with an option to host applications for free. The limitation being that it would work for only 1000 active hours in a month. This is more than enough to host a personal Discord Bot.

That's All Folks!!!

Thank you for making it to the end of this blog. I had a lot of fun while learning to build this Discord Bot. I learned and used a few new techniques like decorators, using the ASYNCIO library and interacting with the Discord API. Infact, this is my first application that I have successfully deployed online and is available for use by anyone. If you'd like to give DeeRank a try in your own guild, click on the button below:

All of DeeRank's code is availabe on my GitHub.

Have a great day!

References

Discord.py Documentation
Discord Bot With Python
Deploying Bot To Heroku