Skip to content

Commit ab53f82

Browse files
"Added sample: python/upload_banner.py"
1 parent 1d39cd1 commit ab53f82

1 file changed

Lines changed: 171 additions & 0 deletions

File tree

python/upload_banner.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#!/usr/bin/python
2+
3+
4+
# This sample sets a custom banner to user's channel by:
5+
#
6+
# 1. Uploading a banner image with "youtube.channelBanners.insert" method via resumable upload
7+
# 2. Getting user's channel object with "youtube.channels.list" method and "mine" parameter
8+
# 3. Updating channel's banner external URL with "youtube.channels.update" method
9+
#
10+
# @author Ibrahim Ulukaya
11+
12+
import httplib
13+
import httplib2
14+
import os
15+
import random
16+
import sys
17+
import time
18+
19+
from apiclient.discovery import build
20+
from apiclient.errors import HttpError
21+
from apiclient.http import MediaFileUpload
22+
from oauth2client.client import flow_from_clientsecrets
23+
from oauth2client.file import Storage
24+
from oauth2client.tools import argparser, run_flow
25+
26+
27+
# Explicitly tell the underlying HTTP transport library not to retry, since
28+
# we are handling retry logic ourselves.
29+
httplib2.RETRIES = 1
30+
31+
# Maximum number of times to retry before giving up.
32+
MAX_RETRIES = 10
33+
34+
# Always retry when these exceptions are raised.
35+
RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, httplib.NotConnected,
36+
httplib.IncompleteRead, httplib.ImproperConnectionState,
37+
httplib.CannotSendRequest, httplib.CannotSendHeader,
38+
httplib.ResponseNotReady, httplib.BadStatusLine)
39+
40+
# Always retry when an apiclient.errors.HttpError with one of these status
41+
# codes is raised.
42+
RETRIABLE_STATUS_CODES = [500, 502, 503, 504]
43+
44+
# CLIENT_SECRETS_FILE, name of a file containing the OAuth 2.0 information for
45+
# this application, including client_id and client_secret. You can acquire an
46+
# ID/secret pair from the APIs & auth tab at
47+
# https://cloud.google.com/console
48+
# For more information about using OAuth2 to access Google APIs, please visit:
49+
# https://developers.google.com/accounts/docs/OAuth2
50+
# For more information about the client_secrets.json file format, please visit:
51+
# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
52+
# Please ensure that you have enabled the YouTube Data API for your project.
53+
CLIENT_SECRETS_FILE = "client_secrets.json"
54+
55+
# An OAuth 2 access scope that allows for full read/write access.
56+
YOUTUBE_READ_WRITE_SCOPE = "https://www.googleapis.com/auth/youtube"
57+
YOUTUBE_API_SERVICE_NAME = "youtube"
58+
YOUTUBE_API_VERSION = "v3"
59+
60+
# Helpful message to display if the CLIENT_SECRETS_FILE is missing.
61+
MISSING_CLIENT_SECRETS_MESSAGE = """
62+
WARNING: Please configure OAuth 2.0
63+
64+
To make this sample run you will need to populate the client_secrets.json file
65+
found at:
66+
67+
%s
68+
69+
with information from the APIs Console
70+
https://cloud.google.com/console
71+
72+
For more information about the client_secrets.json file format, please visit:
73+
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
74+
""" % os.path.abspath(os.path.join(os.path.dirname(__file__),
75+
CLIENT_SECRETS_FILE))
76+
77+
def get_authenticated_service(args):
78+
flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE,
79+
scope=YOUTUBE_READ_WRITE_SCOPE,
80+
message=MISSING_CLIENT_SECRETS_MESSAGE)
81+
82+
storage = Storage("%s-oauth2.json" % sys.argv[0])
83+
credentials = storage.get()
84+
85+
if credentials is None or credentials.invalid:
86+
credentials = run_flow(flow, storage, args)
87+
88+
return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
89+
http=credentials.authorize(httplib2.Http()))
90+
91+
def upload_banner(youtube, image_file):
92+
insert_request = youtube.channelBanners().insert(
93+
media_body = MediaFileUpload(image_file, chunksize=-1, resumable=True)
94+
)
95+
96+
image_url = resumable_upload(insert_request)
97+
set_banner(image_url)
98+
99+
def resumable_upload(insert_request):
100+
response = None
101+
error = None
102+
retry = 0
103+
while response is None:
104+
try:
105+
print "Uploading file..."
106+
status, response = insert_request.next_chunk()
107+
if 'url' in response:
108+
print "Banner was successfully uploaded to '%s'." % (
109+
response['url'])
110+
else:
111+
exit("The upload failed with an unexpected response: %s" % response)
112+
except HttpError, e:
113+
if e.resp.status in RETRIABLE_STATUS_CODES:
114+
error = "A retriable HTTP error %d occurred:\n%s" % (e.resp.status,
115+
e.content)
116+
else:
117+
raise
118+
except RETRIABLE_EXCEPTIONS, e:
119+
error = "A retriable error occurred: %s" % e
120+
121+
if error is not None:
122+
print error
123+
retry += 1
124+
if retry > MAX_RETRIES:
125+
exit("No longer attempting to retry.")
126+
127+
max_sleep = 2 ** retry
128+
sleep_seconds = random.random() * max_sleep
129+
print "Sleeping %f seconds and then retrying..." % sleep_seconds
130+
time.sleep(sleep_seconds)
131+
132+
return response['url']
133+
134+
def set_banner(banner_url):
135+
channels_response = youtube.channels().list(
136+
mine=True,
137+
part="brandingSettings"
138+
).execute()
139+
140+
if "brandingSettings" not in channels_response["items"][0]:
141+
channels_response["items"][0]["brandingSettings"]["image"]["bannerExternalUrl"] = []
142+
143+
channel_brandingSettings = channels_response["items"][0]["brandingSettings"]
144+
145+
channel_brandingSettings["image"]["bannerExternalUrl"] = banner_url
146+
147+
channels_update_response = youtube.channels().update(
148+
part='brandingSettings',
149+
body=dict(
150+
brandingSettings=channel_brandingSettings,
151+
id = channels_response["items"][0]["id"]
152+
)).execute()
153+
154+
banner_mobile_url = channels_update_response["brandingSettings"]["image"]["bannerMobileImageUrl"]
155+
print "Banner is set to '%s'." % (banner_mobile_url)
156+
157+
if __name__ == "__main__":
158+
argparser.add_argument("--file", required=True,
159+
help="Path to banner image file.")
160+
args = argparser.parse_args()
161+
162+
if not os.path.exists(args.file):
163+
exit("Please specify a valid file using the --file= parameter.")
164+
165+
youtube = get_authenticated_service(args)
166+
try:
167+
upload_banner(youtube, args.file)
168+
except HttpError, e:
169+
print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
170+
else:
171+
print "The custom banner was successfully uploaded."

0 commit comments

Comments
 (0)