Page Summary
-
The YouTube Content ID API is only available to YouTube content partners and requires access through the Google API Console.
-
Uploading a reference via the YouTube Content ID API involves creating an asset, configuring its ownership and match policy, and then uploading the reference file.
-
The process uses OAuth 2.0 for authorization, which involves a
client_secrets.jsonfile and the storage of credentials for later use. -
The code provided demonstrates these steps using a Python script, and it uses
httplib2to manage API requests after they're authorized. -
The script does not include error handling and requires specific parameters such as a reference file, asset title, and content owner name to execute properly.
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. Access requires a YouTube Content Manager account, and the API appears in the Google Cloud console only when you sign in with a Google Account that is an active Content Manager user (allow 1 to 2 days after accepting an invitation for access to sync). If you still don't see the YouTube Content ID API after 2 days, contact your YouTube point of contact or partner support.
This code sample demonstrates how to upload a
reference
using the YouTube Content ID API. To upload a
reference,
you must first create an
asset and
configure the asset's ownership and match policy. This example walks through all of these
steps.
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.
The sample script does not do any error handling.
Requirements
- Python 3.7 or higher
- google-api-python-client
In this step, we'll 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 YouTube Content ID API requires a client_secrets.json file, which contains information from the Cloud console, to perform authentication. You also need to register your application. For a more complete explanation of how authentication works see the authentication guide.
{ "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" } }
Add authentication code to your script
To enable user authentication and authorization, you need to add the following import statements:
from datetime import datetime from oauth2client.file import Storage from oauth2client.client import flow_from_clientsecrets from oauth2client.tools import argparser, run_flow
Next, we'll create a FLOW object using the client secrets configured in step 2a. 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 will need to reauthorize our application if the credentials expire.
Add the following code to the end of the main function:
# Set up a Flow object to be used if we need to authenticate. FLOW = flow_from_clientsecrets('client_secrets.json', scope='https://www.googleapis.com/auth/youtubepartner', message='error message') # The Storage object stores the credentials. If it doesn't exist, or if # the credentials are invalid or expired, run through the native client flow. storage = Storage('yt_partner_api.dat') credentials = storage.get() if (credentials is None or credentials.invalid or credentials.token_expiry <= datetime.now()): credentials = run_flow(FLOW, storage, args)
Create httplib2 object and attach credentials
After the user authorizes our script, we create an httplib2.Http object, which handles API requests, and attach the authorization credentials to that object.
Add the following import statement:
import httplib2
And add this code to the end of the main function:
# Create httplib2.Http object to handle HTTP requests and # attach auth credentials. http = httplib2.Http() http = credentials.authorize(http)
Obtain services
After successful authorization, the code obtains the necessary services for the
operations it will perform. It first creates a service object that provides
access to all YouTube Content ID API services. The code then uses the service
object to obtain the four resource-specific services it calls.
from apiclient.discovery import build
# ...
service = build("youtubePartner", "v1", http=http, static_discovery=False)
# ...
asset_service = service.assets()
# ...
ownership_service = service.ownership()
# ...
match_policy_service = service.assetMatchPolicy()
# ...
reference_service = service.references()
Create an Asset
The first step in uploading a
reference
is to create the
asset. First
we create a simple metadata object that only sets the asset's title. The code
then adds that object to the asset_body, which also identifies the asset's
type. The asset_body object, in turn, is used as input to the
asset_service.insert() method. That method creates the asset and returns its
unique ID.
def _create_asset(service, title, metadata_type):
metadata = {'title': title}
asset_body = {'metadata': metadata, 'type': metadata_type}
# Retrieve asset service.
asset_service = service.assets()
# Create and execute insert request.
request = asset_service.insert(body=asset_body)
response = request.execute()
logger.info('Asset has been created.\n%s', response)
asset_id = response['id']
return asset_id
Update the Ownership
After creating the
asset, the
script configures the asset's
ownership.
This example indicates that the content owner owns 100% of the asset but that
that ownership is limited to Poland (PL) and Great Britain (GB).
def _create_asset_ownership(service, asset_id, owner_name):
ownership = {
'owner': owner_name,
'ratio' : 100,
'type': 'include',
'territories': ['PL', 'GB']}
ownership_body = {'general': [ownership]}
ownership_service = service.ownership()
request = ownership_service.update(assetId=asset_id, body=ownership_body)
response = request.execute()
logger.info('Asset ownership has been created.\n%s', response)
Update the asset's match policy
Before creating the reference, the code must also configure the asset's match
policy by updating the
assetMatchPolicy
resource associated with the asset. The asset's match policy dictates the action
that YouTube will take when a video on YouTube is found to match any reference
associated with that asset. This example creates a simple policy that tracks
worldwide any matches longer than 10 seconds.
def _create_match_policy(service, asset_id):
match_policy_service = service.assetMatchPolicy()
everywhere_policy_condition = {
'requiredTerritories': {
'type': 'exclude', 'territories': []},
'requiredReferenceDuration': [{'low': 10}],
'contentMatchType': 'video'}
track_everywhere_rule = {
'action': 'track',
'condition': everywhere_policy_condition}
request = match_policy_service.update(
assetId=asset_id,
body={
'name': 'Track Everywhere 10s.',
'description': 'Track Everywhere matches longer than 10s.',
'rules': [track_everywhere_rule]})
response = request.execute()
logger.info('Asset match policy has been created.\n%s', response)
Upload the Reference
Once the
asset,
ownership
and
assetMatchPolicy
are in place, the script uploads a
reference.
It uses the MediaFileUpload method so that it can take advantage of resumable
uploading. Note that the reference_file parameter specifies the name of a
local file to be uploaded, and that value is passed to the script using the
reference_file command-line option.
def _create_reference(service, asset_id, reference_file):
reference_service = service.reference()
media = MediaFileUpload(reference_file, resumable=True)
request = reference_service.insert(
body={'assetId': asset_id, 'contentType': 'video'},
media_body=media)
status, response = request.next_chunk()
while response is None:
status, response = request.next_chunk()
if status:
logger.info("Uploaded %d%%.", int(status.progress() * 100))
logger.info('Reference has been created.\n%s', response)
Full code sample
The complete working sample asset_reference_upload_example.py is listed below:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012 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 asset, asset ownership, match policy
and reference.
Usage:
$ python3 asset_reference_upload_example.py --reference_file=REFERENCE_FILE \
--asset_title=ASSET_TITLE --owner=OWNER
You can also get help on all the command-line flags the program understands
by running:
$ python3 asset_reference_upload_example.py --help
"""
__author__ = 'mateuszz+pub@google.com (Mateusz Zięba)'
import argparse
import httplib2
import logging
import os
import sys
from apiclient.discovery import build
from apiclient.errors import HttpError
from apiclient.http import MediaFileUpload
from oauth2client.client import AccessTokenRefreshError
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run
# 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 Cloud console at
# https://console.cloud.google.com/.
# See the "Implement authorization" instructions for an explanation
# of how to find these values:
# https://developers.google.com/youtube/partner/guides/auth#prerequisites
CLIENT_SECRETS = 'client_secrets.json'
# 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 found at:
%s
with information from the Cloud console
<https://console.cloud.google.com/>.
""" % os.path.join(os.path.dirname(__file__), CLIENT_SECRETS)
# Set up a Flow object to be used if we need to authenticate.
FLOW = flow_from_clientsecrets(CLIENT_SECRETS,
scope='https://www.googleapis.com/auth/youtubepartner',
message=MISSING_CLIENT_SECRETS_MESSAGE)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())
def _create_asset(service, title, metadata_type):
metadata = {'title': title}
asset_body = {'metadata': metadata, 'type': metadata_type}
# Retrieve asset service.
asset_service = service.assets()
# Create and execute insert request.
request = asset_service.insert(body=asset_body)
response = request.execute()
logger.info('Asset has been created.\n%s', response)
asset_id = response['id']
return asset_id
def _create_asset_ownership(service, asset_id, owner_name):
ownership = {
'owner': owner_name,
'ratio' : 100,
'type': 'include',
'territories': ['PL', 'GB']}
ownership_body = {'general': [ownership]}
ownership_service = service.ownership()
request = ownership_service.update(assetId=asset_id, body=ownership_body)
response = request.execute()
logger.info('Asset ownership has been created.\n%s', response)
def _create_match_policy(service, asset_id):
match_policy_service = service.assetMatchPolicy()
everywhere_policy_condition = {
'requiredTerritories': {
'type': 'exclude', 'territories': []},
'requiredReferenceDuration': [{'low': 10}],
'contentMatchType': 'video'}
track_everywhere_rule = {
'action': 'track',
'condition': everywhere_policy_condition}
request = match_policy_service.update(
assetId=asset_id,
body={
'name': 'Track Everywhere 10s.',
'description': 'Track Everywhere matches longer than 10s.',
'rules': [track_everywhere_rule]})
response = request.execute()
logger.info('Asset match policy has been created.\n%s', response)
def _create_reference(service, asset_id, reference_file):
reference_service = service.references()
media = MediaFileUpload(reference_file, resumable=True)
request = reference_service.insert(
body={'assetId': asset_id, 'contentType': 'video'},
media_body=media)
status, response = request.next_chunk()
while response is None:
status, response = request.next_chunk()
if status:
logger.info("Uploaded %d%%.", int(status.progress() * 100))
logger.info('Reference has been created.\n%s', response)
def _parse_options():
parser = argparse.ArgumentParser(
description='Creates asset, asset ownership, match policy and reference.')
parser.add_argument('--version',
default='v1',
help='API version.')
parser.add_argument('--reference_file', required=True,
help='File containing reference to be uploaded. Required')
parser.add_argument('--asset_title', required=True,
help='Asset title. Required')
parser.add_argument('--owner', required=True,
help='Content owner name. Required')
return parser.parse_args()
def main():
options = _parse_options()
# If the Credentials don't exist or are invalid run through the native client
# flow. The Storage object ensures that if successful the good
# Credentials are written back to a file.
storage = Storage('yt_partner_api.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = run(FLOW, storage)
# Create an httplib2.Http object to handle our HTTP requests and authorize it
# with our good Credentials.
http = httplib2.Http()
http = credentials.authorize(http)
service = build("youtubePartner", options.version, http=http, static_discovery=False)
try:
asset_id = _create_asset(service, options.asset_title, 'web')
_create_asset_ownership(service, asset_id, options.owner)
_create_match_policy(service, asset_id)
_create_reference(service, asset_id, options.reference_file)
except AccessTokenRefreshError:
logger.info("The credentials have been revoked or expired, please re-run"
" the application to re-authorize")
if __name__ == '__main__':
main()