| |
|
| |
|
| | import httplib2
|
| | import os
|
| | import random
|
| | import sys
|
| | import time
|
| | import glob
|
| |
|
| | from apiclient.discovery import build
|
| | from apiclient.errors import HttpError
|
| | from apiclient.http import MediaFileUpload
|
| | from oauth2client.client import flow_from_clientsecrets
|
| | from oauth2client.file import Storage
|
| | from oauth2client.tools import argparser, run_flow
|
| |
|
| |
|
| |
|
| |
|
| | httplib2.RETRIES = 1
|
| |
|
| |
|
| | MAX_RETRIES = 10
|
| |
|
| |
|
| | RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError)
|
| |
|
| |
|
| |
|
| | RETRIABLE_STATUS_CODES = [500, 502, 503, 504]
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | CLIENT_SECRETS_FILE = "client_secrets.json"
|
| |
|
| |
|
| |
|
| | YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload"
|
| | YOUTUBE_API_SERVICE_NAME = "youtube"
|
| | YOUTUBE_API_VERSION = "v3"
|
| |
|
| |
|
| |
|
| | MISSING_CLIENT_SECRETS_MESSAGE = """
|
| | WARNING: Please configure OAuth 2.0
|
| |
|
| | To make this sample run you will need to populate the client_secrets.json file
|
| | found at:
|
| |
|
| | %s
|
| |
|
| | with information from the API Console
|
| | https://console.cloud.google.com/
|
| |
|
| | For more information about the client_secrets.json file format, please visit:
|
| | https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
|
| | """ % os.path.abspath(os.path.join(os.path.dirname(__file__),
|
| | CLIENT_SECRETS_FILE))
|
| |
|
| | VALID_PRIVACY_STATUSES = ("public", "private", "unlisted")
|
| |
|
| |
|
| | def get_authenticated_service(args):
|
| | flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE,
|
| | scope=YOUTUBE_UPLOAD_SCOPE,
|
| | message=MISSING_CLIENT_SECRETS_MESSAGE)
|
| |
|
| | oauth_files = glob.glob("*oauth2*.json")
|
| | valid_credentials = []
|
| |
|
| | for oauth_file in oauth_files:
|
| | args = argparser.parse_args()
|
| | args.client_secrets_file = oauth_file
|
| | print(oauth_file)
|
| | storage = Storage(args.client_secrets_file)
|
| |
|
| | credentials = storage.get()
|
| |
|
| | if credentials is None or credentials.invalid:
|
| | try:
|
| | credentials = run_flow(flow, storage, args)
|
| | valid_credentials.append(credentials)
|
| | except HttpError as e:
|
| | print("An HTTP error %d occurred:\n%s" % (e.resp.status, e.content))
|
| | else:
|
| | valid_credentials.append(credentials)
|
| |
|
| | if len(valid_credentials) == 0:
|
| | exit("No valid credentials found in the provided OAuth files")
|
| |
|
| |
|
| | return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
|
| | http=valid_credentials[0].authorize(httplib2.Http()))
|
| |
|
| |
|
| | 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
|
| | )
|
| | )
|
| |
|
| |
|
| | insert_request = youtube.videos().insert(
|
| | part=",".join(body.keys()),
|
| | body=body,
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True)
|
| | )
|
| |
|
| | resumable_upload(insert_request)
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | def resumable_upload(insert_request):
|
| | response = None
|
| | error = None
|
| | retry = 0
|
| | while response is None:
|
| | try:
|
| | print("Uploading file...")
|
| | status, response = insert_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 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:
|
| | 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)
|
| |
|
| |
|
| | if __name__ == '__main__':
|
| | argparser.add_argument("--file", required=True,
|
| | help="Video file to upload")
|
| | argparser.add_argument("--title", help="Video title", default="Test Title")
|
| | argparser.add_argument("--description", help="Video description",
|
| | default="Test Description")
|
| | argparser.add_argument("--category", default="24",
|
| | help="Numeric video category. " +
|
| | "See https://developers.google.com/youtube/v3/docs/videoCategories/list")
|
| | argparser.add_argument("--keywords", help="Video keywords, comma separated",
|
| | default="")
|
| | argparser.add_argument("--privacyStatus", choices=VALID_PRIVACY_STATUSES,
|
| | default=VALID_PRIVACY_STATUSES[0], help="Video privacy status.")
|
| | args = argparser.parse_args()
|
| |
|
| | if not os.path.exists(args.file):
|
| | exit("Please specify a valid file using the --file= parameter.")
|
| |
|
| | youtube = get_authenticated_service(args)
|
| | try:
|
| | initialize_upload(youtube, args)
|
| | except HttpError as e:
|
| | print("An HTTP error %d occurred:\n%s" % (e.resp.status, e.content))
|
| |
|