ycdl/ytapi.py

112 lines
3.8 KiB
Python
Raw Normal View History

2016-11-29 04:16:16 +00:00
import apiclient.discovery
import datetime
import helpers
2016-12-07 06:11:09 +00:00
class VideoNotFound(Exception):
pass
2016-11-29 04:16:16 +00:00
class Video:
def __init__(self, snippet):
self.id = snippet['id']
snippet = snippet['snippet']
self.title = snippet['title'] or '[untitled]'
self.description = snippet['description']
self.author_id = snippet['channelId']
self.author_name = snippet['channelTitle']
# Something like '2016-10-01T21:00:01'
self.published_string = snippet['publishedAt']
published = snippet['publishedAt']
published = published.split('.')[0]
published = datetime.datetime.strptime(published, '%Y-%m-%dT%H:%M:%S')
self.published = published.timestamp()
thumbnails = snippet['thumbnails']
best_thumbnail = max(thumbnails, key=lambda x: thumbnails[x]['width'] * thumbnails[x]['height'])
self.thumbnail = thumbnails[best_thumbnail]
2017-05-21 20:50:17 +00:00
def __str__(self):
return 'Video:%s' % self.id
2016-11-29 04:16:16 +00:00
class Youtube:
def __init__(self, key):
youtube = apiclient.discovery.build(
developerKey=key,
serviceName='youtube',
version='v3',
)
self.youtube = youtube
2016-12-07 06:11:09 +00:00
def get_user_id(self, username):
user = self.youtube.channels().list(part='snippet', forUsername=username).execute()
return user['items'][0]['id']
2016-11-29 04:16:16 +00:00
def get_user_name(self, uid):
user = self.youtube.channels().list(part='snippet', id=uid).execute()
return user['items'][0]['snippet']['title']
def get_user_videos(self, username=None, uid=None):
if username:
user = self.youtube.channels().list(part='contentDetails', forUsername=username).execute()
else:
user = self.youtube.channels().list(part='contentDetails', id=uid).execute()
upload_playlist = user['items'][0]['contentDetails']['relatedPlaylists']['uploads']
page_token = None
while True:
items = self.youtube.playlistItems().list(
maxResults=50,
pageToken=page_token,
part='contentDetails',
playlistId=upload_playlist,
).execute()
page_token = items.get('nextPageToken', None)
new = [item['contentDetails']['videoId'] for item in items['items']]
count = len(new)
new = self.get_video(new)
new.sort(key=lambda x: x.published, reverse=True)
yield from new
#print('Found %d more, %d total' % (count, len(videos)))
if page_token is None or count < 50:
break
2017-05-21 20:50:17 +00:00
def get_related_videos(self, video_id, part='id,snippet', count=50):
if isinstance(video_id, Video):
video_id = video_id.id
results = self.youtube.search().list(
part=part,
relatedToVideoId=video_id,
type='video',
maxResults=count,
).execute()
videos = []
for related in results['items']:
related['id'] = related['id']['videoId']
video = Video(related)
videos.append(video)
return videos
2016-11-29 04:16:16 +00:00
def get_video(self, video_ids):
if isinstance(video_ids, str):
singular = True
video_ids = [video_ids]
else:
singular = False
2016-12-07 06:11:09 +00:00
2016-11-29 04:16:16 +00:00
results = []
2016-12-07 06:11:09 +00:00
chunks = helpers.chunk_sequence(video_ids, 50)
for chunk in chunks:
2016-11-29 04:16:16 +00:00
chunk = ','.join(chunk)
data = self.youtube.videos().list(part='snippet', id=chunk).execute()
items = data['items']
2017-05-21 20:50:17 +00:00
results.extend(items)
2016-11-29 04:16:16 +00:00
results = [Video(snippet) for snippet in results]
2016-12-07 06:11:09 +00:00
if singular:
if len(results) == 1:
return results[0]
elif len(results) == 0:
raise VideoNotFound(video_ids[0])
2016-11-29 04:16:16 +00:00
return results