Skip to content

Commit 30ee928

Browse files
"Added sample: python/upload_video.py"
1 parent b333d7c commit 30ee928

1 file changed

Lines changed: 180 additions & 0 deletions

File tree

python/upload_video.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#!/usr/bin/python
2+
3+
import httplib
4+
import httplib2
5+
import os
6+
import random
7+
import sys
8+
import time
9+
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
16+
17+
18+
# Explicitly tell the underlying HTTP transport library not to retry, since
19+
# we are handling retry logic ourselves.
20+
httplib2.RETRIES = 1
21+
22+
# Maximum number of times to retry before giving up.
23+
MAX_RETRIES = 10
24+
25+
# Always retry when these exceptions are raised.
26+
RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, httplib.NotConnected,
27+
httplib.IncompleteRead, httplib.ImproperConnectionState,
28+
httplib.CannotSendRequest, httplib.CannotSendHeader,
29+
httplib.ResponseNotReady, httplib.BadStatusLine)
30+
31+
# Always retry when an apiclient.errors.HttpError with one of these status
32+
# codes is raised.
33+
RETRIABLE_STATUS_CODES = [500, 502, 503, 504]
34+
35+
# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
36+
# the OAuth 2.0 information for this application, including its client_id and
37+
# client_secret. You can acquire an OAuth 2.0 client ID and client secret from
38+
# the {{ Google Cloud Console }} at
39+
# {{ https://cloud.google.com/console }}.
40+
# Please ensure that you have enabled the YouTube Data API for your project.
41+
# For more information about using OAuth2 to access the YouTube Data API, see:
42+
# https://developers.google.com/youtube/v3/guides/authentication
43+
# For more information about the client_secrets.json file format, see:
44+
# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
45+
CLIENT_SECRETS_FILE = "client_secrets.json"
46+
47+
# This OAuth 2.0 access scope allows an application to upload files to the
48+
# 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"
52+
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
57+
58+
To make this sample run you will need to populate the client_secrets.json file
59+
found at:
60+
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()))
87+
88+
def initialize_upload(youtube, options):
89+
tags = None
90+
if options.keywords:
91+
tags = options.keywords.split(",")
92+
93+
body=dict(
94+
snippet=dict(
95+
title=options.title,
96+
description=options.description,
97+
tags=tags,
98+
categoryId=options.category
99+
),
100+
status=dict(
101+
privacyStatus=options.privacyStatus
102+
)
103+
)
104+
105+
# Call the API's videos.insert method to create and upload the video.
106+
insert_request = youtube.videos().insert(
107+
part=",".join(body.keys()),
108+
body=body,
109+
# The chunksize parameter specifies the size of each chunk of data, in
110+
# bytes, that will be uploaded at a time. Set a higher value for
111+
# reliable connections as fewer chunks lead to faster uploads. Set a lower
112+
# value for better recovery on less reliable connections.
113+
#
114+
# Setting "chunksize" equal to -1 in the code below means that the entire
115+
# file will be uploaded in a single HTTP request. (If the upload fails,
116+
# it will still be retried where it left off.) This is usually a best
117+
# practice, but if you're using Python older than 2.6 or if you're
118+
# running on App Engine, you should set the chunksize to something like
119+
# 1024 * 1024 (1 megabyte).
120+
media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True)
121+
)
122+
123+
resumable_upload(insert_request)
124+
125+
# This method implements an exponential backoff strategy to resume a
126+
# failed upload.
127+
def resumable_upload(insert_request):
128+
response = None
129+
error = None
130+
retry = 0
131+
while response is None:
132+
try:
133+
print "Uploading file..."
134+
status, response = insert_request.next_chunk()
135+
if 'id' in response:
136+
print "Video id '%s' was successfully uploaded." % response['id']
137+
else:
138+
exit("The upload failed with an unexpected response: %s" % response)
139+
except HttpError, e:
140+
if e.resp.status in RETRIABLE_STATUS_CODES:
141+
error = "A retriable HTTP error %d occurred:\n%s" % (e.resp.status,
142+
e.content)
143+
else:
144+
raise
145+
except RETRIABLE_EXCEPTIONS, e:
146+
error = "A retriable error occurred: %s" % e
147+
148+
if error is not None:
149+
print error
150+
retry += 1
151+
if retry > MAX_RETRIES:
152+
exit("No longer attempting to retry.")
153+
154+
max_sleep = 2 ** retry
155+
sleep_seconds = random.random() * max_sleep
156+
print "Sleeping %f seconds and then retrying..." % sleep_seconds
157+
time.sleep(sleep_seconds)
158+
159+
if __name__ == '__main__':
160+
argparser.add_argument("--file", required=True, help="Video file to upload")
161+
argparser.add_argument("--title", help="Video title", default="Test Title")
162+
argparser.add_argument("--description", help="Video description",
163+
default="Test Description")
164+
argparser.add_argument("--category", default="22",
165+
help="Numeric video category. " +
166+
"See https://developers.google.com/youtube/v3/docs/videoCategories/list")
167+
argparser.add_argument("--keywords", help="Video keywords, comma separated",
168+
default="")
169+
argparser.add_argument("--privacyStatus", choices=VALID_PRIVACY_STATUSES,
170+
default=VALID_PRIVACY_STATUSES[0], help="Video privacy status.")
171+
args = argparser.parse_args()
172+
173+
if not os.path.exists(args.file):
174+
exit("Please specify a valid file using the --file= parameter.")
175+
176+
youtube = get_authenticated_service(args)
177+
try:
178+
initialize_upload(youtube, args)
179+
except HttpError, e:
180+
print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)

0 commit comments

Comments
 (0)