Note:
The YouTube Content ID API is intended for use by YouTube content partners and is not accessible to all developers or to all YouTube users. If you do not see the YouTube Content ID API as one of the services listed in the
Google API Console
, see the
YouTube Help Center
to learn more about the YouTube Partner Program.
This code sample demonstrates how to upload a YouTube video and apply a monetization policy to it. To monetize a video, you must
claim
the video with an
asset
in the YouTube rights management system. The sample uploads the video, creates a new asset, claims the video using the asset, and applies a monetization policy to the video.
This example is presented as the series of steps involved along with the relevant sections of the code. You can find the entire script at the end of this page. The code is written in Python.
Client libraries
for other popular programming languages are also available.
Step 1: Common housekeeping functions
The first sections of the code sample perform basic housekeeping functions that are common to many scripts: parse the command line, authenticate the user, and obtain the necessary API services.
Parse the command line
The
parse_options
method uses
OptionParser
from the Python client library to create an
options
object that contains each command-line argument as a property. Subsequent methods retrieve values from the
options
object as necessary.
The sample script's command-line arguments are listed below. The first two (
file
and
channelId
) are required; the rest are optional.
-
file
: The name and location of the video file to upload.
Example: --file="/home/path/to/file.mov"
-
channelId
: The YouTube channel to which you want to upload the video. The channel must be managed by the YouTube Content Manager account of the authenticated user. You can retrieve the channel ID in the
YouTube account settings
for the authenticated user or by using the
channels.list
method.
Example: --channelId="UC_x5XG1OV2P6uZZ5FSM9Ttw"
-
title
: A title for the video that you're uploading. The default value is
Test title
.
Example: --title="Summer vacation in California"
-
description
: A description of the video that you're uploading. The default value is
Test description
.
Example: --description="Had a great time surfing in Santa Cruz"
-
category
: The category ID for the
YouTube video category
associated with the video. The default value is
22
, which refers to the
People & Blogs
category.
Example: --category=22
-
keywords
: A comma-separated list of keywords associated with the video. The default value is an empty string.
Example: --keywords="surfing, beach volleyball"
-
privacyStatus
: The privacy status of the video. The default behavior is for an uploaded video to be publicly visible (
public
). When uploading test videos, you may want to specify a
--privacyStatus
argument value to ensure that those videos are private or unlisted. Valid values are
public
,
private
, and
unlisted
.
Example: --privacyStatus="private"
-
policyId
: The monetization policy to apply to the uploaded video. The policy must be associated with the YouTube Content Manager account of the authenticated user. The default is the standard YouTube "monetize" policy.
Example: --policyId="S309961703555739"
def parse_options():
parser = OptionParser()
parser.add_option("--file", dest="file", help="Video file to upload")
parser.add_option("--title", dest="title", help="Video title",
default="Test Title")
parser.add_option("--description", dest="description",
help="Video description",
default="Test Description")
parser.add_option("--category", dest="category",
help="Numeric video category. " +
"See https://developers.google.com/youtube/v3/docs/videoCategories/list",
default="22")
parser.add_option("--keywords", dest="keywords",
help="Video keywords, comma separated", default="")
parser.add_option("--privacyStatus", dest="privacyStatus",
help="Video privacy status: public, private or unlisted",
default="public")
parser.add_option("--policyId", dest="policyId",
help="Optional id of a saved claim policy")
parser.add_option("--channelId", dest="channelId",
help="Id of the channel to upload to. Must be managed by your CMS account")
(options, args) = parser.parse_args()
return options
Authorize the request
In this step, we incorporate OAuth 2.0 authorization into the script. This enables the user running the script to authorize the script to perform API requests attributed to the user's account.
Create a client_secrets.json file
The type of authorization shown in the sample requires a
client_secrets.json
file, which contains information from the
Google API Console
, to perform authorization. You also need to
register your application
. For a more complete explanation of how authorization works see the
authorization guide
. Note that this sample requires both the YouTube Data API V3 and the YouTube Content ID API service to be configured in the API Console for your project.
{
"web": {
"client_id": "
INSERT CLIENT ID HERE
",
"client_secret": "
INSERT CLIENT SECRET HERE
",
"redirect_uris": [],
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token"
}
}
Authorization code in the script
The script includes these
import
statements to enable user authentication and authorization:
from oauth2client.file import Storage
from oauth2client.client import flow_from_clientsecrets
from oauth2client.tools import run
Next, the
get_authenticated_services
method creates a
FLOW
object using the data from the
client_secrets.json
file configured in the previous step. If the user authorizes our application to submit API requests on the user's behalf, the resulting credentials are stored in a
Storage
object for later use. The user needs to reauthorize our application if the credentials expire.
YOUTUBE_SCOPES = (
# An OAuth 2 access scope that allows for full read/write access.
"https://www.googleapis.com/auth/youtube",
# A scope that grants access to YouTube Partner API functionality.
"https://www.googleapis.com/auth/youtubepartner")
flow = flow_from_clientsecrets(
CLIENT_SECRETS_FILE,
scope=" ".join(YOUTUBE_SCOPES),
message=MISSING_CLIENT_SECRETS_MESSAGE
)
storage = Storage(CACHED_CREDENTIALS_FILE)
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = run(flow, storage)
Obtain services
After successful authorization we obtain the necessary services for the operations we want to perform. The sample uses the YouTube Data API to upload the video and the YouTube Content ID API to create the asset and claim the video. We create separate services to provide authorized access to the functionality of the two APIs.
from googleapiclient.discovery import build
import httplib2
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
YOUTUBE_CONTENT_ID_API_SERVICE_NAME = "youtubePartner"
YOUTUBE_CONTENT_ID_API_VERSION = "v1"
youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
http=credentials.authorize(httplib2.Http()))
youtube_partner = build(YOUTUBE_CONTENT_ID_API_SERVICE_NAME,
YOUTUBE_CONTENT_ID_API_VERSION, http=credentials.authorize(httplib2.Http()),
static_discovery=False)
return (youtube, youtube_partner)
Step 2: Identify the content owner
To create assets and make claims, the authenticated user must have a YouTube Content Manager account. The Content Manager account holds the rights management objects for one or more
content owners
. The content owner is the copyright holder who has the right to decide whether to monetize, track, or block a video.
The
get_content_owner
method retrieves the ID of the content owner in the authenticated user's Content Manager account. Most accounts have a single content owner (the authenticated user), but if the account has multiple content owners, the method returns the first.
def get_content_owner_id(youtube_partner):
try:
content_owners_list_response = youtube_partner.contentOwners().list(
fetchMine=True
).execute()
except HttpError, e:
if INVALID_CREDENTIALS in e.content:
logging.error("The request is not authorized by a Google Account that "
"is linked to a YouTube content owner. Please delete '%s' and "
"re-authenticate with a YouTube content owner account." %
CACHED_CREDENTIALS_FILE)
exit(1)
else:
raise
# This returns the CMS user id of the first entry returned
# by youtubePartner.contentOwners.list()
# See https://developers.google.com/youtube/partner/reference/rest/v1/contentOwners/list
# Normally this is what you want, but if you authorize with a Google Account
# that has access to multiple YouTube content owner accounts, you need to
# iterate through the results.
return content_owners_list_response["items"][0]["id"]
Step 3: Upload the video
To upload a video, we build a partial JSON resource representing the video and pass it to the
videos.insert
method. We set the video metadata using values from the
options
object created when we
parsed the command line
. For the media file itself, we use
MediaFileUpload
to be able to use resumable uploading. See
Uploading a video
for further details.
The
upload
method returns the video ID for the new video, and the script needs to pass that value to other methods in later steps.
def upload(youtube, content_owner_id, options):
if options.keywords:
tags = options.keywords.split(",")
else:
tags = None
insert_request = youtube.videos().insert(
onBehalfOfContentOwner=content_owner_id,
onBehalfOfContentOwnerChannel=options.channelId,
part="snippet,status",
body=dict(
snippet=dict(
title=options.title,
description=options.description,
tags=tags,
categoryId=options.category
),
status=dict(
privacyStatus=options.privacyStatus
)
),
# chunksize=-1 means that the entire file will be uploaded in a single
# HTTP request. (If the upload fails, it will still be retried where it
# left off.) This is usually a best practice, but if you're using Python
# older than 2.6 or if you're running on App Engine, you should set the
# chunksize to something like 1024 * 1024 (1 megabyte).
media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True)
)
response = None
error = None
retry = 0
duration_seconds=0
while response is None:
try:
logging.debug("Uploading file...")
start_seconds = time.time()
status, response = insert_request.next_chunk()
delta_seconds = time.time() - start_seconds
duration_seconds += delta_seconds
if "id" in response:
return (response["id"], duration_seconds)
else:
logging.error("The upload failed with an unexpected response: %s" %
response)
exit(1)
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:
logging.error(error)
retry += 1
if retry > MAX_RETRIES:
logging.error("No longer attempting to retry.")
exit(1)
max_sleep = 2 ** retry
sleep_seconds = random.random() * max_sleep
logging.debug("Sleeping %f seconds and then retrying..." % sleep_seconds)
time.sleep(sleep_seconds)
Step 4: Create an asset
To monetize a YouTube video, you first have to associate it with an asset. The
create_asset
method creates a new asset for the newly uploaded video.
Just like we did for the video, we build a partial JSON resource that identifies the type of asset to create (a web video) and provides a title and description for the new asset. We pass the JSON resource to the
assets.insert
method, which creates the asset and returns its unique ID. Again, the script needs to pass that value to other methods in later steps.
def create_asset(youtube_partner, content_owner_id, title, description):
# This creates a new asset corresponding to a video on the web.
# The asset is linked to the corresponding YouTube video via a
# claim that will be created later.
body = dict(
type="web",
metadata=dict(
title=title,
description=description
)
)
assets_insert_response = youtube_partner.assets().insert(
onBehalfOfContentOwner=content_owner_id,
body=body
).execute()
return assets_insert_response["id"]
Step 5: Update the ownership
Before you can monetize a video, YouTube must know who owns the associated asset. So, with the asset created, we now configure the asset's
ownership
. In the sample, we specify that the content owner has worldwide ownership of the asset.
def set_asset_ownership(youtube_partner, content_owner_id, asset_id):
# This specifies that content_owner_id owns 100% of the asset worldwide.
# Adjust as needed.
body = dict(
general=[dict(
owner=content_owner_id,
ratio=100,
type="exclude",
territories=[]
)]
)
youtube_partner.ownership().update(
onBehalfOfContentOwner=content_owner_id,
assetId=asset_id,
body=body
).execute()
Step 6: Claim the video
The next step is to associate the uploaded video with its corresponding asset by
claiming
the video. The claim provides the link between the video and the YouTube rights management system, which establishes ownership of the video and enables the owner to set a monetization policy.
The
claim_video
method claims audiovisual rights. If you include the
policyId
parameter on the command line, the method applies the specified policy to the video; if you don't include the parameter, the method applies the standard "monetize" policy.
def claim_video(youtube_partner, content_owner_id, asset_id, video_id,
policy_id):
# policy_id can be set to the id of an existing policy, which can be obtained
# via youtubePartner.policies.list()
# See https://developers.google.com/youtube/partner/reference/rest/v1/policies/list
# If you later update that existing policy, the claim will also be updated.
if policy_id:
policy = dict(
id=policy_id
)
# If policy_id is not provided, a new inline policy is created.
else:
policy = dict(
rules=[dict(
action="monetize"
)]
)
body = dict(
assetId=asset_id,
videoId=video_id,
policy=policy,
contentType="audiovisual"
)
youtube_partner.claims().insert(
onBehalfOfContentOwner=content_owner_id,
body=body
).execute()
Step 7: Set the advertising options
We've claimed the video and applied a monetization policy to it. The final step is to specify what type of advertisements to show in the video. Whenever the "monetize" policy applies, YouTube checks the advertising options and shows the highest-revenue type of advertisements available.
The sample tells YouTube to show in-stream
TrueView
advertisements with this video.
def set_advertising_options(youtube_partner, content_owner_id, video_id):
# This enables the TrueView ad format for the given video.
# Adjust as needed.
body = dict(
adFormats=["trueview_instream"]
)
youtube_partner.videoAdvertisingOptions().update(
videoId=video_id,
onBehalfOfContentOwner=content_owner_id,
body=body
).execute()
Complete code sample
The complete working sample
upload_monetize_video_example.py
is listed below:
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2013 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Simple command-line sample for Youtube Partner API.
Command-line application that creates an asset, uploads and claims a video for that asset.
Usage:
$ python upload_monetize_video_example.py --file=VIDEO_FILE --channelID=CHANNEL_ID \
[--title=VIDEO_TITLE] [--description=VIDEO_DESCRIPTION] [--category=CATEGORY_ID] \
[--keywords=KEYWORDS] [--privacyStatus=PRIVACY_STATUS] [--policyId=POLICY_ID]
You can also get help on all the command-line flags the program understands
by running:
$ python upload_monetize_video_example.py --help
"""
__author__ = 'jeffy+pub@google.com (Jeffrey Posnick)'
import httplib
import httplib2
import logging
import os
import random
import sys
import time
from apiclient.discovery import build
from apiclient.errors import HttpError
from apiclient.http import MediaFileUpload
from oauth2client.file import Storage
from oauth2client.client import flow_from_clientsecrets
from oauth2client.tools import run
from optparse import OptionParser
# 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
# Always retry when these exceptions are raised.
RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, httplib.NotConnected,
httplib.IncompleteRead, httplib.ImproperConnectionState,
httplib.CannotSendRequest, httplib.CannotSendHeader,
httplib.ResponseNotReady, httplib.BadStatusLine,)
# Always retry when an apiclient.errors.HttpError with one of these status
# codes is raised.
RETRIABLE_STATUS_CODES = (500, 502, 503, 504,)
# The message associated with the HTTP 401 error that's returned when a request
# is authorized by a user whose account is not associated with a YouTube
# content owner.
INVALID_CREDENTIALS = "Invalid Credentials"
# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
# the OAuth 2.0 information for this application, including its client_id and
# client_secret. You can acquire an OAuth 2.0 client ID and client secret from
# the Google API Console at
# https://console.cloud.google.com/.
# See the "Registering your application" instructions for an explanation
# of how to find these values:
# https://developers.google.com/youtube/partner/guides/registering_an_application
# For more information about using OAuth2 to access Google APIs, please visit:
# https://developers.google.com/accounts/docs/OAuth2
# For more information about the client_secrets.json file format, please visit:
# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
CLIENT_SECRETS_FILE = "client_secrets.json"
# The local file used to store the cached OAuth 2 credentials after going
# through a one-time browser-based login.
CACHED_CREDENTIALS_FILE = "%s-oauth2.json" % sys.argv[0]
YOUTUBE_SCOPES = (
# An OAuth 2 access scope that allows for full read/write access.
"https://www.googleapis.com/auth/youtube",
# A scope that grants access to YouTube Partner API functionality.
"https://www.googleapis.com/auth/youtubepartner",)
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
YOUTUBE_CONTENT_ID_API_SERVICE_NAME = "youtubePartner"
YOUTUBE_CONTENT_ID_API_VERSION = "v1"
# Helpful message to display if the CLIENT_SECRETS_FILE is missing.
MISSING_CLIENT_SECRETS_MESSAGE = """
WARNING: Please configure OAuth 2.0
To make this sample run you need to populate the client_secrets.json file 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))
def parse_options():
parser = OptionParser()
parser.add_option("--file", dest="file", help="Video file to upload")
parser.add_option("--title", dest="title", help="Video title",
default="Test Title")
parser.add_option("--description", dest="description",
help="Video description",
default="Test Description")
parser.add_option("--category", dest="category",
help="Numeric video category. " +
"See https://developers.google.com/youtube/v3/docs/videoCategories/list",
default="22")
parser.add_option("--keywords", dest="keywords",
help="Video keywords, comma separated", default="")
parser.add_option("--privacyStatus", dest="privacyStatus",
help="Video privacy status: public, private or unlisted",
default="public")
parser.add_option("--policyId", dest="policyId",
help="Optional id of a saved claim policy")
parser.add_option("--channelId", dest="channelId",
help="Id of the channel to upload to. Must be managed by your CMS account")
(options, args) = parser.parse_args()
return options
def get_authenticated_services():
flow = flow_from_clientsecrets(
CLIENT_SECRETS_FILE,
scope=" ".join(YOUTUBE_SCOPES),
message=MISSING_CLIENT_SECRETS_MESSAGE
)
storage = Storage(CACHED_CREDENTIALS_FILE)
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = run(flow, storage)
youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
http=credentials.authorize(httplib2.Http()))
youtube_partner = build(YOUTUBE_CONTENT_ID_API_SERVICE_NAME,
YOUTUBE_CONTENT_ID_API_VERSION, http=credentials.authorize(httplib2.Http()),
static_discovery=False)
return (youtube, youtube_partner)
def get_content_owner_id(youtube_partner):
try:
content_owners_list_response = youtube_partner.contentOwners().list(
fetchMine=True
).execute()
except HttpError, e:
if INVALID_CREDENTIALS in e.content:
logging.error("Your request is not authorized by a Google Account that "
"is associated with a YouTube content owner. Please delete '%s' and "
"re-authenticate with an account that is associated "
"with a content owner." % CACHED_CREDENTIALS_FILE)
exit(1)
else:
raise
# This returns the CMS user id of the first entry returned
# by youtubePartner.contentOwners.list()
# See https://developers.google.com/youtube/partner/reference/rest/v1/contentOwners/list
# Normally this is what you want, but if you authorize with a Google Account
# that has access to multiple YouTube content owner accounts, you need to
# iterate through the results.
return content_owners_list_response["items"][0]["id"]
def upload(youtube, content_owner_id, options):
if options.keywords:
tags = options.keywords.split(",")
else:
tags = None
insert_request = youtube.videos().insert(
onBehalfOfContentOwner=content_owner_id,
onBehalfOfContentOwnerChannel=options.channelId,
part="snippet,status",
body=dict(
snippet=dict(
title=options.title,
description=options.description,
tags=tags,
categoryId=options.category
),
status=dict(
privacyStatus=options.privacyStatus
)
),
# chunksize=-1 means that the entire file will be uploaded in a single
# HTTP request. (If the upload fails, it will still be retried where it
# left off.) This is usually a best practice, but if you're using Python
# older than 2.6 or if you're running on App Engine, you should set the
# chunksize to something like 1024 * 1024 (1 megabyte).
media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True)
)
response = None
error = None
retry = 0
duration_seconds=0
while response is None:
try:
logging.debug("Uploading file...")
start_seconds = time.time()
status, response = insert_request.next_chunk()
delta_seconds = time.time() - start_seconds
duration_seconds += delta_seconds
if "id" in response:
return (response["id"], duration_seconds)
else:
logging.error("The upload failed with an unexpected response: %s" %
response)
exit(1)
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:
logging.error(error)
retry += 1
if retry > MAX_RETRIES:
logging.error("No longer attempting to retry.")
exit(1)
max_sleep = 2 ** retry
sleep_seconds = random.random() * max_sleep
logging.debug("Sleeping %f seconds and then retrying..." % sleep_seconds)
time.sleep(sleep_seconds)
def create_asset(youtube_partner, content_owner_id, title, description):
# This creates a new asset corresponding to a video on the web.
# The asset is linked to the corresponding YouTube video via a
# claim that will be created later.
body = dict(
type="web",
metadata=dict(
title=title,
description=description
)
)
assets_insert_response = youtube_partner.assets().insert(
onBehalfOfContentOwner=content_owner_id,
body=body
).execute()
return assets_insert_response["id"]
def set_asset_ownership(youtube_partner, content_owner_id, asset_id):
# This specifies that content_owner_id owns 100% of the asset worldwide.
# Adjust as needed.
body = dict(
general=[dict(
owner=content_owner_id,
ratio=100,
type="exclude",
territories=[]
)]
)
youtube_partner.ownership().update(
onBehalfOfContentOwner=content_owner_id,
assetId=asset_id,
body=body
).execute()
def claim_video(youtube_partner, content_owner_id, asset_id, video_id,
policy_id):
# policy_id can be set to the id of an existing policy, which can be obtained
# via youtubePartner.policies.list()
# See https://developers.google.com/youtube/partner/reference/rest/v1/policies/list
# If you later update that existing policy, the claim will also be updated.
if policy_id:
policy = dict(
id=policy_id
)
# If policy_id is not provided, a new inline policy is created.
else:
policy = dict(
rules=[dict(
action="monetize"
)]
)
body = dict(
assetId=asset_id,
videoId=video_id,
policy=policy,
contentType="audiovisual"
)
claims_insert_response = youtube_partner.claims().insert(
onBehalfOfContentOwner=content_owner_id,
body=body
).execute()
return claims_insert_response["id"]
def set_advertising_options(youtube_partner, content_owner_id, video_id):
# This enables the true view ad format for the given video.
# Adjust as needed.
body = dict(
adFormats=["trueview_instream"]
)
youtube_partner.videoAdvertisingOptions().update(
videoId=video_id,
onBehalfOfContentOwner=content_owner_id,
body=body
).execute()
if __name__ == '__main__':
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
options = parse_options()
if options.file is None or not os.path.exists(options.file):
logging.error("Please specify a valid file using the --file= parameter.")
exit(1)
# The channel ID looks something like "UC..." and needs to correspond to a
# channel managed by the YouTube content owner authorizing the request.
# youtube.channels.list(part="snippet", managedByMe=true,
# onBehalfOfContentOwner=*CONTENT_OWNER_ID*)
# can be used to retrieve a list of managed channels and their channel IDs.
# See https://developers.google.com/youtube/v3/docs/channels/list
if options.channelId is None:
logging.error("Please specify a channel ID via the --channelId= parameter.")
exit(1)
(youtube, youtube_partner) = get_authenticated_services()
content_owner_id = get_content_owner_id(youtube_partner)
logging.info("Authorized by content owner ID '%s'." % content_owner_id)
(video_id, duration_seconds) = upload(youtube, content_owner_id, options)
logging.info("Successfully uploaded video ID '%s'." % video_id)
file_size_bytes = os.path.getsize(options.file)
logging.debug("Uploaded %d bytes in %0.2f seconds (%0.2f megabytes/second)." %
(file_size_bytes, duration_seconds,
(file_size_bytes / (1024 * 1024)) / duration_seconds))
asset_id = create_asset(youtube_partner, content_owner_id,
options.title, options.description)
logging.info("Created new asset ID '%s'." % asset_id)
set_asset_ownership(youtube_partner, content_owner_id, asset_id)
logging.info("Successfully set asset ownership.")
claim_id = claim_video(youtube_partner, content_owner_id, asset_id,
video_id, options.policyId)
logging.info("Successfully claimed video.")
set_advertising_options(youtube_partner, content_owner_id, video_id)
logging.info("Successfully set advertising options.")
logging.info("All done!")