My Custom Discord bot, with a Hint of Ventrilo

Back when I was in high school I used to game [A LOT] with a group of guys. We gathered together, virtually, from different parts of the world to play some of the best titles of that era (CS 1.5, COD1, COD2, COD4, etc.)

Before tools like Discord popped onto the scene we used Ventrilo to communicate in and out of game. We hosted our own server, a place where we got together to hang out and play competitively.

Screenshot of the old ventrilo client on Windows

Fast forward 10-15 years, we've all grown up and one-by-one began to gather once again.

Two of the original members (myself included) started a private Discord server, a few years later, we have ~60 active members at any given time.

Ventrilo's best feature

We quickly realized Discord was missing 1 major feature we loved from Ventrilo, that of the Channel Announcer. We would typically run Ventrilo in the background while we gamed in the foreground. When someone would join or leave a channel you were in, Ventrilo would announce that person's name, this way you could tell who it was (duh).

Discord has an in-game overlay that visually shows you who's in the channel, but, we typically disable it (in order to improve in-game performance).

Discord has an awesome API, so I decided to build a bot to replicate that old channel announcing feature we loved from Ventrilo. I wrote the bot in Javascript/Node and it works great!

Here's a bit of the code that listens for voiceStatusUpdates:

1client.on('voiceStateUpdate', (oldMember, newMember) => {
2 // ...
3 if (
4 newMember.voiceChannel &&
5 client.voiceConnections.find(
6 (item) => item.channel === newMember.voiceChannel,
7 )
8 ) {
9 announce.sayJoin(newMember)
10 } else if (
11 oldMember.voiceChannel &&
12 client.voiceConnections.find(
13 (item) => item.channel === oldMember.voiceChannel,
14 )
15 ) {
16 announce.sayLeave(oldMember)
17 }
18})

The announce module has sayJoin and sayLeave methods that synthesize the member's name + their phrases using a text to speech service. The bot then caches the resulting .wav file for future events.

I took it a step further and allow users to modify their join/leave phrase in order to introduce some personalization.

This bot also announces when a member mutes, deafens, or starts streaming (which can all optionally be turned off).

Stats

I love a good stat dashboard as much as the next person, and i've been really keen on using Grafana for everything lately.

I setup a Prometheus extractor to read from the bot's database and report (every 15s) on a few stats, in realtime.

  • CPU, Memory & Heap usage of the Docker process.
  • Total number of servers the bot is in.
  • Total number of actions responded to (join/leave events).
  • Total number of phrases directly edited by users.
Dashboard of Stats for the Bot in Grafana

Ventrilo Inspired Commands

1// Customize the default join/leave phrase for the server
2!default
3
4// Disable the announcement of a specific events
5!disable-event
6
7// Enable the announcement of a specific events
8!enable-event
9
10// List the state of all announcement events (if they are enabled or not)
11!events
12
13// Joins the user's current voice channel
14!join
15
16// Leaves the user's current voice channel
17!leave
18
19// A list of phrases added for this server
20!list
21
22// Add a join or leave phrase for a member
23!phrase
24
25// Rejoin the user's current voice channel
26!rejoin
27
28// Reset a user's join/leave phrase to the default server value
29!reset
30
31// Says a phrase in the users current voice channel
32!say
33
34// Sends a test phrase to the bot's current voice channel
35!test
36
37// Sets the server's voice. Use the voices command for a list of all available voices.
38!voice
39
40// A list of available voices you can choose from.
41!voices

Additional Miscellaneous Commands

1// Lists all command groups
2!groups
3
4// Enables a command or command group
5!enable
6
7// Disables a command or command group. (good for disabling a command if it's being abused)
8!disable
9
10// Displays a list of available commands, or detailed information for a specified command
11!help
12
13// Shows or sets the command prefix
14!prefix
15
16// Checks the bot's ping to the Discord server
17!ping
18
19// How long the bot process has been running.
20!uptime

Admin Commands

1// Forces the bot to disconnect and reconnect to discord
2!restart

What Next?

Currently the bot is private, but i've been getting requests from others who want to add it to their server as well (awesome!).

I've got some refactoring to do (ideally a re-write in Typescript) and enable sharding so it can scale to hundreds of servers.

I'll most likely open-source it as well. Stay tuned!

Edit 2020:

I've completely re-written this bot in Typescript using the latest Discord.js library. It has been submitted to top.gg (a Discord bot search directory), so that anyone can install it on their own server for free.

Edit 2021:

I've renamed this bot to KITT (shout out to Knight Rider) and the code is up on Github . This bot was also verified by Discord for surpassing 100 servers and now sports the verified-check badge!