← Home Archive Photos About Ryboflavins
  • Building a Discord Alert System For Twitch.tv

    Recently, a host in a Discord server pinged me asking if we could have a feature demoed by @nuttylmao in this X post: https://x.com/nuttylmao/status/1839718888025796817. Here the poster demos having various alerts from their Twitch stream posted to a channel in their Discord. This honestly seems like a feature that should be available built in with the Discord-to-Twitch integration that already exists, but I digress. I scoured the video to try and see how they were doing it, only to find that this seems to be done with Streamer.bot, and some custom code (plugin?) for that platform. As is the Rybo way, rather than use an already solid way to solve this problem, I was determined to do it myself, and thought it might be useful to detail here. Let’s see if we can learn how to replicate the functionality on our own with some JavaScript wizardry.

    So here we go, With the usual warning that I am by no means a professional developer nor is this a full tutorial (it’s more pseudo-code of my thinking), and while I did get this to work, you should probably use the Streamer.bot method instead.

    Before We Begin To start with I am going to assume a couple of things, that is that you have Node.js running on something with a publicly accessible HTTPS address, are able to install packages with npm, and have registered an app at dev.twitch.tv. This will provide us with the requisite Client ID and Client Secret needed to communicate with Twitch’s services. It is paramount that the client be kept as an actual secret, so be sure to store it in a secure way, such as a secured database. Likewise the same is needed for Discord.

    Figure 1
    A Discord Embed Example
    Embed Example
    Note. by Ryboflavins, 2024

    Now that those requirements are out of the way, this project will need a few external packages, namely TESjs, DiscordJS, and date-fns, and lastly node-twitch. The TESjs package makes interacting with EventSub, frankly, a breeze, while DiscordJS naturally gives us the tools to interact with Discord. We will use date-fns to so some quite date math, and node-twitch is handy for getting some information about the live stream.

    How I chose to tackle this was first, using the TES.subscribe method to subscribe to a Twitch EventSub endpoint, and then the TES.on event handler to first grab the link to the livestream (as EventSub does not provide this). In order to get the timestamp of the alert, we do some date math in the form of taking the current time, subtracting 15 seconds (date-fns time to shine), and with that time in hand we subtract the start time of the live stream itself. This difference can then be appended to the livestream link in the form of twitch.tv/video/[video_id]?t=00h00m00s. We can then use DiscordJS’s EmbedBuilder function to create a nice looking Discord post with a direct link to when the event happened in the video (minus that 15 seconds!). For example the following (rough) code would first subscribe to an EventSub alert, and upon a cheer event triggering, run the code in the TES.on event:

    tes
      .subscribe("channel.cheer", { broadcaster_user_id: "[twitch channel user_id goes here]" })
      .then(() => {
        console.log("Subscription successful");
      })
      .catch((err) => {
        console.log(err);
      });
    
    tes.on("channel.cheer", (event) => {
      async function updateStream() {
        var timeStamp = new Date(Date.now());
    
        async function streamData() {
          const streams = await twitch.getVideos({
            user_id: "twitch channel user_id goes here",
            period: "day",
          });
          return streams;
        }
    
        const liveStreamData = await streamData();
        const liveStreamURL = liveStreamData.data[0].url;
        const liveStreamDate = liveStreamData.data[0].published_at;
    
        var now = new Date(timeStamp.toISOString());
        var then = new Date(liveStreamDate);
    
        var modDate = subSeconds(now, 15);
        var dateMath = modDate - then;
        var markerDate = convertMillis(dateMath);
    
        let timeStampURL = `${liveStreamURL}?t=${markerDate}`;
    
        const embed = new EmbedBuilder()
          .setTitle(`${event.user_name} Cheered!`)
          .setColor("#ff5aff")
          .setDescription(
            `${event.user_name} Cheered ${
              event.bits
            } Bits! on ${timeStamp.toLocaleDateString()} Link: ${timeStampURL}`
          );
        console.log(`Now: ${now} Then: ${then} Math: ${dateMath}`);
        channel.send({ embeds: [embed] });
      }
    
      updateStream();
    });
    

    Within the event handler, we get the latest video url as well as when it started, do that date math, and post to Discord as an embed. It is important to note that the above code lacks error handling, and should be added before any kind of production use.

    Pulling this all together means we can have a running log of the major Twitch events (with the notable exception of new followers), right in Discord. This is especially useful if you like to create clips of some events, including raids and subscriptions! Having the basic requirements for a bot completed (Twitch and Discord API access), also gives us the major Lego blocks to build all sorts of fun integrations. This is just one of many. For example if one was raising money for Extra Life, you could utilize the extra-life-api package, to tie in a donation event to the timestamp on the stream as well.

    To wrap up, I want to give a special thanks to @nuttylmao for the idea that sparked all of this, and until next time, may all your code be bug free, and have a wonderful day!

    mitchwadair. (n.d.). GitHub - mitchwadair/tesjs: Streamline your Twitch EventSub JavaScript integration with TESjs. GitHub; GitHub. Retrieved October 12, 2024, from https://github.com/mitchwadair/tesjs

    β†’ Tuesday, 15 October 2024
  • Fun with DiscordKit

    To give myself a purpose for learning Swift, I decided to try and port my Discord bot, based on Node, to Swift. This of course means I lose the benefit of the fantastic Discord.js library.

    Because I have no clue what I’m doing, I rely on these libraries to make the magic happen, so I was going to need something for Swift. Enter DiscordKit, another handy Discord library. I HIGHLY recommend following the getting started guide at: https://swiftcord.gitbook.io/discordkit-guide/, but here’s how I made the basics work:

    import Foundation
    import DiscordKitBot
    
    @main
    struct ribble {
        
        static func main() {
            
            let bot = Client(intents: [.unprivileged])
            let commandGuildID = ProcessInfo.processInfo.environment["COMMAND_GUILD_ID"]
            
            bot.ready.listen {
                print("Logged in as \(bot.user!.username)#\(bot.user!.discriminator)!")
                
                func registerSlashCommands() async throws {
                    try await bot.registerApplicationCommands(guild: commandGuildID) {
                        NewAppCommand("swifty", description: "Test The Swift Bot") { interaction in
                            print("Received swifty interaction!")
                            try? await interaction.reply("Whaddup Doe from Swift")
                        }
                    }
                }
                    do {
                        print("Registering interactions...")
                        try await registerSlashCommands()
                        print("Registered interactions!")
                    } catch {
                        print("Failed to register interactions: \(error.localizedDescription)")
                    }
            }
            do {
                try bot.login()
            } catch let error {
                print(error)
            }
            RunLoop.main.run()
        }
    }
    

    I also had to learn the Swift Package Manager. Click on your project -> Package Dependencies to get started. From here click the + and add https://github.com/SwiftcordApp/DiscordKit, and then make sure that DiscordKitBot specifically is added to your target.

    Seriously, follow the official guide though. πŸ˜‚

    β†’ Friday, 9 February 2024
  • Simple SwiftUI

    I’ve decided to try and tackle SwiftUI, and was immediately greeted by not knowing how to take the text from a textbox, format it as name components, and then update a label, ALL from a button push.

    This took me way too long and too many searches to come up with πŸ˜‚

        @State private var fullName = PersonNameComponents()
        @State private var enteredName: String = "Johnny Bazookatone"
        @State private var personName: String = ""
        
        
        var body: some View {
            VStack {
                TextField("Proper Name", text: $enteredName)
                
                Button("Go") {
                    let formatter = PersonNameComponentsFormatter()
                    self.fullName = formatter.personNameComponents(from: enteredName)!
                    self.personName = fullName.formatted()
                }
              
                Text("Hello, \(self.personName)")
            }
            .padding()
        }
    }
    

    I don’t even have a use for this code, but here it is.

    β†’ Wednesday, 7 February 2024
  • RSS
  • JSON Feed


Copyright 2024 - Ryboflavins