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