|
|
@ -0,0 +1,110 @@ |
|
|
|
#!/usr/bin/python |
|
|
|
# coding: utf-8 |
|
|
|
# From Youtube samples : https://raw.githubusercontent.com/youtube/api-samples/master/python/upload_video.py |
|
|
|
|
|
|
|
import argparse |
|
|
|
import httplib |
|
|
|
import httplib2 |
|
|
|
import os |
|
|
|
import random |
|
|
|
import time |
|
|
|
|
|
|
|
import google.oauth2.credentials |
|
|
|
import google_auth_oauthlib.flow |
|
|
|
from googleapiclient.discovery import build |
|
|
|
from googleapiclient.errors import HttpError |
|
|
|
from googleapiclient.http import MediaFileUpload |
|
|
|
from google_auth_oauthlib.flow import InstalledAppFlow |
|
|
|
|
|
|
|
|
|
|
|
# Explicitly tell the underlying HTTP transport library not to retry, since |
|
|
|
# we are handling retry logic ourselves. |
|
|
|
httplib2.RETRIES = 1 |
|
|
|
|
|
|
|
# Maximum number of times to retry before giving up. |
|
|
|
MAX_RETRIES = 10 |
|
|
|
|
|
|
|
# Youtube retriables cases |
|
|
|
RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, httplib.NotConnected, |
|
|
|
httplib.IncompleteRead, httplib.ImproperConnectionState, |
|
|
|
httplib.CannotSendRequest, httplib.CannotSendHeader, |
|
|
|
httplib.ResponseNotReady, httplib.BadStatusLine) |
|
|
|
|
|
|
|
RETRIABLE_STATUS_CODES = [500, 502, 503, 504] |
|
|
|
|
|
|
|
|
|
|
|
CLIENT_SECRETS_FILE = 'client_secret.json' |
|
|
|
SCOPES = ['https://www.googleapis.com/auth/youtube.upload'] |
|
|
|
API_SERVICE_NAME = 'youtube' |
|
|
|
API_VERSION = 'v3' |
|
|
|
|
|
|
|
VALID_PRIVACY_STATUSES = ('public', 'private', 'unlisted') |
|
|
|
|
|
|
|
|
|
|
|
# Authorize the request and store authorization credentials. |
|
|
|
def get_authenticated_service(): |
|
|
|
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES) |
|
|
|
credentials = flow.run_console() |
|
|
|
return build(API_SERVICE_NAME, API_VERSION, credentials = credentials) |
|
|
|
|
|
|
|
def initialize_upload(youtube, options): |
|
|
|
tags = None |
|
|
|
if options.keywords: |
|
|
|
tags = options.keywords.split(',') |
|
|
|
|
|
|
|
body=dict( |
|
|
|
snippet=dict( |
|
|
|
title=options.title, |
|
|
|
description=options.description, |
|
|
|
tags=tags, |
|
|
|
categoryId=options.category |
|
|
|
), |
|
|
|
status=dict( |
|
|
|
privacyStatus=options.privacyStatus |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
# Call the API's videos.insert method to create and upload the video. |
|
|
|
insert_request = youtube.videos().insert( |
|
|
|
part=','.join(body.keys()), |
|
|
|
body=body, |
|
|
|
media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True) |
|
|
|
) |
|
|
|
|
|
|
|
resumable_upload(insert_request) |
|
|
|
|
|
|
|
# This method implements an exponential backoff strategy to resume a |
|
|
|
# failed upload. |
|
|
|
def resumable_upload(request): |
|
|
|
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 'Video id "%s" was successfully uploaded.' % response['id'] |
|
|
|
else: |
|
|
|
exit('The upload failed with an unexpected response: %s' % response) |
|
|
|
except HttpError, 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, e: |
|
|
|
error = 'A retriable error occurred: %s' % e |
|
|
|
|
|
|
|
if error is not None: |
|
|
|
print error |
|
|
|
retry += 1 |
|
|
|
if retry > MAX_RETRIES: |
|
|
|
exit('No longer attempting to retry.') |
|
|
|
|
|
|
|
max_sleep = 2 ** retry |
|
|
|
sleep_seconds = random.random() * max_sleep |
|
|
|
print 'Sleeping %f seconds and then retrying...' % sleep_seconds |
|
|
|
time.sleep(sleep_seconds) |
|
|
|
|