In this post, I thought I’d break down how Roger’s Jukebox works. You can access the repository I will be referencing here. This post was created in reference to release Beta v0.1.0.
Imports
As with practically any Python script, I start by importing all the required modules. The modules I’m importing are as follows:
datetime– this is for the unadvertised and unmaintained/helpcommand, so will be removed at the next release.os– file/directory management when dealing with downloaded tracks.discord– the main discord.py module that does most of the heavy lifting.logging– logs all actions into abot.logfile.ythandler– another file; I’ll get onto this another time.asyncio– using the.sleep()method to make the program wait.
Constants
I then declare the following constants…
TOKEN– access a file that holds the bot token.LOGHANDLER– usesloggingto create and update the log file.LOCALGUILDID– primarily used for testing, but should be set to the target guild the bot will be used in.
Classes
Guild– holds information regarding playback in a given server. I am yet to test the bot working in multiple guilds simultaneously, but the logic is there to ensure that works.Client– managing the bot itself. Required for it to even turn on!
Intents and Other Vital Elements
The bot’s intents must be specified and I also assign a Client class to a client variable.
Commands
I chose to implement all the bot’s commands as “slash commands” as that seems to be the way Discord is going. The @client.tree.command() adds a new command to the command tree, which is where slash commands are gathered from. The following commands are implemented…
/ping– basically just a quick health check to see if the bot is responding./help– the unused command I mentioned earlier. Meant to supply an embed with all commands listed. The embed is still supplied, but I just haven’t updated it in a while!/play– this is probably the most important command in the entire script, so I’ll break it down step-by-step.- A check is performed to make sure that either a search query or a URL is provided, not both and not none! If one of the latter is the case, an error message is sent back to the user.
- Another check is performed to see if the user is actually in a VC. If not, they won’t be able to use the command and another error will be returned.
- If the above checks pass, and a URL is detected, it is passed into a
yt.Trackobject (using theythandlermodule that I’ll talk about some other day). This is also where the file is downloaded and given an ID. If an error happens here, an error message is produced and the rest of the code does not execute. If the checks in steps 1/2 pass and a search query is detected, the same as above goes but the query is passed into ayt.Trackobject instead of a URL. - If step 3 is successful, the process of connecting the bot to the VC begins. First, a new
Guildobject is appended to theguildsdictionary in theclientif it is not already present. This holds information such as the queue, voice client, and more. A pointer to the appropriate guild object is then stored in a variable for easy access. - A check is then performed to make sure the audio file exists. If not, an error message is returned.
- Another check is performed to see if something is currently playing. If so, the
Trackis added to the queue with theaddToQueuemethod of theGuildclass. - If the audio file has successfully downloaded nothing is currently playing, the bot will grab the current voice channel of the user, create a voice client and attempt to connect to the voice channel. An important note here is that the bot needs a separate voice client for every server it is actively playing in; hence the need for the dictionary mentioned earlier.
- If this succeeds, the Discord interaction messaged is changed to display the current track and the track begins playback.
- Once playback has finished, if the queue is empty, the bot will disconnect and remove the
Guildobject from the dictionary. If the queue still has items in, theplayNowmethod is called to play the next track. There are also some other blocks in here, but they’re not too relevant here, so I’ll skip over them.
/queue– this displays the current queue. At the moment for the currently playing track, the unique ID I mentioned before is shown, but I want to change this to show the name of the track./stop– this stops playback, disconnects the bot from the voice channel and clears the queue./skip– this skips to the next track in the queue.
Other Methods
There are also some other methods used for various bits and pieces, but since this post is mainly just an overview, I’ll skip those. Be sure to tell me if you want these outlined though as it may be useful!
Running the Bot
The final line of code in the script actually starts the bot using the token set earlier, and sets the logs to be sent to the LOGHANDLER.
Final Words
Writing this made me realise that there are many parts of this that need changing/updating, but I’m also relatively happy with the current state of the bot! I hope this post has proven helpful, informative or interesting to you. I mainly wrote it for myself to understand the decisions I made when I look back on it. I also hope to host the bot soon for anyone to use, but we’ll see what comes of that!
