├── readme.txt └── youtube-dl-playlist /readme.txt: -------------------------------------------------------------------------------- 1 | youtube-dl-playlist 2 | 3 | Author: Jordon Mears 4 | License: LGPL version 2 or greater 5 | 6 | Usage: youtube-dl-playlist PLAYLIST_ID [DESTINATION_PATH] 7 | 8 | This utility allows you to download all the videos from a playlist on Youtube. 9 | It creates a folder in the current directory (or in the specified path) named 10 | after the playlist name and then downloads each video in order and places it 11 | within the folder. 12 | 13 | If the script fails in the middle of the playlist you can restart it with the 14 | same options and should pick up where it left off. 15 | 16 | Depends on: 17 | - Python (should be available on Linux/Unix/Mac by default) 18 | - youtube-dl (avaliable at http://rg3.github.com/youtube-dl/ and in repos for 19 | most Linux distros) 20 | 21 | To install: 22 | 1. Download the file youtube-dl-playlist and place it in /usr/local/bin. 23 | 2. Make sure it has execute permissions: 24 | chmod /usr/local/bin/youtube-dl-playlist 25 | 3. Install youtube-dl by placing its downloaded file in /usr/local/bin as well. 26 | It must also have execute permissions. 27 | 4. Enjoy. -------------------------------------------------------------------------------- /youtube-dl-playlist: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # youtube-dl-playlist 3 | # 4 | # Utility to download Youtube playlist videos. 5 | # 6 | # @author Jordon Mears 7 | # @license LGPL version 2 or greater 8 | 9 | import sys 10 | import urllib 11 | import httplib 12 | import json 13 | import os 14 | import shutil 15 | import tempfile 16 | import glob 17 | 18 | 19 | class PlaylistDownloader: 20 | targetDir = '' 21 | totalVideos = 0 22 | downloaded = 0 23 | 24 | def setTarget(self, target): 25 | self.targetDir = os.path.realpath(target) + '/'; 26 | return self.targetDir; 27 | 28 | def download(self, playlistId): 29 | print 'Getting playlist information ... ' 30 | data = self.fetchInfo(playlistId) 31 | self.totalVideos = int(data['feed']['openSearch$totalResults']['$t']) 32 | print 'Total videos to download: ' + str(self.totalVideos) 33 | 34 | playlistDir = self.createPath(self.targetDir, data['feed']['title']['$t']); 35 | os.chdir(self.setTarget(playlistDir)) 36 | 37 | self.downloaded = 1; 38 | while(self.downloaded <= self.totalVideos): 39 | data = self.fetchInfo(playlistId, self.downloaded, 50) 40 | self.downloadEntires(data['feed']['entry']) 41 | 42 | def downloadEntires(self, entries): 43 | for entry in entries: 44 | group = entry['media$group']; 45 | if self.downloadEntry(group['yt$videoid']['$t'], group['media$title']['$t']): 46 | self.downloaded = self.downloaded + 1 47 | print 48 | 49 | def downloadEntry(self, ytId, ytTitle): 50 | print ytId + '(' + str(self.downloaded).zfill(3) + '):', ytTitle, '...' 51 | 52 | existing = glob.glob('*' + ytId + '.*'); 53 | filtered = [x for x in existing if not x.endswith('part')] 54 | if filtered.__len__() > 0: 55 | print 'alreary exists, skipping...' 56 | return True 57 | 58 | try: 59 | os.system('youtube-dl -t --audio-format=best http://www.youtube.com/watch?v=' + ytId) 60 | return True 61 | 62 | except KeyboardInterrupt: 63 | sys.exit(1) 64 | 65 | except Exception as e: 66 | print 'failed: ', e.strerror 67 | return False 68 | 69 | def fetchInfo(self, playlistId, start = 1, limit = 0): 70 | connection = httplib.HTTPConnection('gdata.youtube.com') 71 | connection.request('GET', '/feeds/api/playlists/' + str(playlistId) + '/?' + urllib.urlencode({ 72 | 'alt' : 'json', 73 | 'max-results' : limit, 74 | 'start-index' : start, 75 | 'v' : 2 76 | })) 77 | 78 | response = connection.getresponse() 79 | if response.status != 200: 80 | print 'Error: Not a valid/public playlist.' 81 | sys.exit(1) 82 | 83 | data = response.read() 84 | data = json.loads(data) 85 | return data 86 | 87 | def createPath(self, path, title): 88 | title = title.replace('/', '') 89 | number = '' 90 | 91 | if os.path.exists(path + title) == True and os.path.isdir(path + title) == False: 92 | while(os.path.exists(path + title + str(number)) == True and os.path.isdir(path + title + str(number)) == False): 93 | if number == '': 94 | number = 0 95 | 96 | number = number + 1 97 | 98 | if os.path.exists(path + title + str(number)) == False: 99 | os.mkdir(path + title + str(number)) 100 | 101 | return path + title + str(number) 102 | 103 | 104 | 105 | if __name__ == '__main__': 106 | if len(sys.argv) < 2: 107 | print 'Usage: youtube-dl-playlist PLAYLIST_ID [DESTINATION_PATH]' 108 | sys.exit(1) 109 | else: 110 | if sys.argv[1][0] == 'P' and sys.argv[1][1] == 'L': 111 | PLAYLIST_ID = sys.argv[1][2:] 112 | else: 113 | PLAYLIST_ID = sys.argv[1] 114 | downloader = PlaylistDownloader() 115 | if len(sys.argv) == 3: 116 | downloader.setTarget(sys.argv[2] + '/') 117 | else: 118 | downloader.setTarget('./') 119 | downloader.download(PLAYLIST_ID); 120 | --------------------------------------------------------------------------------