11#!/usr/bin/python
22
3+ import argparse
34import httplib
45import httplib2
56import os
67import random
7- import sys
88import time
99
10- from apiclient . discovery import build
11- from apiclient . errors import HttpError
12- from apiclient . http import MediaFileUpload
13- from oauth2client . client import flow_from_clientsecrets
14- from oauth2client . file import Storage
15- from oauth2client . tools import argparser , run_flow
10+ import google . oauth2 . credentials
11+ import google_auth_oauthlib . flow
12+ from googleapiclient . discovery import build
13+ from googleapiclient . errors import HttpError
14+ from googleapiclient . http import MediaFileUpload
15+ from google_auth_oauthlib . flow import InstalledAppFlow
1616
1717
1818# Explicitly tell the underlying HTTP transport library not to retry, since
4242# https://developers.google.com/youtube/v3/guides/authentication
4343# For more information about the client_secrets.json file format, see:
4444# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
45- CLIENT_SECRETS_FILE = "client_secrets .json"
45+ CLIENT_SECRETS_FILE = 'client_secret .json'
4646
4747# This OAuth 2.0 access scope allows an application to upload files to the
4848# authenticated user's YouTube channel, but doesn't allow other types of access.
49- YOUTUBE_UPLOAD_SCOPE = " https://www.googleapis.com/auth/youtube.upload"
50- YOUTUBE_API_SERVICE_NAME = " youtube"
51- YOUTUBE_API_VERSION = "v3"
49+ SCOPES = [ ' https://www.googleapis.com/auth/youtube.upload' ]
50+ API_SERVICE_NAME = ' youtube'
51+ API_VERSION = 'v3'
5252
53- # This variable defines a message to display if the CLIENT_SECRETS_FILE is
54- # missing.
55- MISSING_CLIENT_SECRETS_MESSAGE = """
56- WARNING: Please configure OAuth 2.0
53+ VALID_PRIVACY_STATUSES = ('public' , 'private' , 'unlisted' )
5754
58- To make this sample run you will need to populate the client_secrets.json file
59- found at:
6055
61- %s
62-
63- with information from the {{ Cloud Console }}
64- {{ https://cloud.google.com/console }}
65-
66- For more information about the client_secrets.json file format, please visit:
67- https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
68- """ % os .path .abspath (os .path .join (os .path .dirname (__file__ ),
69- CLIENT_SECRETS_FILE ))
70-
71- VALID_PRIVACY_STATUSES = ("public" , "private" , "unlisted" )
72-
73-
74- def get_authenticated_service (args ):
75- flow = flow_from_clientsecrets (CLIENT_SECRETS_FILE ,
76- scope = YOUTUBE_UPLOAD_SCOPE ,
77- message = MISSING_CLIENT_SECRETS_MESSAGE )
78-
79- storage = Storage ("%s-oauth2.json" % sys .argv [0 ])
80- credentials = storage .get ()
81-
82- if credentials is None or credentials .invalid :
83- credentials = run_flow (flow , storage , args )
84-
85- return build (YOUTUBE_API_SERVICE_NAME , YOUTUBE_API_VERSION ,
86- http = credentials .authorize (httplib2 .Http ()))
56+ # Authorize the request and store authorization credentials.
57+ def get_authenticated_service ():
58+ flow = InstalledAppFlow .from_client_secrets_file (CLIENT_SECRETS_FILE , SCOPES )
59+ credentials = flow .run_console ()
60+ return build (API_SERVICE_NAME , API_VERSION , credentials = credentials )
8761
8862def initialize_upload (youtube , options ):
8963 tags = None
9064 if options .keywords :
91- tags = options .keywords .split ("," )
65+ tags = options .keywords .split (',' )
9266
9367 body = dict (
9468 snippet = dict (
@@ -104,14 +78,14 @@ def initialize_upload(youtube, options):
10478
10579 # Call the API's videos.insert method to create and upload the video.
10680 insert_request = youtube .videos ().insert (
107- part = "," .join (body .keys ()),
81+ part = ',' .join (body .keys ()),
10882 body = body ,
10983 # The chunksize parameter specifies the size of each chunk of data, in
11084 # bytes, that will be uploaded at a time. Set a higher value for
11185 # reliable connections as fewer chunks lead to faster uploads. Set a lower
11286 # value for better recovery on less reliable connections.
11387 #
114- # Setting " chunksize" equal to -1 in the code below means that the entire
88+ # Setting ' chunksize' equal to -1 in the code below means that the entire
11589 # file will be uploaded in a single HTTP request. (If the upload fails,
11690 # it will still be retried where it left off.) This is usually a best
11791 # practice, but if you're using Python older than 2.6 or if you're
@@ -124,58 +98,57 @@ def initialize_upload(youtube, options):
12498
12599# This method implements an exponential backoff strategy to resume a
126100# failed upload.
127- def resumable_upload (insert_request ):
101+ def resumable_upload (request ):
128102 response = None
129103 error = None
130104 retry = 0
131105 while response is None :
132106 try :
133- print " Uploading file..."
134- status , response = insert_request .next_chunk ()
107+ print ' Uploading file...'
108+ status , response = request .next_chunk ()
135109 if response is not None :
136110 if 'id' in response :
137- print " Video id '%s' was successfully uploaded." % response ['id' ]
111+ print ' Video id "%s" was successfully uploaded.' % response ['id' ]
138112 else :
139- exit (" The upload failed with an unexpected response: %s" % response )
113+ exit (' The upload failed with an unexpected response: %s' % response )
140114 except HttpError , e :
141115 if e .resp .status in RETRIABLE_STATUS_CODES :
142- error = " A retriable HTTP error %d occurred:\n %s" % (e .resp .status ,
116+ error = ' A retriable HTTP error %d occurred:\n %s' % (e .resp .status ,
143117 e .content )
144118 else :
145119 raise
146120 except RETRIABLE_EXCEPTIONS , e :
147- error = " A retriable error occurred: %s" % e
121+ error = ' A retriable error occurred: %s' % e
148122
149123 if error is not None :
150124 print error
151125 retry += 1
152126 if retry > MAX_RETRIES :
153- exit (" No longer attempting to retry." )
127+ exit (' No longer attempting to retry.' )
154128
155129 max_sleep = 2 ** retry
156130 sleep_seconds = random .random () * max_sleep
157- print " Sleeping %f seconds and then retrying..." % sleep_seconds
131+ print ' Sleeping %f seconds and then retrying...' % sleep_seconds
158132 time .sleep (sleep_seconds )
159133
160134if __name__ == '__main__' :
161- argparser .add_argument ("--file" , required = True , help = "Video file to upload" )
162- argparser .add_argument ("--title" , help = "Video title" , default = "Test Title" )
163- argparser .add_argument ("--description" , help = "Video description" ,
164- default = "Test Description" )
165- argparser .add_argument ("--category" , default = "22" ,
166- help = "Numeric video category. " +
167- "See https://developers.google.com/youtube/v3/docs/videoCategories/list" )
168- argparser .add_argument ("--keywords" , help = "Video keywords, comma separated" ,
169- default = "" )
170- argparser .add_argument ("--privacyStatus" , choices = VALID_PRIVACY_STATUSES ,
171- default = VALID_PRIVACY_STATUSES [0 ], help = "Video privacy status." )
172- args = argparser .parse_args ()
173-
174- if not os .path .exists (args .file ):
175- exit ("Please specify a valid file using the --file= parameter." )
176-
177- youtube = get_authenticated_service (args )
135+ parser = argparse .ArgumentParser ()
136+ parser .add_argument ('--file' , required = True , help = 'Video file to upload' )
137+ parser .add_argument ('--title' , help = 'Video title' , default = 'Test Title' )
138+ parser .add_argument ('--description' , help = 'Video description' ,
139+ default = 'Test Description' )
140+ parser .add_argument ('--category' , default = '22' ,
141+ help = 'Numeric video category. ' +
142+ 'See https://developers.google.com/youtube/v3/docs/videoCategories/list' )
143+ parser .add_argument ('--keywords' , help = 'Video keywords, comma separated' ,
144+ default = '' )
145+ parser .add_argument ('--privacyStatus' , choices = VALID_PRIVACY_STATUSES ,
146+ default = 'private' , help = 'Video privacy status.' )
147+ args = parser .parse_args ()
148+
149+ youtube = get_authenticated_service ()
150+
178151 try :
179152 initialize_upload (youtube , args )
180153 except HttpError , e :
181- print " An HTTP error %d occurred:\n %s" % (e .resp .status , e .content )
154+ print ' An HTTP error %d occurred:\n %s' % (e .resp .status , e .content )
0 commit comments