Creating the Bots on Developer Portal
As I mentioned last week, the dragon translators shall be our first bots.
Before coding the bots, we need to establish discord applications using
the Discord Developer Portal. You can connect to the portal
at https://discord.com/developers/applications. On the developer portal, there should be a button to create a new
application. The application is more of a container for the bot, as we need to
actually add our bot to the application we created.
After selecting your application you should see
a bot tab. Within this tab there is a button to add a bot
to your application.
Warning! Discord refuses to create bots with generic
names!
After a successful bot is created you will now have access to a bot
token. KEEP THIS TOKEN SAFE AND PRIVATE! As shown in the picture above, you can regenerate the token if
compromised. While I am not an expert on security, someone with
malicious intent could repurpose your bot should they have the token. We
will be storing all secret API keys and tokens inside ".env" files. The
".env" approach avoids exposing sensitive data in your code.
Designing Dovahzul
At this point we can begin designing our bot. This is technically an
optional section if you are a design-as-you-go type of person. Before
writing any code, I prefer to answer a few questions about my bot.
Who is my audience? (What communities/servers will the bot be
invited too)
Members of the Discord Bot Army discord server.
What actions will my bot perform?
There will be one command to translate English messages to Dovahzul
using a translator API. The bot will reply to the user which
submitted the commanded using discord mentions.
What is the identity of my bot?
Given Dovahzul is from Elder Scrolls, the bot will portray itself as a non-player character from that fictional universe.
What is the intended scale of the application?
Small and solely developed for learning purposes.
There are more questions that can be asked, but these 4 will generally suffice. The design for the dovahzul bot is rather simple. There is going to be a single command for translating message. Commands are typically entered with a single character prefix such as "!" or "$". Discord already as its own set of "slash" commands that are available to any users.
Note: Permission to use slash commands are generally restricted in discord servers.
Rather than implementing slash commands, Dovahzul and the rest of my
bots will use the "!" prefix. Designing the bot to be configurable is an
option, but this would add significant overhead to the project. Should
the bot be intended for public use, configurability is quite important.
The ability to change prefixes reduces the conflictions with other bots
which use the same prefix.
Node: The Workspace
|
|
| Project File Tree |
Assuming you have NodeJS installed on your machine, you run the
npm init -y command in your terminal to initialize the node
project. Make sure you are in your desired root directory before running
the command. A package.json should be visible in the root
directory of your project. My root directory is "dovahzul-node".
In the root I created a .env file to store our environment variables as
well as a "src" folder. Within the "src" folder I created a
"bot.js" file which will server as the entry point of the
application.
There are a few packages I needed to install before really beginning to
code the bot. The dependencies are "discord.js", "axios", and "dotenv".
Optionally, "nodemon" is another package I installed to quickly debug
code. You can install packages with the command
npm i <package_name>.
After successfully installing the packages, your package.json
should include key-value pairs for your dependencies. You should
also see a new node_modules folder in your root
directory.
|
|
| package.json |
Looking closely at the scripts section of the package.json, you
may notice mine is different. There are two custom scripts which allow
me to run the project with either nodemon or node. The command
npm run dev, or if you have yarn installed, yarn dev, will run the project in nodemon mode. This restarts the bot after any
lines of code are changed, which makes for a better workflow.
In the ".env" file, you should have your variables formatted as follows:
Node: discord.js
Because the project is setup, I can now program the Dovahzul bot using the
discord.js library. You can find the documentation for the library at https://discord.js.org/#/docs/main/stable/general/welcome.
The discord.js library acts as an interface between discord and your bot.
Using this library you can control all your bot's actions. We can see in the
documentation there are many events to our disposal. The key event for this
bot will be the messageCreate event, which you can see is
in the Client class here: https://discord.js.org/#/docs/main/stable/class/Client?scrollTo=e-messageCreate. For those proficient with JavaScript, you may recognize the Client class is
an EventEmitter. As an event emitter, Client has access to
two new methods not articulated in the discord.js documentation. Those being
the "on" and "off" methods. While I could write an entire post about emitters,
I will spare you the details since this is not a "Learn JavaScript Blog".
Using the "on" method we create a listener to the event being emitted.
With listeners, we can handle any events that are
emitted with an anonymous function. For reference, the events tab in the
documentation for the Client shows every event.
In the first few lines of code, we need to configure our Client and other
libraries.
The latest version of discord.js requires an Intents object. Intents
specify the bots permissions. For the Dovahzul Client, I specified the GUILDS
and GUILD_MESSAGES intents as shown above.
Using the "on" method, I can define an action for the
messageCreate event. The callback for the messageCreate event uses a parameter of type Message. All the properties
of message are in the discord.js documentation.
A bot will be unable to function unless it is logged into discord. This is
where we pass in the bot token and make use of the "dotenv" package. The login
method in my case is called in the very last line of "bot.js".
Node: Parsing Commands
|
| lines 41-47, bot.js |
Parsing strings are easy in JavaScript compared to other languages.
(Obligatory foreshadowing)
This one-liner deconstructs any message a user sends into a command
string and argument array.
const [cmd, ...args] = msg.content.trim().substring(prefix.length).split(/\s+/);
-
msg.content returns a String of the user's message
-
Trim to "cut out" white-space
-
Substring to "cut out" prefix character
-
Split to separate each word by white space
(regex \s+ refers to one or more whitespace)
- msg.content returns a String of the user's message
- Trim to "cut out" white-space
- Substring to "cut out" prefix character
- Split to separate each word by white space (regex \s+ refers to one or more whitespace)
The parsed message is then sent to a function I created called
handleCommand.
lines 16-22, bot.js
The handleCommand function has to check which
command was entered and then execute x action. For those
familiar with the command design pattern, this appears to be a perfect
opportunity to refactor. The reply method instructs the bot to send a
new message "mentioning" the author of the previous message.
Mentions in discord are denoted by an "@" prefix before someones
username. Discord automatically highlights any messages where you are
mentioned.
|
| lines 16-22, bot.js |
The handleCommand function has to check which command was entered and then execute x action. For those familiar with the command design pattern, this appears to be a perfect opportunity to refactor. The reply method instructs the bot to send a new message "mentioning" the author of the previous message. Mentions in discord are denoted by an "@" prefix before someones username. Discord automatically highlights any messages where you are mentioned.
Node: POST Request
The API for the translation logic requires an HTTP POST request. We can use
the axios library we installed earlier to send requests to the translator's
server. The translation service I used is "Fun Translations" at https://funtranslations.com/thuum. They offer 1000 requests per day for $5 a month, however there is also a
free version for 5 requests per day.
|
|
| lines 23-34, bot.js |
The axios post function allows us to configure the request with the required headers and parameters. Any incorrect parameter or header could result in a "bad request error". The arguments passed were previously split by white-space into an array, so we need to rejoin them to have a full string of translatable text. The replyTranslated function is called via a JavaScript promise when the request was successful.
|
|
| lines 9-14, bot.js |
The replyTranslated function I created processes the HTTP response. More specifically, it parses the received JSON and tells the bot to reply with the translation.
Node: Results
|
| translation of "Ragnar the Red" |
Overall I found developing in Node an absolute breeze! I ran into several issues with the translation API, however node always seemed to function when I least expected it too. Nonetheless, next week I will cover Python and Java versions of this bot. This post included more introductory sections, so I was unable to cover Python like I originally intended. Expect later posts to go more in depth into the discord libraries and code.





Comments
Post a Comment