Like me you probably have several YouTube channels that you like to follow. Maybe you enjoy that crazy cat video channel or the channel which shows stupid people doing stupid stuff. Either way you want to bring those favorite channels to the world in all their glory on your site. One thing you want to do however is combine those channels into one feed and display the feed on your site using some JavaScript. Well you have come to the right place. Here we will show you some code that will allow you to take the videos of one YouTube feed and mix it with one or more other channels to create your own super list of videos. Let’s dive in!
First order of business is to locate the feeds we want to put together from YouTube. We are looking to get these feeds through the YouTube API URLs that start with gdata.youtube.com. Now I have noticed that there are at least 2 username formats for these feeds. One seems to be for older channels and then a newer format for newer channels. Older channels seem to follow a format of http://gdata.youtube.com/feeds/users/<username>/uploads and the newer one seems to follow the format http://gdata.youtube.com/feeds/users/<random string>/uploads. They are similar but the newer ones seem to have a random string for their username. For these two feeds you will see we are targeting the “uploads” video streams. Other types of feeds may have different fields and you will have to customize the script below to pull out the various pieces of info based on their schema. I believe the favorites version 2 feeds also conform to the same format so you might be pretty good there.
One thing we will also want to do is make sure that we get the JSON format of these feeds. We can do that by simply attaching a parameter onto the URLs I mention above. Just by adding “alt=json” to the URLs we can get the same info in JSON instead of the default XML. This will make it a bit easier for us to bring this data right into our JavaScript code. So for instance to get the uploads feed for the channel “Machinima”, in JSON format, the URL will be http://gdata.youtube.com/feeds/users/machinima/uploads?alt=json. You can clean this up by using a tool called “The Prettifier” to make it more readable. Since Machinima is an older feed you will notice that its username is right there in the URL. For our demo we are going to bring in Machinima and a new channel I follow called “Funhaus”.
Below we are going to start by creating an array of feed URLs that we want to merge. For this demo we put together the two channels uploads feeds. But if the feeds match you could mix the user’s favorites feed along with uploads feed etc.
// List of feeds we want to list and merge together. We put this into an array. var feeds = [ "http://gdata.youtube.com/feeds/users/boMX_UNgaPBsUOIgasn3-Q/uploads", "http://gdata.youtube.com/feeds/users/machinima/uploads" ];
The first feed is our Funhaus channel and again the second is Machinima. Once we have specified all the URLs we want to merge together, we need to fetch each one’s JSON data. We can do this real quick using a jQuery $.ajax() call and tacking on our JSON parameter. For this code I also put on a nocache parameter. This parameter will make sure we get the most recent videos and that we have no funny caching problems. One thing to note here is that we can do a cross domain call here because YouTube has been nice enough to allow it through their origin setting.
Anyways, we will make the AJAX call for each feed and, if successful, we will append the videos to an array for sorting afterwards. One thing I also want to point out is that we are doing this synchronously. Meaning we are going to halt the script until we get the data back. One reason for this is that if we don’t do it this way the script would continue to process before we receive results and the script would most likely finish before YouTube can give us the information we want. We want to make sure all data is loaded into the array before we continue the script.
// Get each feed from the list above and append their videos // to a list for sorting and displaying. function getFeeds() { var entries = []; for (var i = 0; i < feeds.length; i++) { $.ajax({ url: feeds[i], data: { alt : "json", nocache: "600"}, async: false, //<--- Notice we want to make sure we halt script crossDomain: true, success: function(data) { var entry = data.feed.entry; if ((entry != null) && (entry.length > 0)) { // Loop through each video in the feed and put it into an // array we will sort later. for (var i = 0; i < entry.length; i++) { entries.push(entry[i]); } } } }); } // Need at least two to compare. if (entries.length > 1) { entries.sort(compare); } response(entries); }
In the code above you see that we loop through each feed and then loop through each video in that feed. We add each video to an array. Here you could decide to only pull a limited number of videos (like 5 or 10) for each channel and add them to the list. That part is up to you. Once we have all the videos loaded into our list, we go on to sorting the list. Above you see that we called the sort() method on our array and gave it at a custom function we are going to write for sorting in a second.
We have the array loaded with some video entries and now we need to sort them. We made a call to the function “compare” and in that function we take in two videos from the list and look at their published dates. Using the comparison we decide which is going to be sorted first. Because of this we needed to make sure that there were at least two videos in the list to compare. One thing we can also rely on is that the dates in YouTube feeds are a nice Zulu time format making them easy to compare as strings. Very handy. So we don’t bother with any kind of date manipulation here. We can do the straight comparison…
// Compare two video upload entries to sort order of combined feeds. function compare(a,b) { if (a.published.$t > b.published.$t) { return -1; } if (a.published.$t < b.published.$t) { return 1; } return 0; }
I am not sure why but YouTube has decided to use a property called “$t” to represent this time data. So don’t be thrown off by the dollar sign. You will see later that this dollar sign pops up in all sorts of property names of the feeds and they are treated just as typical properties of an object.
Ok, we have a sorted list of videos now based on their published date. All that is left is to display the videos in our application. This function below will go through each video, pull out the various fields and set them to some variables. We will then use those variables to build up an HTML response. Using your own CSS styling you can make the feed look however you like and match your site or application.
In this code you will probably want to specify some of your own images for times when things like a thumbnail is not available. Or perhaps you want your own images to represent the stars used in the ratings. Once you have built up the content, all you need then is to dump that HTML somewhere. We used a standard div tag with the id of “content_div”.
// Loop through the sorted list of videos and display their details. function response(entrylist) { var html = ""; // Loop through each video in our list for (var i = 0; i < entrylist.length; i++) { var anEntry = entrylist[i]; var title = anEntry.title.$t; var thumbnail = ""; var descript = ""; var videourl = ""; var duration = 0; var ratings = ""; // If this video is restricted in some way, set description to reason. if (anEntry.app$control) { if (anEntry.app$control.yt$state) { descript = anEntry.app$control.yt$state.$t; } } if (anEntry.media$group.media$thumbnail) { thumbnail = anEntry.media$group.media$thumbnail[0].url; } else { // Use some picture for when a thumbnail is not available. thumbnail = "nopic.gif"; } if (anEntry.media$group.media$description) { descript = anEntry.media$group.media$description.$t; } if (anEntry.media$group.media$player) { videourl = anEntry.media$group.media$player[0].url; } else { videourl = "javascript:void(0);"; } if (anEntry.media$group.yt$duration) { duration = anEntry.media$group.yt$duration.seconds; } if (anEntry.gd$rating) { var rating = anEntry.gd$rating.average; ratings = displayStars(rating); } // We choose to limit our description to 150 characters, but you can certainly show the whole thing if you like. if (descript.length > 150) { descript = descript.substr(0,150) + "..."; } // Make your own classes for styling etc. html += "<div class='entry'>"; html += "<a href='" + videourl + "' target='_parent'><img src='" + thumbnail + "' class='picture' alt='" + title + "' title='" + title + "' border='0'/></a>"; html += "<a href='" + videourl + "' target='_parent'>" + title + "</a><br/>"; html += "<span class='descript'>" + descript + " " + getTime(duration) + " " + ratings + "</span>" html += "</div>"; } // Dump the content to some element of your choice. document.getElementById('content_div').innerHTML = html; }
You will see from the code above that we are using two custom functions. One for displaying our stars in the star rating and one to format the time based on the duration of the video. Below are those two functions and of course you can customize them however you like based on how you want them displayed.
// Translate duration into readable hour:min:sec format. function getTime(duration) { if (duration > 0) { var hours = Math.floor(parseInt(duration) / 3600); var minutes = Math.floor((parseInt(duration) % 3600) / 60); var secs = (parseInt(duration) % 3600) % 60; if (hours < 10) { hours = "0" + hours; } if (minutes < 10) { minutes = "0" + minutes; } if (secs < 10) { secs = "0" + secs; } return "<b>Duration</b>: " + hours + ":" + minutes + ":" + secs; } return ""; } // Translates average star rating into appropriate star pictorial. function displayStars(average) { var wholeStars = parseInt(average); var halfStars = 0; var remainder = average % 1; if ((remainder >= .25) && (remainder <= .7499)) { halfStars = 1; } if (remainder >= .75) { wholeStars++; } var emptyStars = 5 - (wholeStars + halfStars); var result = "<b>Rating</b>: "; for (var i = 0; i < wholeStars; i++) { result += "<img src='star-whole.gif' class='star'/>"; } for (var i = 0; i < halfStars; i++) { result += "<img src='star-half.gif' class='star'/>"; } for (var i = 0; i < emptyStars; i++) { result += "<img src='star-empty.gif' class='star'/>"; } return result; }
Again in the code above be sure to use your own graphics for the stars. You will need three. One to represent a whole star, one for half stars and one for empty stars. There are generally five stars for each video. All that is left now for this to all work is to kick off the loading of the video feeds from our array. We can do this with a simple windows.onload event that makes a call to the first function.
// When window loads, call out to load our feeds. window.onload = getFeeds();
That is all there is to it. It may seem like there is a lot of code to do all this, but I found that this design has afforded me a lot of flexibility and customization. I have used this code in my own custom dashboard for a few years now and I thought my readers could benefit from seeing this as well. To help see what is available, I suggest you take a few of the URLs I used in this demo and put them into a browser window. This will show you the feeds and the fields that are passed so you can see what is possible. I hope you enjoy this script and use it to build some new incredible features for your web applications. Thanks for reading! 🙂