Skip to content

Commit

Permalink
added comments
Browse files Browse the repository at this point in the history
  • Loading branch information
jonnekaunisto committed Jun 29, 2019
1 parent 7384187 commit 4346749
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 120 deletions.
5 changes: 3 additions & 2 deletions examples/example_youtube_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
video.set_privacy_status("private")
video.set_public_stats_viewable(True)

print(video.default_language)

channel.upload_video(video)
video = channel.upload_video(video)
print(video.get_video_id())
print(video.get_title())
117 changes: 113 additions & 4 deletions simple_youtube_api/Channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,24 @@
from oauth2client.tools import run_flow
from oauth2client.file import Storage

httplib2.RETRIES = 1
# Maximum number of times to retry before giving up.
MAX_RETRIES = 10

# Always retry when these exceptions are raised.
RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError,
http.client.NotConnected, http.client.IncompleteRead,
http.client.ImproperConnectionState,
http.client.CannotSendRequest,
http.client.CannotSendHeader,
http.client.ResponseNotReady,
http.client.BadStatusLine)


# Always retry when an apiclient.errors.HttpError with one of these status
# codes is raised.
RETRIABLE_STATUS_CODES = [500, 502, 503, 504]


SCOPE = ['https://www.googleapis.com/auth/youtube']
API_SERVICE_NAME = 'youtube'
Expand Down Expand Up @@ -96,15 +114,106 @@ def fetch_uploads(self) -> List[YouTubeVideo]:
def upload_video(self, video: LocalVideo):
''' Uploads video to authorized channel
'''
return youtube_api.initialize_upload(self.channel, video)
return initialize_upload(self.channel, video)

def set_video_thumbnail(self, thumbnail_path, video=None, video_id=None):
def set_video_thumbnail(self, video, thumbnail_path):
''' Sets thumbnail for video
'''
if video is not None:
video_id = video.get_video_id()
video_id = video.get_video_id()

self.channel.thumbnails().set(
videoId=video_id,
media_body=thumbnail_path
)


def generate_upload_body(video):
body = dict()

snippet = dict()
if video.title is not None:
snippet.update({"title": video.title})
else:
Exception("Title is required")
if video.description is not None:
snippet.update({"description": video.description})
if video.tags is not None:
snippet.update({"tags": video.tags})
if video.category is not None:
snippet.update({"categoryId": video.category})
else:
Exception("Category is required")
if video.default_language is not None:
snippet.update({"defaultLanguage": video.default_language})
body.update({"snippet": snippet})

if video.status_set:
status = dict()
if video.embeddable is not None:
status.update({"embeddable": video.embeddable})
if video.license is not None:
status.update({"license": video.license})
if video.privacy_status is not None:
status.update({"privacyStatus": video.privacy_status})
if video.public_stats_viewable is not None:
status.update({"publicStatsViewable": video.public_stats_viewable})
if video.publish_at is not None:
status.update({"publishAt": video.embeddable})
body.update({"status": status})

return body


def initialize_upload(channel, video):
body = generate_upload_body(video)

# Call the API's videos.insert method to create and upload the video.
insert_request = channel.videos().insert(
part=','.join(list(body.keys())),
body=body,
media_body=MediaFileUpload(video.get_file_path(), chunksize=-1,
resumable=True)
)

return resumable_upload(insert_request)


# This method implements an exponential backoff strategy to resume a
# failed upload.
# TODO: add more variables into video when returned
def resumable_upload(request):
youtube_video = None
response = None
error = None
retry = 0
while response is None:
try:
print('Uploading file...')
status, response = request.next_chunk()
if response is not None:
if 'id' in response:
print(str(response))
youtube_video = YouTubeVideo(response['id'])
else:
exit('The upload failed with an unexpected response: %s' %
response)
except HttpError as e:
if e.resp.status in RETRIABLE_STATUS_CODES:
error = 'A retriable HTTP error %d occurred:\n%s' %\
(e.resp.status, e.content)
else:
raise
except RETRIABLE_EXCEPTIONS as e:
error = 'A retriable error occurred: %s' % e

if error is not None:
print(error)
retry += 1
if retry > MAX_RETRIES:
return youtube_video

max_sleep = 2 ** retry
sleep_seconds = random.random() * max_sleep
print('Sleeping %f seconds and then retrying...' % sleep_seconds)
time.sleep(sleep_seconds)
return youtube_video
3 changes: 1 addition & 2 deletions simple_youtube_api/Video.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ def __init__(self):

@video_snippet_set
def set_title(self, title: str):
'''
Sets title for video and returns an exception if title is invalid
'''Sets title for video and returns an exception if title is invalid
'''
if not type(title) is str:
raise Exception("Title must be a string")
Expand Down
14 changes: 14 additions & 0 deletions simple_youtube_api/YouTube.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@ def __init__(self):
self.youtube = None

def login(self, developer_key):
'''Logs into YouTube with credentials
'''
self.youtube = build(API_SERVICE_NAME, API_VERSION,
developerKey=developer_key)

def get_login(self):
'''Gets login object
'''
return self.youtube

def search_raw(self, search_term, max_results=25):
'''Searches YouTube and returns a JSON response
'''
search_response = self.youtube.search().list(
q=search_term,
part='snippet',
Expand All @@ -40,6 +46,8 @@ def search_raw(self, search_term, max_results=25):
return search_response

def search(self, search_term, max_results=25):
'''Searches YouTube and returns a list of video objects
'''
search_response = self.search_raw(search_term, max_results=max_results)

videos = []
Expand All @@ -58,6 +66,8 @@ def search(self, search_term, max_results=25):
return videos

def search_by_video_id_raw(self, video_id):
'''Returns a JSON of video
'''
search_response = self.youtube.videos().list(
part='snippet',
id=video_id
Expand All @@ -66,12 +76,16 @@ def search_by_video_id_raw(self, video_id):
return search_response

def search_by_video_id(self, video_id):
'''Returns a video object
'''
video = YouTubeVideo(video_id, youtube=self.youtube)
video.fetch()

return video

def fetch_categories(self):
'''Finds all the video categories on YouTube
'''
response = self.youtube.videoCategories().list(
part="snippet",
regionCode="US"
Expand Down
25 changes: 24 additions & 1 deletion simple_youtube_api/YouTubeVideo.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,23 @@ def __init__(self, video_id, youtube=None, channel=None):
self.channel_id = None

def set_youtube_auth(self, youtube):
'''Sets authentication for video
'''
self.youtube = youtube

def set_channel_auth(self, channel):
'''Sets channel authenticaton for video
'''
self.channel = channel

def get_video_id(self):
'''Returns video id
'''
return self.video_id

def get_channel_id(self):
'''Returns channel id
'''
return self.channel_id

# TODO add more values to be fetched
Expand All @@ -43,6 +51,8 @@ def fetch(self, snippet=True, content_details=False, status=False,
processing_details=False, suggestions=False,
live_streaming_details=False, localizations=False,
all_parts=False):
'''Fetches specified parts of video
'''

parts_list = []
youtube_perm_parts = [(snippet, 'snippet'), (status, 'status'),
Expand Down Expand Up @@ -91,11 +101,14 @@ def fetch(self, snippet=True, content_details=False, status=False,
self.embeddable = status_result['embeddable']
self.license = status_result['license']
self.privacy_status = status_result['privacyStatus']
self.public_stats_viewable = status_result['publicStatsViewable']
self.public_stats_viewable = \
status_result['publicStatsViewable']

# TODO Finish
@require_channel_auth
def update(self, title=None):
'''updates a part of video
'''
body = {"id": self.__video_id,
"snippet": {"title": '', "categoryId": 1}}

Expand All @@ -110,6 +123,8 @@ def update(self, title=None):

@require_channel_auth
def rate_video(self, rating):
'''Rates video
'''
if rating in ["like", "dislike", "none"]:
request = self.channel.videos().rate(
id="Ks-_Mh1QhMc",
Expand All @@ -121,16 +136,24 @@ def rate_video(self, rating):

@require_channel_auth
def like(self):
'''Likes video
'''
self.rate_video("like")

@require_channel_auth
def dislike(self):
'''Dislikes video
'''
self.rate_video("dislike")

@require_channel_auth
def remove_rating(self):
'''Removes rating
'''
self.rate_video("none")

def download(self):
'''Downloads video
'''
video_url = 'https://youtube.com/watch?v=' + self.video_id
pytube_YouTube(video_url).streams.first().download()
Loading

0 comments on commit 4346749

Please sign in to comment.