DEV Community

Juan Miguel Medina Prieto
Juan Miguel Medina Prieto

Posted on

Writing a custom overlay with React

Whenever I have ideas for personal projects and I don't trash them completely because either they're impossible for me to carry out reasonably well, or they have already been done by everyone and their mother, they tend to be oriented towards content creation or videogame competitions, usually as a result of me finding out a chore that may be automated is being performed manually.

Obviously, I don't blame anyone for not commissioning a programmer to code a tool or a bot to help them with those, mostly because it's normally on the low end where I find these sorts of hiccups, and considering the little money (if any) that will move around those environments, it's unlikely investing into a fancier workflow will be a wise decision to their eyes. However, even if I know my projects will probably go unnoticed by those people, it's still a good chance for me to try out a somewhat original idea and generate some code that doesn't consist of doing the same thing you've already seen a million times on the web for anyone to take a look at.

The idea

That said, I'd like to tell you how I came up with this overlay idea. I was watching one of the streamers I tend to watch on Twitch on a somewhat regular basis, except that day, they were broadcasting a little tournament under a charity event. A link was provided to pledge some money for the cause, and between rounds and matches, the streamer would get to the campaign's website and copy new donations to a textbox in one of their scenes manually.

That brought up a question to my mind: "isn't there a bot for that?". As I imagined, no one was aware of such a thing in the stream. The service used as the basis for the campaign was Tiltify, and the first thing I tried upon figuring out the name of the website was searching tiltify api, and sure enough, there's an HTTP API for it.

One of many campaigns held on Tiltify

Having those docs handy, it's clear I can create a relatively simple overlay using the React library and the default template it provides with the Node script create-react-app as a starting point. The purpose of that is to try it out some and practice working with RxJS. I already have some experience with it as a result of having been working with Angular's HTTP client in the development of an application made with Angular.

Unlike what I first thought, I decided to end up using Redux as well to carry the configuration to the components that need it and not have to either pass the parameters manually or transform them inside the component. Its Angular equivalent is NgRx, although that one works quite a bit differently from Redux, which only makes sense because NgRx is made to suit the way Angular works best. Redux by itself (and a helper package) seems to be better suited to React.

The layout

Being a simple overlay that consumes an API, the application has only two views: the Overlay itself, which will be loaded by the App if the necessary configuration in the query parameters is present, and a LinkGenerator that should make it easier for streamers to paste the required information and do further configuration if they want, then get a link copied to the clipboard that will get the display view loaded into their scene.

The link generator

The Overlay component's job is to get the data from Tiltify's API and render each item of the list as a Donation instance, showing its name and amount. They may be displayed in the order the API yields them (sorted from latest to oldest donation) or sorted descendingly by price, showing the greatest amounts donated on top.

The amount is further delegated into the AmountDisplay, which makes sure to layout the donated amount according to the configured position for it and desired currency. For example, a price in euros has the euro sign placed to the right (eg. 100€), while a price in dollars is written the opposite way (eg $100). Only adjusting the specific parameters is needed so that the display isn't dependant on CSS styles. This should allow the same styles to be used with different currencies.

A diagram of how the components are related to each other

The limitations

As you might imagine, most of the limitations came from the Tiltify API itself, simply because it is quite bare at the moment and the documentation is also lacking. The most significant issue for my purposes was the fact that there's no WebSocket option. In short, WebSocket keeps a communication channel open for longer than a regular HTTP request, thus allowing the sender and receiver to keep sending messages to each other. That way, for example, the application would get updates from the API without having to send another request. Since that wasn't an option, the next better possibility was setting up an observable which calls the code responsible for fetching all the donations every minute.

Also related to the API itself, as of the moment of writing this article, no options to sort the donations seem to be provided, and since that has to be done manually, I think it's best to fetch them all regardless of whether they will be displayed as they are fetched or sorted by amount descendingly. Besides, the tokens I generated to test the overlay with real data were constantly banned in a matter of hours for some reason; I do suspect it's because I accessed multiple campaigns from other people with them. After all, when I try just one campaign with one token, it keeps working all the time.

As I didn't want to create a sample campaign without a proper way to add test donations that didn't involve spending real money, and because there's no easy way of finding a campaign that is getting a lot of new donations regularly, I decided to add a test mode that should allow anyone else making custom styles to test how everything should look without continuously fetching data from Tiltify. It can be triggered in dev mode if you add &test=1, or basically a test query parameter with any value that is truthy to any URL the LinkGenerator makes.

How the test mode looks with default styles

My desire to add unit tests to all the code I wrote caused some unexpected changes as well. Particularly in the overlay, which is actually exposed by itself in a module and connected to the store in another. That's because I couldn't fake the timers needed to test the observable created as a result of the mapping from the state to the component. Besides, even if I pulled it off, all the mocking necessary to make the test suite work correctly would have made it excessively complicated. Thus, I tested the overlay without any connection, separated the code responsible for bringing the current list of donations to its own service, thus testing it by itself, too, and left the connection to the store untested due to the timers' problem I described before.

The result

The finished overlay application is available to try out here. The source code and documentation about its usage and customization can be found in the repo below.

GitHub logo jmmedina00 / tiltify-donors-overlay

An overlay that shows the latest (or highest) donations for a Tiltify's campaign

Tiltify Overlay

Overlay made with React that shows a Tiltify campaign's donations, sorted by newest to oldest or by amount given descendingly. An article about the making of this application is provided here.

Usage instructions (as-is)

  1. Get your campaign's id from the campaign's dashboard. This article describes exactly where it is.

  2. Go to the account settings, then go to Your applications, create an application, enter its settings and get its access token from the section at the bottom.

  3. Enter here.

  4. Fill in the form with the campaign and the token, and select some options as you wish. When it's done, click Generate link.

  5. Go to OBS and add a browser source, paste the link that was copied to your clipboard and set up the dimensions as you prefer. Make sure to remove the default custom CSS and not mark Shutdown source when not visible or Refresh browser when scene becomes

Feel free to ask me any questions about anything in the code or regarding my design decisions and I'll try to give the best reply I can provide.

Oldest comments (0)