Code Snippet: Youtube playlist downloader

A few months ago, I wrote a tiny ruby script I never released, that made it possible to download Youtube playlists and convert them to mp3 files. Unfortunately Youtube changed many things since that time and my script did not work anymore.

Private reasons and a strong will to fight the API forced me to write an alternative program for downloading Youtube playlists and convert them to mp4 files this time. Yes, I know – maybe there are already online services and programs that make this possible too, but take this as an educational code snippet for those who want to know how to download Youtube Playlist or implement the class in their own software.

This time I wrote the program in PHP and used a script from a blog I found after looooong research, ZendGdata and FFMpeg. The videos are downloaded in FLV format and converted to mp4. The code should work on unix and windows machines.

Here’s some code:

  /**    * Class to download youtube videos and convert them to MP4 format    * via FFMpeg. This class uses code from 1chris.com to download the    * video URL.       *    * Requirements:    *  -> PHP with curl
   *  -> FFmpeg (http://ffmpeg.org)
   *  -> ZendGdata library (http://framework.zend.com/download/gdata)
   *
   * See INSTALL.txt for installation instructions.
   *
   * @author Martin Albrecht
   * @version 0.1
   */
  require_once('include/ygrabber.php');
 
  define('ZEND_GDATA_NAME', 'ZendGdata-1.11.10'); // Modify this, if your version differs
  define('BASE_DIR', realpath(dirname(__FILE__).'/../'));
  define('TMP_DIR', BASE_DIR.'/tmp/');
  define('DOWNLOAD_DIR', BASE_DIR.'/output/');
 
  class YTFetcher {
    private $client = NULL;
    private $dl_data = NULL;
    private $os = NULL;
 
    /**
     * Fetch download URLs and video titles and put them in internal array
     * @param  $id The playlist ID to fetch
     * @return  The count of fetched items
     */
    private function FetchUrls($id) {
      $feedUrl = "http://gdata.youtube.com/feeds/api/playlists/$id";
      $playlistVideoFeed = $this->client->getPlaylistVideoFeed($feedUrl);
      $len = sizeof($playlistVideoFeed);
      if( $len > 0 ) {
        $this->dl_data = array($len);
        $ie = 0; // index-entries
        foreach( $playlistVideoFeed as $entry ) {
          $title = $entry->title->text;
          foreach($entry->getMediaGroup()->player as $content) {
            $this->dl_data[$ie] = array();
            $this->dl_data[$ie]['url'] = $content->url;
            $this->dl_data[$ie]['title'] = $title;
          }
          $ie++;
        }
      }
      unset($playlistVideoFeed);
      return $len;
    }    
 
    /**
     * Sanitize filenames, etc.
     * @param  $text The text to sanitize
     * @return  Sanitized string
     */
    private function Sanitize($text) {
      $search = array('ä', 'ö', 'ü', 'ß', ' ', '/', '\\');
      $replac = array('ae', 'oe', 'ue', 'ss', '_', '-', '-');
      return str_replace($search, $replac, strtolower(utf8_decode($text)));
    }
 
    /**
     * (Fetch and) return video data
     * @param  $id The playlist ID
     * @return  False on error, the data array on success
     */
    private function GetData($id=NULL) {
      if( $this->dl_data === NULL || sizeof($this->dl_data) < = 0 ) {         if( ($len = $this->FetchUrls($id)) < = 0 ) {           return false;         }        }        return $this->dl_data;
    }
 
    /**
      * Constructor
      */
    public function __construct() {
      $clientLibraryPath = dirname(__FILE__).'/'.ZEND_GDATA_NAME.'/library/';
      set_include_path(get_include_path() . PATH_SEPARATOR . $clientLibraryPath);
      include_once ZEND_GDATA_NAME.'/library/Zend/Loader.php'; // the Zend dir must be in your include_path
 
      // Check and/or create download directory
      if( !file_exists(DOWNLOAD_DIR) ) {
        mkdir(DOWNLOAD_DIR);
      }
      // Check and/or create temp directory
      if( !file_exists(TMP_DIR) ) {
        mkdir(TMP_DIR);
      }
 
      // Determine operating system
      if( strstr(strtolower(php_uname()), 'win') === false ) {
        $this->os = 'UNIX';
      } else {
        $this->os = 'WIN';
      }
      // Load ZendGdata class as client
      Zend_Loader::loadClass('Zend_Gdata_YouTube');
      $this->client = new Zend_Gdata_YouTube();
    }    
 
    /**
     * Download a playlist
     * @param  $id The playlist ID to download
     * @param  $delete Determines whether or not the temporary files are deleted
     * @param  $echo Toggles console output
     */
    public function DownloadPlaylist($id=0, $delete=true, $echo=true) {
      echo "[+] Fetching playlist data...\n";
      $this->GetData($id);
      $len = sizeof($this->dl_data);
      if( $len > 0 ) {
        if( $echo ) echo "[+] Okay, found $len entries!\n";
        $files = array();
        for($i=0; $i< $len; $i++) {               $files[$i] = TMP_DIR.$this->Sanitize($this->dl_data[$i]['title']).'.flv';
          if( !file_exists($files[$i]) ) {
            if( $echo ) echo "Downloading video file: ", $files[$i], "\n";
            $grabber = new youtubegrabber($this->dl_data[$i]['url'], $files[$i]);
          }
 
          if( $echo ) echo "[+] Converting...\n";
          $out =  DOWNLOAD_DIR.$this->Sanitize($this->dl_data[$i]['title']).'.mp4';
          if( $this->os !== 'WIN' ) {
            $cmd = 'nice -n 19 ffmpeg -y -i "' . $files[$i] . '" -vcodec copy -acodec copy "' . $out.'"';  // UNIX CALL
          } else {
            $cmd = 'ffmpeg\\bin\\ffmpeg.exe -y -i "' . $files[$i] . '" -vcodec copy -acodec libmp3lame -ab 192k "' . $out.'"'; // WINDOWS CALL
          }
          echo $cmd, "\n";
          system($cmd);
          if( $delete === true ) {
            if( file_exists($out) ) {
              unlink($files[$i]);
            } else {
              if( $echo ) echo "\n[!] Skipped: $out\n";
            }
          }
        }
      }
    }
  }

As you can see, this is only a class. A possible implementation would look like this:

require_once('include/YTFetcher.php');         
$id = "4D3F38ABB36CAC38"; // The playlist ID         
$yt = new YTFetcher();             $data = $yt->DownloadPlaylist($id);

This downloads all videos from the playlist with the id “4D3F38ABB36CAC38” and convert them. The original playlist URL is http://www.youtube.com/user/lebensraeume1#grid/user/4D3F38ABB36CAC38

I made a package that contains all you need on the windows platform. On unix systems read the included INSTALL.txt and follow the instructions, but don’t worry – it’s not hard to install. 😉

Download Packages:

All platforms: Download YTFetcher_0.1.zip

If you have any problems, find bugs, have critics, ideas or wishes, let me know – the comments are open!

Similar Posts:

  • Marshall3460

    thx a lot for share