Twitch Streamer App using AngularJs

twitch_streamer_api_app

I recently went to create a twitch streamer app. It wasn’t actually an app you can use to watch Twitch videos, it certainly can be done, but it was way to long for a CodePen app, and I was only trying to accomplish Free Code Camp’s project.

Anyway, the objective is to play around with Twitch API.

There’s a complete list of how you can handle the API on GitHub. It’s pretty neat and deep.

Take a peek if you're interested!

I integrate this project with Angular as it’s UI framework.

Nothing fancy though, only making use of routing and several directives to achieve SPA (Single Page Application).

Let me show you some of it’s code.

To build the app, you need to instantiate using angular.module() . You will almost always refer to your app using this method. Best way is to keep it inside a variable.

var app = angular.module('twitch_streamer', ['ngResource', 'ngRoute']);  

Inject several modules: ngResource and ngRoute.

We’re going to use ngResource to handle HttpRequest.

It’s a bit tricky due to cross domain issue. It’s this thing called ‘Same Origin Policy‘ , read it up if you’re interested. Even more, take a look on CORS.

Next up, you might want to configure your routings:

.when('/', {
    template: A,
    controller: 'mainController'
  })
  .when('/teams', {
    template: B,
    controller: 'teamController'
  })
  .when('/search', {
    template: C,
    controller: 'searchController'
  })
  .otherwise('/');
}]);

Where A:

<section class="content container-fluid" id="content">  
  <div class="headings">{{ headings }}</div>
  <div class="row result-wrapper">
    <div ng-repeat="prop in result.featured">
      <div class="col-xs-12 col-sm-4 col-lg-2 video-wrapper">
        <h3 class="video-title">{{ prop.title }}</h3><img ng-src="{{ prop.stream.channel.logo }}" class="img-responsive center-block">
        <div class="video-content" ng-Class="{" online ": prop.stream.channel.mature}">{{ status(prop.stream.channel.mature) }}</div>
      </div>
    </div>
  </div>
</section>  

B:

<section class="content container-fluid" id="content">  
  <div class="headings">{{ headings }}</div>
  <div class="row result-wrapper">
    <div ng-repeat="prop in result.teams">
      <div class="col-xs-12 col-sm-4 col-lg-2 video-wrapper" ng-hide="$first">
        <h3 class="video-title">{{ prop.display_name }}</h3><img ng-src="{{ image(prop) }}" class="img-responsive center-block">
        <div class="team-content"></div>
      </div>
    </div>
  </div>
</section>  

and, C:

<section class="content container-fluid" id="content">  
  <div class="headings">{{ headings }}</div>
  <div class="row result-wrapper">
    <form ng-submit="search()">
      <input type="text " class="search-input " placeholder="search for channels " ng-model="input" />
    </form>
    <div ng-repeat="prop in result.channels ">
      <div class="col-xs-12 col-sm-3 video-wrapper " id="search-wrapper " ng-click="onContentClick() ">
        <h3 class="video-title ">{{ prop.display_name }}</h3><img ng-src="{{ image(prop) }} " class="img-responsive center-block ">
      </div>
    </div>
  </div>
</section>  

Pardon me for having an unseparated document for the templates.

Looks a bit nasty, don’t you think? 🙂 I put this up on CodePen so having a separate document is not an option.

If you decided to split things up, don’t forget to change template  to templateUrl .

To work on the HttpRequest, you need to set up a factory.

app.factory('HttpRequest', ['$resource', function($resource) {  
  var resource = $resource('https://api.twitch.tv/kraken/:query/:else');
  resource.search = $resource('https://api.twitch.tv/kraken/search/channels?q=:query');
  return resource;
}]);

Factories is similar to services and providers.

Both factory and service functioned to create objects so you can inject it to controllers or other services.

Factory returns an object that will be the one to be injected to your controllers, on the other hand a service act as a function constructor which will be instantiated on the background.

On that code, we name the factory HttpRequest and set an array of injected services.

Array is use to avoid problems related to JavaScript minification.

You see, Angular use this so called ‘dependency injection‘ which literally just passing object around.

To know which object you requested, they evaluate the string given in the function argument.

function($resource){ ... }  

You don’t put your own variable, instead you specify what services you want Angular to inject to your function.

In this case, you requested $resource service.

You might be wondering how this went through, well, JavaScript function is literally just object, and you might guess, object can be coerced into string using the built-in .toString() method.

This way, you can parse function and see what the arguments are.

Head on to the controllers.

I’ve built three separate controllers, each targets a different template.

First one is for the Featured page.

app.controller('mainController', ['$scope', 'HttpRequest', function($scope, HttpRequest) {  
  $scope.result = HttpRequest.get({
    query: 'streams',
    else: 'featured'
  });
  $scope.headings = 'Featured Channels';
  $scope.status = function(bool) {
    return bool ? 'Online' : 'Offline';
  };
}]);

Two services are injected to this controller. You can see that we use array to overcome the dependancy injection issue. String will not be minified as if to function arguments.

We tell Angular to put $scope  for the first argument, HttpRequest  for the second. In this case, the name of the argument doesn’t matter anymore.

Using the built-in HttpRequest , we haven’t actually called a request out to a server just yet. Using the .get()  method we initiate the request.

Previously we set a placeholder for our query:

Now we set the placeholder to the desired instruction. In this case, query will be replaced by ‘streams’ and so does else with ‘featured’.

Head on to the next controller:

app.controller('teamController', ['$scope', 'HttpRequest', function($scope, HttpRequest) {  
  $scope.result = HttpRequest.get({
    query: 'teams'
  });
  $scope.headings = 'Active Teams';
  $scope.image = function(obj) {
    if (obj.logo === null) {
      return 'https://cdn1.iconfinder.com/data/icons/simple-icons/256/twitch-256-black.png';
    } else {
      return obj.logo;
    }
  };
}]);

Nothing fancy, only a single request specifying the query placeholder, change the heading, and apply placeholder images for results in case images are not supported.

Okay then, next one!

app.controller('searchController', ['$scope', 'HttpRequest', function($scope, HttpRequest) {  
  $scope.headings = 'Search Channels';
  $scope.input = '';
  $scope.show = false;
  $scope.httpReq = function() {
    var a = HttpRequest.search.get({
      query: $scope.input
    });
    return a;
  };
  $scope.search = function() {
    $scope.result = $scope.httpReq();
  };
  $scope.image = function(obj) {
    if (!obj.logo) {
      return 'https://cdn1.iconfinder.com/data/icons/simple-icons/256/twitch-256-black.png';
    } else {
      return obj.logo;
    }
  };
}]);

Well, it’s actually pretty much the same with previous controllers, this time it handles the Search Channel page.

What differentiate this controller is only by the way it request and make use of the API. You definitely need to check on the Twitch API GitHub page if you’re bit curious about how these things work.

That’s all for the JavaScript, it all went around JavaScript only since markups are used as a template in this Angular app.

Little bit of the HTML peek:

<div ng-app="twitch_streamer">  
  <section id='navigation-bar'>
    <div class='header'>
      <div class='logo'> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/26/Twitch_logo.svg/2000px-Twitch_logo.svg.png" class='img-responsive'> </div>
    </div>
    <div class="link-wrapper">
      <ul class="nav nav-pills nav-stacked">
        <li role="presentation"><a href="#/">Featured</a>
        </li>
        <li role="presentation"><a href="#teams/">Active Teams</a>
        </li>
        <li role="presentation"><a href="#search/">Search Channel</a>
        </li>
      </ul>
    </div>
  </section>
  <div ng-view></div>
</div>  

Haven’t taught myself about code style when doing this project, so this code style is a little random. No naming conventions like BEM (Block Element Modifier).

Anyway, cheers!

Simple Weather App

On today’s blog I’d like to share how you can build a convenient weather app using the OpenWeather API.

simple weather app using openweather api

You might want to check the source code at Codepen.

I have worked on the JavaScript so I assume that it’s pretty neat, does it 🙂 But I got to admit that the CSS is not as clean as you might wanted to. I’m still working on bringing the best practice as possible to my projects (without altering previous projects to see progress I have made).

When you click on “search”, this code suppose to run. It will add HTML to several elements using jQuery, and with an addition of the corresponding image related to the result. So, if the weather is cloudy, then the image will be more of a clouds (but it won’t appear in CodePen since I put the images on my own computer :D, you might want to tweak that out).

Creating a Random Quote Generator

I was playing around with this new project from Free Code Camp, you can check it out here.

So basically what you have to do is to create a simple random quote machine which would generate new quotes every time you click on the button, yet it needs to have certain transition.

I just figured out what makes a transition and animation different, since I noticed they are quite the same thing. You can glimpse on the tutorial right below:

The point is, what makes them different is the trigger, loop, and keyframe.

Animations don't require any explicit form of triggering, once you define an animation, it will start playing automatically once the browser read the statement, whereas a transition does have scenario of triggering, such as when you hover into an element.

Next up is looping where an animations may have predefined iteration setting, such like:

animation-iteration-count: 2;

or making it it plain infinite .

Another key point is the keyframes. You can marked up any keyframe you'd like on an animation, and having a precise control on when that keyframe would fire up. Here's the visualisation I got from Kirupa.

keyframes on animation

Back on the project itself, it may seem that this was so damn easy. It's true since I meant this for beginners, myself including.

Here's what my code would generated into:

random quote generator 2

Though you can style it way better, yet it has the main functionality as it supposed to.

Mind that I will use Visual Studio Code from Microsoft through out this post.

Here's what my HTML look like:

<!DOCTYPE html>  
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
        <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
        <link rel="stylesheet" href="css/index.css" type="text/css">
        <script src="index.js"></script>
        <title>Quote generator!</title>
    </head>
    <body>
        <div class="container-fluid">
            <div class="row">
                <blockquote>
                    <div class="col-xs-12">
                        <p class="quote roboto"><h2><span class="quote">"Get shit done."</span></h2></p>
                        <div class="text-right cite">- unknown</span></div>
                    </div>
                    <div class="row">
                        <div class="col-xs-6">
                            <a  title="Tweet this quote"><button class="tweet"><i class="fa fa-twitter"></i></button></a>
                            <a title="Post on Tumblr!" href="https://embed.tumblr.com/share"><button class="fa fa-tumblr tumblr"></button></a>
                        </div> 
                        <div class="col-xs-6">
                            <button class="roboto fontSizeSmall">New Quote!</button>
                        </div>
                    </div>
                </blockquote>
            </div>
        <div class="footer">by Vitto Lewerissa</div>    
        </div>
    </body>
</html>

Frankly it's quite not the best code I've written yet. I'd say it's way too long, a couple of div's would just be fine. Still, it's the code I've written for the projects, though. It's not perfect, but whatever, as my motto says: it's about PROGRESS :)

Let me break down to a smaller pieces.

It will start off with the head tag:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>  
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="stylesheet" href="css/index.css" type="text/css">
<script src="index.js"></script>
<title>Quote generator!</title>

It is a simple import task, where I include the jQuery library on the first line, a mere Bootstrap CDN on the second line, a Google Font (which I supposed to include it in the CSS file instead using the @import), a Font Awesome CDN, and eventually the my own CSS and JavaScript relative link.

<body>  
    <div class="container-fluid">
        <div class="row">
            <blockquote>
                <div class="col-xs-12">
                    <p class="quote roboto"><h2><span class="quote">"Get shit done."</span></h2></p>
                    <div class="text-right cite">- unknown</span></div>
                </div>
                <div class="row">
                    <div class="col-xs-6">
                        <a  title="Tweet this quote"><button class="tweet"><i class="fa fa-twitter"></i></button></a>
                        <a title="Post on Tumblr!" href="https://embed.tumblr.com/share"><button class="fa fa-tumblr tumblr"></button></a>
                    </div> 
                    <div class="col-xs-6">
                        <button class="roboto fontSizeSmall">New Quote!</button>
                    </div>
                </div>
             </blockquote>
         </div>
        <div class="footer">by Vitto Lewerissa</div>    
   </div>
</body>

Here is where I thought the immense (if not exaggerating) occur :(

When I finish this code and think thoroughly. I figured out that several lines are not required, but I was eager to finish the project so that I could continue to the next project. I know, it's not a good thing to left by, it would a great disaster if this happen by the office in terms of maintenance.

Anyway, I figure to use the Bootstrap predefined class container-fluid instead of the container so the page will generate on a wide scale, and I would easily configure it using the margin-auto  by the CSS file.

I added some extra unnecessary div's all the way through ;-)

Further down, an anchor tag to sustain the button elements.

Ignore the href attribute which links to some disrupted page in Tumblr. Not the wisest way to share a post though (a decent Tumblr API should go the way before :")).

Let's proceed on this middling CSS file:

@charset "UTF-8";  
body {  
  background-color: #D102CA;
  transition: 1.5s;
}

div.row {  
  margin: auto;
  margin-top: 100px;
  width: 500px;
}

blockquote {  
  border-radius: 7px;
  background: #f9f9f9;
  text-align: center; 
}

blockquote > p {  
  display: inline; 
}

.roboto {
  font-family: "Roboto", sans-serif; 
}

.fontSizeSmall {
  font-size: 0.8em;
}

button {  
  margin-top: 10px;
  margin-bottom: 10px;
  transition: 1.5s;
  background-color: #D102CA;
  font-size: 1em;
  border: none;
  border-radius: 3px;
  padding: 7px;
  color: white;
}

button:hover {  
  opacity: 0.6;
}  

span.quote {  
  color:#D102CA;
}

.footer{
  text-align: center;
  color: white;
}

div.cite {  
  color: grey;
}

.tweet {
  position: relative;
  right: 80px;
  min-width: 40px; 
}

.tumblr {
  position: relative;
  right: 70px;
  bottom: 1px;
  min-width: 40px;
  min-height: 39px;
}

It is not a hard task to scan all the way through the CSS file. It's quite brief.

Not the best yet, but frankly not a monstrous stylesheet anyway.

I would not hash around the CSS as it is easy to digest in my humble opinion.

Let's get down to the dirty part if I may say.

$(document).ready(function(){  
    var temporary;
    var quote = "\"Get shit done.\"";
    var random = function(){
        var temp = (Math.floor(Math.random() * 5)) + 1;
        var quoteArray = ["\"Get up and Code!\"","\"Let them see results in 5 YEARS!\"","\"Let them spend while you SAVE.\"","\"Let them sleep while you GRIND.\"","\"Let them party while you WORK.\""];
        while(temp === temporary){
            temp = (Math.floor(Math.random() * 5)) + 1;
        }
        temporary = temp;
        quote = quoteArray[temp - 1];
        var fadeIn = $("span.quote").delay(750).fadeIn();
        var unknownFade = $(".cite").delay(750).fadeIn();
        switch(temp){
            case 1: 
                $("span.quote").html(quoteArray[0]);
                $("body").css("background-color", "#34B5E0");
                $("button").css("background-color", "#34B5E0");
                $("span.quote").css("color", "#34B5E0");
                unknownFade();
                fadeIn();
                break;
            case 2: 
                $("body").css("background-color", "#E33977");
                $("button").css("background-color", "#E33977");
                $("span.quote").html(quoteArray[1]);
                $("span.quote").css("color", "#E33977");
                unknownFade();
                fadeIn();
                break;
            case 3:
                $(".cite").fadeIn();
                $("body").css("background-color", "#259C08");
                $("button").css("background-color", "#259C08");
                $("span.quote").html(quoteArray[2]);
                $("span.quote").css("color", "#259C08");
                unknownFade();
                fadeIn();
                break;
            case 4: 
                $("body").css("background-color", "#C27F0C");
                $("button").css("background-color", "#C27F0C");
                $("span.quote").html(quoteArray[3]);
                $("span.quote").css("color", "#C27F0C");
                unknownFade();
                fadeIn();
                break;
            case 5:
                $("body").css("background-color", "#C9B902");
                $("button").css("background-color", "#C9B902");
                $("span.quote").html(quoteArray[4]);
                $("span.quote").css("color", "#C9B902");
                unknownFade();
                fadeIn();
                break;
        }
    };

    $("button.tweet").click(function(){
        var array = quote.split(" ");
        var joinArray = array.join("%20");
        var total = "https://twitter.com/intent/tweet?text=" + joinArray + " - Unknown";
        // var test = "http://twitter.com";
        window.location.replace(total);
    });

    $(":button").click(function(){
        $(".cite").hide();
        $("span.quote").hide();
        random();
    } );
});

There are way much more better way rather than using the switch statement. A JSON is another delicate, if not elegant, way to shorten the code.

Basically, what I did is using the jQuery method of hide()  and fadeIn()  to gain the effect of transition. There would a be a delay (, so the transition would seen on the play.

The Math.random()  is used to  come up with a pseudo-random number between 0 (inclusive) to 1 (exclusive). There you need to twist on the expression.

The temp  variable will hold on the result and thus go through the switch statement.

Any comment regarding my code will be highly appreciated as it will help me to attain progress :)