Miki Sayaka Devblog 002: Two Months Later

December 16, 2024


Four months ago, I started working on Sayaka, with some simple features to kick it off with. I originally planned to write a weekly-ish devblog, with the first entry being two months ago, but… being a combination of my laziness with how fast Sayaka was moving at that point, it was a rather impossible feat for me to do.

So, two months later from that last post, where are we? I'm happy to say Sayaka has managed to bump one whole major version (!!!) and we've improved quite a lot from where we started.

Pagination

To start off with, Sayaka has proper pagination now. As of the time of writing, she's currently tracking about 115 manga titles. Using s>manga list now gives you a neat little embed like so, with buttons to change pages.

The message output for Sayaka's manga list

This… unfortunately isn't available (yet) in the self-roles commands… because I'm lazy… I'll get around to it sometimes, I swear. It doesn't see a whole lot of uses because Nazunacord itself doesn't see much activity and we're all admins, but I cannot check this off as finished until I do it…

Sayaka also got a neat feature, matching any MangaDex link posted to the Discord channel to read data for!

The message output for Sayaka's MD link parser

I originally let MangaDex's original embed sorta coexist with Sayaka's: MangaDex would have the description, the cover art, while Sayaka would have all the information. But, after a while it cluttered up pretty quickly. So… it took me like… two hours… to figure out how to remove another user's embed from the bot's side. I merged up the cover thumbnail, as well as the description, and there we have it!

Chapter tracker

While I was at it, I also figured out how to neatly create a chapter tracker / notifier as originally planned too!

Notification messages sent by Sayaka

Originally, I implemented this by using a webhook, as I couldn't figure out how to send a message through the bot client created by poise. Afterwards, I spent a lot of time trying to figure out, even thinking of using a MPSC channel to fire things from the tracker task to the bot client.

After a good while figuring out the internals of the types used in poise and serenity, I realized… it's all Arc<T> under the hood… The solution then? I cloned the Arc<Http> instance from the bot and just used it to send messages, as I already know the Discord channel I'll be sending notifications into in the first place. This ends up making me really appreciate Rust and the Arc<T> type. Nothing beats being able to just do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let http = client.http.clone();

let bot_handle = tokio::spawn(async move { client.start().await.unwrap() });

if data_clone.md.is_some() && webhook_url.is_ok() {
    tracing::info!("initialized chapter tracker!");

    tokio::spawn(
        async move {
            let interval = tokio::time::interval(std::time::Duration::from_secs(7200));
            let task = futures::stream::unfold(interval, |mut interval| async {
                interval.tick().await;
                let _ = chapter_tracker::chapter_tracker(&http, &data_clone).await;

                Some(((), interval))
            });

            task.for_each(|_| async {}).await;
        }
        .in_current_span(),
    );
}

and it just fucking works. I don't even have to worry about it being thread-unsafe as it's all atomically reference-counted, and cloning is free. It's amazing!

さようなら, slash commands!

I've also decided to pull the plug on slash commands. Why? I personally don't use it, and no one really does in the server it's made for anyways. I feel like it would end up being a pain in the ass to maintain if I ever added some funky features that required a lot of arguments parsing, as my friend beerpsi had suffered writing extra features for his own bot…

tangent

Time for a rant on slash commands and the general state of the Discord API. The more I write Discord bots, the more I seem to dislike it, or at least, how often it's slightly changing.

Now that I'm no longer one to be impressed by the shiny, latest™ technologies, (and this is probably a lukewarm take at this point) I've come to realize Discord slash commands are one of the worst things to ever be created by mankind.

Personally, I very much dislike slash commands, as it's lumping all available bot commands under the same namespace and… tell me how you're quickly using a commmand at a glance if there are five hundred bots using the same /status?

The API changes very often in very subtle ways, especially surrounding the whole permissions / privileges thing. Maybe I'm not the one looking out for Discord API changes, but I swear that these are not clearly stated anywhere when they actually do change it.

Everything feels very inconsistent, from the way the APIs are designed to handle slash commands vs. prefix commands, and how to respond to those as well, it feels horrible and unwieldy to write code for, and that is reflected down to the libraries.

Yes, you can argue that prefix commands are being phased out by Discord and that's why they feel horrible to use, but honestly writing a slash-first bot isn't much easier either - they categorize a lot of stuff in very weird ways that would wind you in reading a lot of badly-documented documentations. Not the best of impressions, after I spent more than 24 hours attempting to write something that leveraged those features.

Future?

I'm not too sure what's going to be next for Sayaka. Feature-wise, she's generally complete, and I'm not too keen on expanding her far too much beyond her original scope.

A neat thing could be that s>manga sync also manually triggering the chapter tracker - but I have yet to figure out a method to lock the entire tracking process to only run once at any given time.

Of course… there's implementing pagination for the roles list too… I'll get to it I promise… It should just be the same code but changing the content strings… I think.

I think I would also spend some time doing configuration stuff, right now the chapter tracker is straight up hardcoded to be two hours, and sometimes I want to lower it, but I keep forgetting to do so as well.

Finally, thanks for reading to the end. Source code for Sayaka is always available on my GitHub!