Free Code Camp — Twitch Viewer

Vamp
12 min readApr 24, 2017

--

Twitch Project Live Link

(for those who want to skip the reading and get to the finished product)

Free Code Camp required user stories:

  • I can see whether Free Code Camp is currently streaming on Twitch.tv
  • I can click the status output and be sent directly to the Free Code Camp’s Twitch.tv channel.
  • If a Twitch user is currently streaming, I can see additional details about what they are streaming.
  • I will see a placeholder notification if a streamer has closed their Twitch account (or the account never existed).

Personal Goals (beyond requirements):

  • Display an overview section for each followed channel that displays online status, name, and current streaming title
  • Embed stream video and chat for each online stream
  • User options to add / remove followed channels stored in [never done this before…god help me] cookies? html5 local storage? Twitch login? other options?

Phase 0 — Research

Twitch API

Phase 1 — Mucking About

EDIT: I’ve Made a Huge Mistake

MFW

Since writing and learning what you see in the next section I have been informed that I was reading the page incorrectly...

The examples I was reading were server code and I spent quite a bit of time learning how and eventually converting those examples to javascript / jQuery. Well this is awkward. I’m leaving it up because I spent a chunk of time getting to this point and I learned a bit from it.

You can skip the following section and just read the javascript code if you want to ignore me vocalizing my struggle :[

My first choice of masochistic mucking starts on the twitch API main page. I have, of course, registered my app as per their directions, and received my client ID by this point.

Getting User IDs

So the first thing I see is:

Curl?

Great. I have no idea how to use your API and I also have just the faintest idea what language you are even speaking to me in.

If you followed my last post you know I had to have my precious $.get pried from my hands and replaced with the more robust request form of $.ajax. I thought it was over — I thought I had learned all there was to making API requests. As usual I thought wrong.

So curl is another request method I supposed… As luck would have it through my recent extensive mucking about with terminal — in trying to gain some semblance of what git is and does — I actually came across this term before. At least I know that they are referring to using terminal to make requests. Learned something new in the first 5 minutes of this project! Off to a good start.

Once again I won’t sit here and pretend I understand what curl is or does…but this curl documentation might help. I will, however, sit here and proclaim that I guessed correctly (sort of) that -H meant header and -X meant action [technically means request but close enough].

So I hopped into my terminal window and tried it out using my shiny new client ID. Worked as expected — I was returned some client information including something critical I know I will be using: the user ID. It seems a lot of tools in this API rely on user IDs rather than user names so this will be handy later on.

Let’s see how this terminal request would look in jQuery using my new friend $.ajax I learned from the last project. I dug through the $.ajax documentation to see how to translate the terminal formatting found above

Essentially the translation goes as follows:

  • -H: headers: { "insert -H string here", },
  • -X: type first [usually GET]: type: "GET",
  • followed by the request url url: "url string here",

I made a simple input and button page to test the request translation:

$('#test_API').click(function(){
var input = $('#input').val();
$.ajax({ type: "GET", url: "https://api.twitch.tv/kraken/users?login="+input, headers: {
"Client-ID": "REDACTED",
"Accept": "application/vnd.twitchtv.v5+json"
},

success: function (data) {
console.log(data);
}

});

});
I love when things work

To access the important bits of the returned user JSON object —

generic form: data.users[userIndex].property

with relevant properties:

  • user ID: ._id
  • name: .name
  • display name: .display_name

STOP — SKIPPING — HERE

Checking Stream Status and Details

Relevant API link(s):

Returns:

  • Online status
  • Number of viewers and followers
  • Current title being streamed
  • Preview image
  • Channel logo
  • Channel direct link

This request returns everything needed to fulfill the FCC required user stories [emphasized above] and some other fun bits.

It requires the channel ID for each request so I have to use the above [name → ID] request and callback this [stream status and details] request in the success function of the former.

Wow that was an ugly sentence, it should be easier to see like this:

Step-by-step of what is happening (on page load):

  1. pass the array of channel names to the convert_username request function
  2. loop through this array making a new request for each element in the channel array: channel_names
  3. on each success of convert_username call the status_details function for that channel passing the data (containing the ID) over to it
  4. in the status_details function extract the ID from the passed data in the form of var id = data.users[0]._id (if this is confusing see the above “skipped” section for details)
  5. make the request for status and details by using the extracted ID
  6. log the resulting status and details object to the console for review

And here is the output:

Notice the stream:null and stream: Object

When the return is stream: null it means the channel is offline (no stream data is available for something that isn’t streaming…)

  • This will be useful for designating whether a stream is on or offline as per the FCC user story requirements

When the return is stream: Object it means the stream is active and a wealth of data is made available. As seen below for ESL_SC2 (a channel that never sleeps):

Look at all that data!

Alright so we’ve made some good progress here. The next step is to get this data to be displayed in the DOM. To accomplish this I create a generic channel jumbotron “banner” that can be customized with the resulting data.

As an aside I just love jumbotrons. I like saying it. I like seeing how nice they look. I like their functionality. The only thing I hate is the rude bastard of Medium’s autocorrect red-underlining my jumbotron as if it could do any wrong. Moving on…

The idea here will be to append this customizable jumbotron to the main container for each successful request. If the channel returns null then an OFFLINE default state will be displayed. If the channel returns a data Object then the corresponding data for that channel will be used to customize the ONLINE display.

This will all occur within the success function. I have made several variable shortcuts from the data to make this process easier. Everything else in the JS file will remain the same for now so let’s take a closer look at the modified status_details function:

Resulting in:

Did I mention how much I like when things just work!

Well that looks rather hideous as usual. Time for some styling and a reVamp (eh eh?) of the code.

As the code above stands it doesn’t actually function completely — when a channel is returned as null absolutely nothing is passed in the success function. So adding the channel name and logo has to occur in the convert_username function instead to give every channel, regardless of online status, at least a name and logo for identification.

Looking ahead at embedding the stream and chat I will need to include an accordion setup as well. Let’s move onto embedding the stream and chat and seeing what muckery is required before I get to building.

Embedding Stream and Chat

Relevant API Link(s):

Returns:

Embedding the stream gives two options — embed as a javascript object with a DOM element anchor or as an iFrame.

  • Javascript route [my comments]
// twitch javascript file link
<script src= "http://player.twitch.tv/js/embed/v1.js"></script>
// player anchor in DOM
<div id="<player div ID>"></div>
<script type="text/javascript"> // mandatory settings
var options = {
width: <width>,
height: <height>,
channel: "<channel ID>",
video: "<video ID>",
collection: "<collection ID>",
};
// instantiating the player object
var player = new Twitch.Player("<player div ID>", options);
// optional player object attributes
player.setVolume(0.5);
</script>
  • iFrame route [my comments]
<iframe// <channel, video, or collection> is input as 
// channel=channel_name etc.

src="http://player.twitch.tv/?<channel, video, or collection>"
height="<height>"
width="<width>"
frameborder="<frameborder width>"
scrolling="<scrolling>"
allowfullscreen="<allowfullscreen>">
</iframe>

Looking at the two there is a distinction of “interactive” [script] and “non-interactive” [iFrame].

However, in testing I did not notice any difference. I think it comes down to the script version having more controllability through JS (forcing play/pause, ads, etc). None of these are necessary for my application so I am going to choose the iFrame route for simplicity.

Relevant API Link(s):

Returns:

  • iFrame is the only option for chat
<iframe 
frameborder="<frameborder width>"
scrolling="<scrolling>"
id="<channel>"
src="http://www.twitch.tv/CHANNEL_NAME/chat"
height="<height>"
width="<width>">
</iframe>

Functionally it works the exact same as the stream iFrame. These are pretty straightforward to put into the doc. The only customization required will be entering a unique channel name for each stream channel.

Phase 2 — Building

Goals

  • Each channel will have its own channel banner built per data request. Each channel banner will house the channel logo, the name of the channel, and the current game being streamed. If no game is present this section will report ‘Offline’.
  • The banner will have a default red box shadow behind it (to signify offline status) and when actively streaming this shadow will turn green (to signify online status).
  • When the channel is streaming the user can activate an expanding accordion on click.
  • The accordion will house two divs — one containing the stream and the other containing the chat. When the accordion is closed the stream and chat are closed so as to prevent overlapping content and resource drain.
  • No rule will be set in place against having multiple accordions (streams and chats) open at the same time although it will be up to the user to mute the channels or endure a cacophony of stream chatter.

Reach Goals

  • Enable user login to Twitch and automate the channel selection process based on their channel subscriptions

Channel Banner

For starters I need a generic channel banner with space for the channel logo, name, and currently streaming game

Now since the last project I have taken some time to up my CSS game. Nowhere near wizard status but I have to say I am feeling more confident. Thanks to Richard Middleton for his CSS-Tricks FlexBox tip and a healthy dose of late night muckery on codepen — I present the channel banners!

Example banners (red and green glows for online / offline status) Is FCC ever online…?

And a view of the embedded stream and chat. Shoutout to RealKraftyy my favorite Destiny streamer!

Free Code Camp — Twitch Project: MultiTwitch channel expanded view

Alright so things are working and fancy looking. Let’s take a peek at the insides and see how it was all done

Reach Goal

After some light digging I came across a way to achieve my reach goal

Combining this with the previously mentioned Twitch Javascript SDK I will be able to have a user login and pull the and customize the display with the channels they follow!

The Twitch JS SDK is very straight forward in terms of adding the login button and loading the SDK to handle the authentication process. With one little caveat…of course.

So I will save you the struggle of running into the issue that plagued me for way too long. If you remember earlier when registering your app with Twitch to receive your client ID you were asked to set a ‘redirect URL’. Well I took their instructions — literally — and set it to ‘http://localhost’.

The problem is that ‘http://localhost’ is a generic path to where your website is being tested. For example when I load a preview of my website through the Webstorm IDE it opens in a chrome window that begins with ‘http://localhost’ but then continues to display the entire filepath to my project.

So if you leave that redirect URL to the generic term suggested by twitch you will receive a ‘localhost refused to connect’ error until your eyes bleed. In order to fix this change the redirect URL to be the FULL path to your project (just copy and paste the URL from your project preview in your browser). This fixes the issue and lets you continue testing with 100% less self harm.

the url should look like a filepath to your project

Next up you will want to customize the scopes requested during login. These are essentially the permissions that your app / website will request on behalf of the user. Now for my purposes I reduced the scope to the bare minimum needed to pull their channel follows. This scope is ‘user_read’ only.

This isn’t obvious at first (I thought it was asking for personal information — of which I have no use for) based on the descriptions in the scopes options link above. But after some testing I found that this scope is required to be able to get the user’s followed channels.

To be clear this scope is set in the Twitch.login method supplied by the Twitch JS SDK.

Set your comma separated scopes here

Up next was converting the user from their OAuth Token (returned after login authentication) to a user ID that can later be used to pull their followed channels.

Below is the commented code which:

  1. takes the token passed by successful user authentication (after login redirects back to your page)[code snippet 1]
  2. converts the OAuth token to a user ID for the logged in user [code snippet 2]
  3. passes that ID to another call to populate an array of the user’s channels [code snippet 2]
Code Snippet 1 — Document Ready Function checking for authentication
Code Snippet 2 — Convert OAuth Token and populate channel_names array with user’s channels

Reach goal…Reached! High five to my friendless self.

Phase 3 — Finalizing and Deploying

Finalizing

I was not pleased with the aesthetic of the site at this point. I made quite a few modifications using my fancy new CSS skills to prettify things.

Up next I added a popover modal that appears for new users / users that are not logged in. This display instructions on how to login and how to expand the online channel banners to display the stream and chat.

Free Code Camp — Twitch Project: MultiTwitch Landing Page

I quite like the new look of the page. The channel banner is split from the currently streaming game / stream status div so that when it expands they encapsulate the stream and chat.

Here is a full look at the final code being deployed. Everything is heavily commented but feel free to post any questions if you need more clarification:

And the CSS I’m so proud of…

So here I am. Feeling accomplished. Ready to share my new tool with the world. Nothing can go wrong at this point. I simply upload my files to my host, run over to my twitch app and update the redirect url and I’m ready to go right?

Right?

WRONG!

Once again an issue pops up. This one is madness. What could possibly be missing? I know I am entering the url properly. Yet no matter what happens I keep getting a failed redirect. So once again Vamp will help maintain your blood pressure with a little tip. Your redirect URL must be EXACT including a single demon-spawn of a slash at the end. Thank you to this Twitch API forum post that (eventually) saved my night.

Bless you DallasNChains

Phew. What a journey. Anyways I hope you love and use the tool as much as I do and am. If you have any suggestions for improvements or more features to add please let me know I’d like to hear them.

Thanks for reading and stay tuned for my struggles with completing the intermediate and advanced algorithms!

--

--

Vamp

Full Stack Developer. Chemical Engineer. I try to sleep but all I want to do is learn.