Twitch box art code dissection

Posted by adrian on March 18th, 2016

I recently posted about adding Twitch game box art to your stream using a web page that I wrote, it took me quite some time to work out how to do it and I thought I would share my experience and also give anyone the opportunity to amend the code as they see fit. I’m not a coder by trade and I find the only way to learn is to have something that I want to code and learn around that, not the best way to learn but it works for me. There may be other ways to do this and I am happy to get feedback.

I just want to mention that I was inspired to have a go at this by an article which I read here thanks Daniel!

My objective was to make a local web page which would display the box art for the game you are playing on Twitch in a scene. For instance I make reference to the currently playing game in my ‘Be Right Back’ scene and having the game art in the scene would make it look more professional. All the streaming software is capable of displaying the contents of a web page in your stream and in theory it should be a simple task to use an html page and a javascript to update an image based on the game that is configured on Twitch.

Let’s get the easy stuff out of the way first, the html page is a very simple page with a placeholder for an image, the css style is included as I found it was the only way to get the OBS browser to handle the size of the image correctly without any page wrapping.

The javascript needed to achieve a couple of things:

  1. Update the html to show the right image
  2. Get the currently configured playing game from Twitch and find it’s box art
  3. Poll to see if the game changes and update accordingly.

Step 1. is pretty straight forward as you can use a url which we’ll get later on, I pass the url as a parameter to the update function for ease of use.  Here’s how that works:


function updateImage(url) {

var image = document.getElementById("myImage");

//Check if the url passed in is invalid, this should never be the case but if it is then set the image
//to be the default image
if (url === null | typeof url === "undefined") {
url = defaultLargeBoxArt;
}

//update the image in the html
image.src = url;
}

Step 2. turned out to be less straightforward than I hoped. I knew going into this that the Twitch API is easy to access as it’s REST and all the API calls return standard (self describing) JSON. I started off by working out what calls I’d need to make just using internet explorer. For example typing this into your browser will cause a file to be generated which you can download that actually describes your channel. You obviously need to put the channel name you want to query.

https://api.twitch.tv/kraken/channels/unshapedadrian

I found that this query returned the game currently configured which was great and then I needed to work out how to get the game box art. Turns out the API has a search function for games which allows you to query the platform like this for information about the game called Spintires.

https://api.twitch.tv/kraken/search/games?q=Spintires&type=suggest

The full API documentation is here with example links for each call.

I did some research to find out how I could get this data using javascript and found that jQuery had a method called getJSON which I thought would be the best bet. However when I tried to use it I couldn’t get any errors out of it which meant that during my initial testing it just failed constantly and silently. This is obviously a normal issue and the general recommendation is actually to stick with the standard ajax method as that has proper error handling. So initial problem solved and I found that I needed to allow for Cross origin resource sharing because IE was being a pain. Initially though I was handling the data returned inside the ajax call and it turned out that was not going to work because of the async behaviour of the calls.

Not being a regular coder I always run into this problem which basically means that calls are often not waited on to return which is very common place but something that always catches me out. What this meant was that I was trying to handle data before the ajax call had completed meaning that I would get inconsistent results so I had to use callback functions with ajax to make sure that the data had returned before trying to handle the data. For instance this is the call to get the current game from Twitch:


function getCurrentGame() {

//If you are testing this in IE you may need to uncomment the line below to allow cross site scripting
//$.support.cors = true;

//Using ajax here, could have used getJSON but the error handling is awful
$.ajax({
url: "https://api.twitch.tv/kraken/channels/" + channel,
dataType: 'json',
success: getCurrentGameCallback
})

}

//This is the callback for getCurrentGame that handles the data once the call to Twitch has completed

function getCurrentGameCallback(data) {

//if the game name is the same we don't need to make the second call as we already have the url
//stored in the global

if (data["game"] === globalGameName) {
return;
}
else {
globalGameName = data["game"];
}

//We found a new game so we need to call into Twitch again to get the JSON for the game itself
getGameImageUrl(globalGameName);
}

What I had to do here was first call the Twitch API using ajax and specify a callback routine, this is a callback locally and not sent to the server. In the callback routine I then knew I had the JSON data and could handle it appropriately. In the above routine I knew once I had the game title I could check against the global variable to see if it had changed and if it had go on to make another call to Twitch to get the box art URLs. I then did the second call to Twitch in the same way. Basically I ended up with a chain of callback routines to make sure that the data had been returned before processing.

A quick word about the JSON that is returned when you query for the game data. Basically this is a search which will return multiple results, I found it consistently returned the game I wanted in position zero because I was passing the full name into the search. The JSON returned in the second call is pretty deep I ended up referring to data like this:


globalBoxartUrl = data["games"]["0"]["box"][size];

This is pretty messy but I only wanted the one piece of data out and so it seemed like the easiest option. It also made it easy if a user wanted a different size as they can just change the definition of the size variable appropriately.

Step 3. actually turned out to be pretty easy but of course had a challenge at the last. JavaScript has a couple of timing functions and the one I decided to use was setInterval as this repeats the specified function ad infinitum based on a polling interval that you configure. One thing I didn’t realise was that it doesn’t cause the function to get called straight away and then pauses it does it the other way, so I had to do a manual update to the image before starting the polling. With the polling I set a five minute interval and was also careful to avoid calling Twitch if it wasn’t required. This is only a small piece of code and so shortening the polling interval wouldn’t have caused a lot of issues but I always think it’s best to play on the safe side and for what I was trying to achieve five minutes seemed more than adequate.

And that was it, although I have a couple of further things that I am concerned about or would like to add

  1. I am concerned that there is a memory leak somehow maybe in the way that I am handling images in the html and I need to investigate this further.
  2. The CDN configuration for the images is interesting, for instance when you query the Spintires game the API says that there is an image here:http://static-cdn.jtvnw.net/ttv-boxart/SPINTIRES-272×380.jpg. However when that finally resolves you get sent to this URL: http://static-cdn.jtvnw.net/ttv-static/404_boxart-272×380.jpg. This is interesting because whenever a game doesn’t have box art it gets redirected to the default image, this saves there being a default image saved for each game without box art. If I could catch this then I could put something else up maybe by going to the GiantBomb site instead. It’s also interesting that many games don’t have box art which is a little disappointing and so it would be great if I could work out a better fall back rather than relying on the Twitch fall back.

 

Last thing as this has been a learning experience I have also learned how to use GitHub a little bit, the source code for this project is available here:

https://github.com/adrianschofield/twitchboxart

Comments and feedback are greatly appreciated as I’m always trying to learn.

/* */