#
Todor: A Discord music bot
#
Introduction
This article's purpose is to describe the development of "Todor" a music bot I wrote for the Discord server that me and my friends hang out in. During the early stages of the project, a friend of mine would constantly play something on the bot, and then leave. Thus, I named the bot after him.
Todor is written in C#
, utilizing the DSharpPlus
library, and early versions utilized the library's build-in audio playback. Since then, that system has been replaced by
Lavalink
. Lavalink
is an audio server written in Java
, which also has a client library written in C#
. The main reason for the switch, was to support a broader range of audio sources.
Over the course of this article, I will go over:
- Some of the bot's origins
- Deployment
- Hosting
- Maintenance
- Future
- Closing statements
#
Origins
As already mentioned, the bot is named after a friend of mine. Around that time, I was still getting started with development, and a lot of the ready made bots' free versions, had limitations that I didn't like. Not to mention, that plenty of them would either not work, or have laggy playback.
So, I originally started experimenting with using Python
, having seen some tutorials on the internet. To say that the original version was messy, would be an understatement. I wish I had some archives to be able to show some code, but alas, they have been lost to time. Not to say that the current version is anything to write home about, after all, it has suffered from 4 years of organic growth, but it is still much better than the original Python
version.
#
todor-reloaded
After that initial version, todor-reloaded was created in C#
with DSharpPlus
.
The reasons why C#
was chosen, were:
- I already had experience with the language
DSharpPlus
The main thing that I learned from that original Python
version, is that I needed some sort of a structure in the program, so that it didn't become unmaintainable. The Python
version was mostly two .py files, one for the entry point, and a big if-else statement for each command, and another file, which implemented each command. Finally, there was a big global dictionary, which severed as centralized storage.
DSharpPlus
on the other hand, provided the framework to build out commands, as separate classes, with a more defined structure. Not to mention, the framework automatically handled things like command and argument parsing, as well as providing important events, to which you can attach handlers.
Finally, this was before the time I used Docker in any serious capacity. So, I really valued that I could compile the bot as a single executable, and that I didn't have to install a runtime on the server hosting it.
#
Deployment
For quite some time, the bot's deployment consisted of me manually cross-compiling an executable (as I develop on Windows
) for Linux
, getting a cheap VPS from somewhere, copying it to the server, and running it with the screen
command. This worked surprisingly well for a good amount of the bot's lifespan. As it was a single executable, and didn't really depend on anything else (aside from a config file that had to sit next to it), it didn't really need any fancy orchestration.
After I switched to using Lavalink
for audio playback, I also started using Docker
with docker-compose
to deploy the bot, as having to have another screen for Lavalink
, started to feel annoying. This way, the only things needed for a deployment from scratch, were the config files for the bot and Lavalink
as well as a docker-compose.yml
file.
#
Hosting
Hosting has been a journey and a half. Trying to find a way to host the bot, either for free or effectively free, has meant that I've had to work with hosting providers, who haven't been exactly reliable. Imagine buying a VPS, and it just doesn't boot because it is stuck in a boot loop. Fun times!
#
Google Cloud
At the start, I hosted it on Google Cloud, using their free trail. That took about a year to run out, as the bot (even when using Lavalink
) can happily live on a machine with 1GB of RAM and 2 CPUs. After that was over free trial, I had to find somewhere affordable to host.
#
Romania
For about a year, there was a Romanian hosting provider, that managed to suffice. The bot ran fine, but anytime I had to do any maintenance on that machine (such as updating it) it was a pain, as it seems that there was something fundamentally wrong with the OS templates that they provided. And don't get me started on their KVM solution. Good luck installing a custom ISO. That said, I persisted, as the price was good, and 95% of the time, there were no real issues. The bot ran fine. That was, until I started running into the boot loop issues I mentioned in the first section.
#
Hetzner
DISCLAMER: Hetzner have not given me any money, and this is not an advertisement for them. That said, they have been the most affordable, reliable, and performant hosting option I've used so far. Period. And, technically, I could end this section here, but that is not the end of the Hetzner story. Unfortunately, Todor is no longer hosted there. And this is no fault of Hetzner themselves, but rather Google.
You see, the way the bot fundamentally works, is that it streams videos from YouTube, strips the video from them, and then it forwards the audio to Discord. This, as you may imagine, put extra pressure on YouTube's servers, which I can bet that they don't appreciate. However, worse than putting extra load, is that it also acts as a bit of an ad blocker. Whenever you play a "video" via the bot, ads are not streamed, as they are a separate video/audio stream.
As a result, YouTube, seem to have marked the entirety of Hetzner's IP ranges, as addresses from which requests require authentication, which is something that . So, I had to move again.Lavalink
doesn't support
UPDATE (03/12/24): Since version 1.10.1 of the youtube-source
plugin for Lavalink
, it is now possible use OAuth to authenticate with a YouTube account. You can refer to the plugin's docs on how that works. Tip: Use a throwaway account, just in case it gets banned!
#
Sofia
Currently, the bot lives on a small VPS in Sofia, Bulgaria. The provider seems to be small enough, so that their IPs are not flagged. That said, this new VPS only has 256 MB of memory, and it is a really tight fit. But, it is still alive! If anything, it highlights something that I really want to achieve with the next major version of the bot (todor-revolutions perhaps?). I want it to be extremely memory disciplined, so that it can even run on extremely low end VPS boxes (such as the one from LowEndSpirit), some of which can have as low as 64MB of memory, and a quarter of a CPU core.
After all, theoretically, it is just needs to move bytes from A to B while deleting some of them.
#
Maintenance
So, if you look on GitHub, project's repository has been on the site since May 31, 2020. A question that might come up, is what was it like to maintain over 4 years (and counting). Well, despite me not being very satisfied with the bot's overall code architecture, and the way it does some things, after going through some growing pains during the first year or so, it has been surprisingly reliable. Mostly, it has only needed minor version bumps, and that is about it.
If anything, the bigger problems have come from operating the bot, mostly due to YouTube's flagging of Hetzner's IP range, rather than the bot itself.
The only bigger change that has happened in the last 2 years or so, has been the need to change Lavalink
's configuration, to use the new YouTube plugin that they have, but even that, hasn't required any changes in the bot's code itself.
#
Future
So, what does the future hold for Todor? Well, there are a few goals that I would like to achieve with a future version.
- It needs to be able to run on extremely low end VPS-es, such as the ones from LowEndSpirit. This will not only make it cheaper for me to run in the long term, but also make it more mobile, in the case the YouTube decide to keep flagging addresses.
- Support YouTube authentication. As much as I would like to not have to authenticate to pull video from the platform, eventually I think that they will make it a requirement for any request.
- Use Discord's newly introduced slash commands, instead of a config defined prefix (as it does now).
- Some sort of a remote control over the network. Either via HTTP, or something custom, as the memory budget would be quite tight. One could even call it out of band control, as in, not via Discord commands.
#
Conclusion
Overall, working on Todor has given me a lot of the fundamental skills that I posses today. Working on it was the first time I had to:
- Work with Linux in way that was more than installing a package or two
- Developing a software project that would actually go on to be actively used for years
- Migration from one hosting provider to another
- Docker
- And probably more that I can't quite recall on the spot
More updates to come, bookmark this blog if you are interested!