Sunday, March 3, 2013

How to grab YouTube playback video files

How to grab YouTube playback video files

Step-by-step tutorial showing how to get all available video source files from a video on YouTube using only Javascript. No plugins and/or server side scripts are required.

First of all I want to list here a few benefits from being able to do that.

  1. You can download any video from YouTube without plugins or server-side scripts. You just need a browser.
  2. You can use YouTube as an encoder. Let's say you have to convert a FLV video to MP4 or
    WebM.
  3. You can set a cron job to run once a week to download all available video files from any channel.
  4. You can play any YouTube video out of the YouTube player (not recommend).
  5. You can play YouTube videos on HTML5 canvas and go crazy! Check this out at: http://videopuzzle.possum-cms.com

How to do it



Step 1: Extract YouTube video ID from URL

  var url = 'http://www.youtube.com/watch?v=yntfUjenls0';  
  var video_id = '';  
  var regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/;  
  var match = url.match(regExp);  
  if(match){  
   video_id = match[1];  
  }  

Step 2: Request YouTube playback files information

Easy as pie. Just make an Ajax request to: http://www.youtube.com/get_video_info sending the desired video ID...
  $.ajax({  
   url: "http://www.youtube.com/get_video_info?video_id="+video_id,  
   dataType: "text"  
  }).done(function(data) {  
   ...  
  });  


Step 3: Parse the response data information from YouTube

The information that we are looking for is "url_encoded_fmt_stream_map". This variable contains all streams available for the requested movie.

 function(data) {  
  var info = {};  
  parse_str(data, info);  
  var streams = explode(',', info['url_encoded_fmt_stream_map']);  
  ...  


Step 4: Trick. Parse again each one of the streams

YouTube encode the information twice, so you have to parse it again.
There is other trick here, You also have to add a signature value on each stream url, otherwise it won't work.

  var results = [];  
  for(var i=0; i<streams.length; i++){  
   var real_stream = {};  
   parse_str(streams[i], real_stream);  
   real_stream['url'] += '&signature=' + real_stream['sig'];  
   results.push(real_stream);  
  }  



Step 5: Have fun!


By now you should have a variable "results" with all YouTube video files available for the requested movie.

You can do whatever you want with the files. For example: display a link, play the video, grab snap shots of the video... Have fun!

To display the a link for each video file available...

   if(results.length > 0){  
    $.each(results, function(index, value) {  
     $('#results').append('<a href="'+value.url+'">'+value.quality+' - '+value.type</a>');  
    });  
   }