""" UTubeAPI.py A simple, workable library for accessing the YouTube API with Python. Copyright 2007 Jesse Legg THIS SOFTWARE IS SUPPLIED AS IS WITHOUT ANY WARRANTY OF ANY KIND, AND MAY BE COPIED, MODIFIED OR DISTRIBUTED IN ANY WAY, AS LONG AS THIS NOTICE AND ACKNOWLEDGEMENT OF AUTHORSHIP REMAIN Requires ElementTree 1.2.6, available from http://effbot.org/zone/element-index.htm Updated: May 18, 2007 Example usage: >>> import utubeapi >>> ut = utubeapi.UTubeAPI('developer_id') >>> me = utubeapi.UTubeUser(ut, 'my_youtube_username') >>> print me.first_name >>> for friend in me.get_friends(): ... print friend.first_name >>> video = utubeapi.UTubeVideo(ut, 'video_id') >>> print video.title >>> len(video.comment_list) >>> pl = utubeapi.UTubePlaylist(ut, 'playlist_id') >>> for video in pl.get_videolist(): >>> print video.title >>> print 'This playlist is %s seconds long' % pl.get_playtime() You can also use the API object directly. All YouTube API calls are implemented and return a dictionary with keys corresponding to the tags in the YouTube API response. Each method is converted directly from the YouTube API name, with periods replaced by underscores and 'youtube' removed. E.g. youtube.users.get_profile --> object.users_get_profile() Pass the appropriate parameters to the UTubeAPI methods as named arguments. E.g. ut.users_get_profile(user='jlegg80') ut.videos_list_by_tag(tag='comedy', page=2, per_page=20) NOTE: You do not need to pass your developer id as an argument. """ import elementtree.ElementTree as ET import urllib import time, datetime import math def utube_time2datetime(utime): time_str = time.ctime(float(utime)) time_lst = time.strptime(time_str, "%a %b %d %H:%M:%S %Y") return datetime.datetime(*time_lst[0:7]) class UTubeError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class UTubeVideo: """ Construct with a UTubeAPI object and video id as parameters. Returns a UTubeVideo object with class variables corresponding to tags in . For example: self.author, self.thumbnail_url, self.comment_list, etc. See YouTube API docs. """ def __init__(self, api, id): self.api = api self.id = id details = self.api.videos_get_details(video_id=self.id) for elem in details.keys(): self.__dict__[elem] = details[elem] self.upload_time = utube_time2datetime(self.upload_time) self.update_time = utube_time2datetime(self.update_time) class UTubePlaylist: """ Construct with UTubeAPI object and playlist id as parameters. Only works for playlists < 100 videos """ def __init__(self, api, id): self.api = api self.id = id self.video_list = list() playlist = self.api.videos_list_by_playlist(id=self.id,page=1,per_page=100) for v in playlist: self.video_list.append(UTubeVideo(self.api, v['id'])) def get_videolist(self): """ Returns the list of videos in the playlist """ return self.video_list def get_playtime(self): """ Returns the total length of time for the playlist (in seconds) """ length = 0 for v in self.video_list: length += int(v.length_seconds) return length class UTubeUser: """ UTubeUser objects includes all information about a YouTube user that is accessible from the API. - User profile information (self.first_name, self.age, self.homepage, see API docs for details) - List of favorites (10 maximum, API limitation) via get_favorites method - List of uploads via get_uploads method - List of friends via get_friends method Each method can be passed refresh=True to force reconnect to YouTube and download new information. Otherwise this only occurs the first time called per object. """ def __init__(self, api, id): self.api = api self.id = id self.uploads = list() self.friends = list() self.favorites = list() details = self.api.users_get_profile(user=self.id) for elem in details.keys(): self.__dict__[elem] = details[elem] def get_favorites(self, refresh=False): """ Downloads a user's favorite videos list. Returns a list of UTubeVideo objects that is cached until called with refresh=True NOTE: Currently the YouTube API only returns a maximum of 10 favorites per user! """ if refresh or len(self.favorites) == 0: favorites = self.api.users_list_favorite_videos(user=self.id) self.favorites = [UTubeVideo(self.api, x['id']) for x in favorites] return self.favorites def get_friends(self, refresh=False, page=1, per_page=20): """ Downloads a user's friends list Can be passed page and per_page parameters to download in paginated form. Returns list of UTubeUser objects that is cached until called with refresh=True """ if refresh or len(self.friends) == 0: friends = self.api.users_list_friends(user=self.id, page=page, per_page=per_page) self.friends = [UTubeUser(self.api, x['user']) for x in friends] return self.friends def get_uploads(self, refresh=False, page=1, per_page=20): """ Downloads user's uploaded video information. Can be passed page and per_page parameters to download in paginated form. Returns list of UTubeVideo objects that is cached until called with refresh=True. NOTE: If called after get_all_uploads(), refresh parameter must be True. """ if refresh or len(self.uploads) == 0: uploads = self.api.videos_list_by_user(user=self.id, page=page, per_page=per_page) self.uploads = [UTubeVideo(self.api, x['id']) for x in uploads] return self.uploads def get_all_uploads(self, refresh=False): """ Downloads information for every uploaded video by this user Does not paginate data. This downloads details on EVERY video the user uploaded and could require some time to execute. Returns list of UTubeVideo objects. """ if refresh or len(self.uploads) == 0: if int(self.video_upload_count) <= 100: uploads = self.api.videos_list_by_user(user=self.id, page=1, per_page=self.video_upload_count) self.uploads = [UTubeVideo(self.api, x['id']) for x in uploads] else: pages = math.ceil(float(self.video_upload_count) / 100.00) uploads = list() for p in range(pages): uploads.append(self.api.videos_list_by_user(user=self.id, page=p+1, per_page=100)) self.uploads = [UTubeVideo(self.api, x['id']) for x in uploads] return self.uploads class UTubeAPI: """ Python interface to the You Tube API Pass your developer id as a parameter to the class constructor. """ def __init__(self, dev_id): """ Initialize a new UTubeAPI object, constructed with developer ID """ self.dev_id = dev_id self.api_base_url = 'http://www.youtube.com/api2_rest?method=' def process_element(self, e): return dict([(x.tag, x.text) for x in e.getiterator()]) def iterate_over_tag(self, url, list_tag, item_tag=None): tree = ET.parse(urllib.urlopen(url)) time.sleep(1) root = tree.getroot() if root.get('status') == 'fail': code = root.find('error/code').text reason = root.find('error/description').text raise UTubeError, '%s %s' % (code, reason) if item_tag: return tree.find(list_tag).getiterator(item_tag) else: return tree.find(list_tag).getiterator() def ut_rest_method(self, method, **args): param_list = ['&' + x + '=' + str(args[x]) for x in args.keys()] param_str = '&dev_id=%s' % self.dev_id + ''.join(param_list) return self.api_base_url + method + param_str def users_get_profile(self, **args): url = self.ut_rest_method('youtube.users.get_profile', **args) return dict([(x.tag, x.text) for x in self.iterate_over_tag(url, 'user_profile')]) def users_list_favorite_videos(self, **args): url = self.ut_rest_method('youtube.users.list_favorite_videos', **args) return [self.process_element(x) for x in self.iterate_over_tag(url, 'video_list', 'video')] def users_list_friends(self, **args): url = self.ut_rest_method('youtube.users.list_friends', **args) return [self.process_element(x) for x in self.iterate_over_tag(url, 'friend_list', 'friend')] def videos_get_details(self, **args): url = self.ut_rest_method('youtube.videos.get_details', **args) tree = ET.parse(urllib.urlopen(url)) root = tree.getroot() if root.get('status') == 'fail': code = root.find('error/code').text reason = root.find('error/description').text raise UTubeError, '%s %s' % (code, reason) video_details = tree.find('video_details') comment_list = video_details.find('comment_list').findall('comment') channel_list = video_details.find('channel_list') details = dict([(x.tag, x.text) for x in video_details.getiterator()]) comments = [self.process_element(x) for x in comment_list] channels = [self.process_element(x) for x in channel_list] details['comment_list'] = comments details['channel_list'] = channels # some hackery... if details.has_key('comment'): del details['comment'] if details.has_key('channel'): del details['channel'] return details def videos_list_featured(self): url = self.ut_rest_method('youtube.videos.list_featured') return [self.process_element(x) for x in self.iterate_over_tag(url, 'video_list', 'video')] def videos_list_popular(self, time_range): url = self.api_base_url + 'youtube.videos.list_popular&dev_id=%s&time_range=%s' % (self.dev_id, time_range) return [self.process_element(x) for x in self.iterate_over_tag(url, 'video_list', 'video')] def videos_list_by_tag(self, **args): url = self.ut_rest_method('youtube.videos.list_by_tag', **args) return [self.process_element(x) for x in self.iterate_over_tag(url, 'video_list', 'video')] def videos_list_by_user(self, **args): url = self.ut_rest_method('youtube.videos.list_by_user', **args) return [self.process_element(x) for x in self.iterate_over_tag(url, 'video_list', 'video')] def videos_list_by_related(self, **args): url = self.ut_rest_method('youtube.videos.list_by_related', **args) return [self.process_element(x) for x in self.iterate_over_tag(url, 'video_list', 'video')] def videos_list_by_playlist(self, **args): url = self.ut_rest_method('youtube.videos.list_by_playlist', **args) return [self.process_element(x) for x in self.iterate_over_tag(url, 'video_list', 'video')] def videos_list_by_category_and_tag(self, **args): url = self.ut_rest_method('youtube.videos.list_by_category_and_tag', **args) return [self.process_element(x) for x in self.iterate_over_tag(url, 'video_list', 'video')] if __name__ == '__main__': print "Please read the opening comments of this file for usage!"