Tracking GameBoy records with a Discord Bot

January 6, 2025

This post is part of the Game Boy series (#8).

In Speedrunning, there is still an active community playing GameBoy games, and now and then, there is a new record for a fastest playthrough (or run) of a GameBoy game.

Now how can we get a notification without visiting speedrun.com? It turns out that Discord has a cool feature called "Bots", where you can push messages based on events you can define. They look like this:

wr-bot

The cool thing is that you can use a simple Python script to check for new World Records and publish them to a Discord Server. Let's dive in!

Accessing the speedrun.com API

First, we need to know if a new record happened. There is a public repository for the speedrun.com API over on Github, but it doesn't seem to be maintained anymore. Still, it is enough to get some information like what games there are, and the best run for every game.

For example, this link will return 10 GameBoy games (n5683oev is the ID of the GameBoy platform): https://www.speedrun.com/api/v1/games?platform=n5683oev&_bulk=yes&max=10 - you can also open it in your browser!

Now with a list of relevant games (where we can also include GBC for example), we can do the following:

  • Fetch all categories and the best run in each of them
  • Compare that run to a list of record we already have. Note that this requires updating & saving that list on every run of the script, to not get notified twice.
  • If we found a run we didn't know so far, we can push a notification!

You can find the full source code here: fetch.py

Using the Discord SDK

With a list of new records, we can now set up a script that sends out a new Discord message, using the Python package that Discord provides. The script listens to certain events (@client.event) which will be called when it's ready, and when our code can run:

import discord

client = discord.Client()

@client.event
async def on_ready():
    wr_runs = feth_latest_wr_runs()
    for server in client.guilds:
        for channel in server.channels:
            if 'new-world-records' in str(channel):
                for run in wr_runs:
                    await channel.send(embed=create_message(run))
    await client.logout()

client.run('<my-token>')

That's the most of it! There is some error handling when parts of this fails, but overall it is quite simple. You can see that it goes through the servers the Bot is part of, and checks if a channel is named new-world-records, and then publishes the records as separate messages.

Now the create_message() is a method which returns a Discord message object. We can set a title, a content, and also add a thumbnail like you can see in the screenshot at the top.

def create_message(run: Dict) -> discord.Embed:
    """ Create embedded message from run info """
    title = f'{run["game"]} - {run["category"]}'
    description = f'{run["primary_time"]} by {run["player"]}'
    embedded_message.set_thumbnail(url=run['image'])
    ...
    return embedded_message

You can find the full source code here: bot.py

Connecting to Discord

To connect the Bot to Discord, we need to create a "Discord application", something that is actually able to send messages to a Discord server.

You can do that in the developer portal. For detailed instructions, please see the tutorial on realpython.com.

Once it is created, you will be able to copy a token which you can use in the Python script. You can also set a custom avatar etc.:

wr-bot


Now that we have a a working Bot, we just need to set it on a regular schedule (for example with cron) so it is checked daily if new records appear. I use pythonanywhere.com for most of my Python projects, but anything that can run Python will do.

By the way, if you just want to invite the GameBoyWRBot without creating your own, you can use this invite link.

You can find the code here: akleemans/gameboy-wr-bot.

Thanks for reading and happy botting!