注意:YouTube Content ID API 专供 YouTube 内容合作伙伴使用,并非所有开发者或所有 YouTube 用户都可以使用。如果您在 Google API 控制台中没有看到 YouTube Content ID API 作为一项服务,请访问 YouTube 帮助中心,详细了解 YouTube 合作伙伴计划。
本指南介绍了 YouTube 内容合作伙伴如何从 XML 内容 Feed 迁移到 YouTube Content ID API,以便将内容提取到 YouTube 的权利管理系统中。
概览
要使用 YouTube 的 Content ID 权利管理系统,您需要向 YouTube 提供资产的元数据、所有权信息、政策设置和参考资料。
YouTube 提供了多种传送资产数据的选项。定期传送大量内容的合作伙伴通常会使用批量上传方法,使用 YouTube DDEX Feed 或 YouTube 提供的电子表格模板指定资产信息。另外,您还可以使用 YouTube Content ID API 更精细地控制上传流程。
与批处理 XML Feed 和电子表格不同,您可以使用 API 逐个创建资源和其他资源。API 的单独方法可以提高上传速度和可靠性。您可以通过事务性方式管理上传流程,监控各项操作是否成功,并在出现任何问题时立即做出响应。您可以立即使用由 YouTube 生成的 ID 来更新内容管理系统,而不是使用后期处理批量作业。
本文档介绍了如何使用 YouTube Content ID API 在 YouTube 权利管理系统中定义您的资产。本文假定您目前正在使用 YouTube DDEX Feed 定义资产,并说明了如何使用 API 重新创建 XML 内容 Feed 的功能。更具体地说,它使用了示例 XML 内容 Feed,并标识了使用 Python 客户端库实现相同效果的 API 命令。
向 YouTube 传送资产数据的方法
使用 XML 内容 Feed 或 Content ID API 的最终结果是一样的:您在自己的合作伙伴账号中创建(或更新)YouTube 权利管理资源。在某些情况下,您还可以创建(或更新)YouTube 视频。
XML 内容 Feed 和 API 处理任务的方式有所不同。通过 XML 内容 Feed,您可以创建单个文件,其中包含资源的所有相关信息以及各资源之间的关系。在批量上传过程中,YouTube 会将 Feed 用作蓝图来创建实际资源。使用 API,您可以逐个创建资源,而无需批量创建。您可以监控每个资源和 API 调用的进度和成功。
当您直接使用 API 方法创建资源时,必须明确执行 YouTube 批量上传流程在后台处理的某些操作。最值得注意的是,您需要上传媒体文件并对问题做出响应(通过重试操作或报告错误)。您还需要按正确的顺序执行操作:例如,只有在视频制作完成后,您才能声明视频的版权。
YouTube XML 内容 Feed 格式中的每个根级元素都对应于您使用 YouTube API 创建的资源(或资源属性)。
| XML 元素及相应的 API 资源 | |
|---|---|
<asset> |
asset |
<file> |
videos.fileDetails(通过 YouTube Data API)或thumbnail(通过 YouTube Data API)或reference |
<ownership> |
ownership |
<rights_admin> |
assetMatchPolicy(针对匹配政策)claims.policy(针对使用政策) |
<rights_policy> |
policy |
<video> |
videos(来自 YouTube Data API) |
<video_breaks> |
videoAdvertisingOption.adbreaks[ ] |
<ad_policy> |
videoAdvertisingOption |
<claim> |
claim |
<playlist> |
playlist(来自 YouTube Data API) |
<relationship> |
各种 |
注意:YouTube Content ID API 目前不支持字幕文件、预告片或专辑封面文件。
对 <relationship> 元素的处理很好地说明了 XML Feed 和 API 之间的区别。
-
XML
<relationship>元素声明<item>和<related_item>元素之间存在关系,但没有明确说明这种关系的性质。YouTube 上传流程会根据内容的类型推断出适当的关系。例如,某项资产与视频之间的关系表示 YouTube 应将视频文件用作资产的参考,而广告政策与视频之间的关系表示为视频设置政策。 -
通过使用 YouTube Content ID API,您可以使用明确建立适当关系的特定 API 资源。如需将视频用作资产的参考,您需要创建
reference资源。要为某个视频设置广告政策,请创建一项videoAdvertisingOptions资源。只有在资源存在后,您才能设置其属性。
通过脚本上传素材资源数据
要使用 API 上传资产数据,您需要编写一个脚本,用于发送 API 请求、上传文件以及创建 YouTube 权利管理资源。本部分提供编写脚本的教程。
主要步骤如下:
- 创建使用 YouTube API 的基本脚本。
- 添加用于上传媒体文件的代码。
- 添加用于创建权利管理资源的代码。
- 操作您的脚本,以便配合您的内容传送系统。
本文档末尾提供了代码示例(第 4 步除外)。虽然代码是用 Python 编写的,但我们还提供了其他常用编程语言的客户端库。
第 1 步:进行 API 调用
发送第一个请求教程介绍了如何编写用于发送 YouTube Content API 请求的基本脚本。该教程中的示例脚本会对用户进行身份验证、授权 API 请求的使用并构建与 YouTube Content ID API 互动的资源。
该脚本是本例中使用的脚本的基础。但是,如上所述,本示例介绍了如何创建 YouTube 视频并声明其版权,并且您需要使用 YouTube Data API 来上传 YouTube 视频。为使本教程中的脚本也能访问 YouTube 数据 API,请添加以下两项内容:
-
授权对 YouTube Data API 中的上传功能的访问权限,方法是将其 URI 添加到
flow_from_clientsecrets调用中的scope参数(参见本教程的第 2 步)。FLOW = flow_from_clientsecrets( 'client_secrets.json ', scope='https://www.googleapis.com/auth/youtubepartner https://www.googleapis.com/auth/youtube.upload', message= 'error message')
-
构建用于与 YouTube Data API 交互的资源(参见教程的第 3 步)。
service = build("youtubePartner", "v1", http=http, static_discovery=False) dataApi = build("youtube", "v3", http=http)
第 2 步:上传视频文件
下一步是添加用于上传视频文件的函数。为了尽可能提高可靠性,请使用可续传上传协议。该协议可让您在发生网络中断或其他传输故障后恢复上传操作,从而在发生网络故障时节省时间和带宽。
YouTube Data API 文档中的上传视频指南提供了一个示例上传脚本:upload_video.py。通过添加 upload_video.py 中的 resumable_upload 函数,更新第 1 步中的基本脚本。您还需要添加函数依赖的 import 语句和变量定义。
第 3 步:创建 YouTube 权利管理资源
有了基本的框架,您就可以添加用于创建 YouTube 资产、视频和相关资源的代码了。
创建资源的顺序非常重要。例如,您需要先创建资产并上传视频,然后才能针对该资产声明视频版权。
电影、电视、音乐视频和网络视频资产的一般操作顺序如下:
- 创建资产资源 (
assets.insert) - 更新资产的所有权(
ownership.update)和匹配政策(assetMatchPolicy.update) - 创建视频资源 (
videos.insert),设置其元数据并上传媒体文件 - 更新视频的广告政策(
videoAdvertisingOptions.update) - 代表资产(
claims.insert)对视频提出版权主张 - 使用已主张版权的视频 (
references.insert) 为资产创建参考文件
录音或仅用作参考文件的资产的一般操作顺序相同,省略了第 3 步到第 5 步:
- 创建资产资源 (
assets.insert) - 更新资产的所有权(
ownership.update)和匹配政策(assetMatchPolicy.update) - 为素材资源创建参考 (
references.insert) 并上传媒体文件
本部分的其余内容通过比较示例 XML Feed 和示例脚本中的相应代码,详细介绍这些步骤。
第 3.1 步:创建资产
第一次调用是对该 API 的 assets.insert 方法。它对应于 XML Feed 的以下部分:
<asset type="web"> <title>Broadcast Yourself!: Using the YouTube Live APIs to stream to the world</title> <description>See a preview of the Google I/O presentation.</description> </asset>
如需在 asset 资源中指定这些值,您需要设置以下属性值:
{ "type": "web", "metadata": { "title": "Broadcast Yourself!: Using the YouTube Live APIs to stream to the world", "description": "See a preview of the Google I/O presentation." } }
从 API 返回的资源中提取 id 属性。该属性标识 YouTube 分配的资产 ID,用于唯一标识资产。此值在随后的几次 API 调用中是必需的,本文档后面会标识为 assetId。
第 3.2 步:更新资产的所有权
创建资产后,您可以使用 API 的 ownership.update 方法设置资产的所有权。此步骤与 XML Feed 的这一部分相对应:
<ownership/> <relationship> <item path="/feed/asset[1]"/> <related_item path="/feed/ownership[1]"/> </relationship>
XML 使用空的 <ownership> 标记,这表示您拥有相应内容的全球所有权。
您的 API 请求会将 assetId 请求参数设置为在第 1 步中获得的 assetId。它还将使用如下所示的属性值指定 ownership 资源:
assetId(请求参数):设置为第 1 步中获得的 assetId。general[0].ratio:100general[0].owner:“your_content_owner_name”general[0].type:“exclude”general[0].territories:[]
{ "general": [ "ratio": 100, "owner": "your_content_owner_name", "type": "exclude", "territories": [] ] }
这些属性表明指定内容所有者(您需要将 your_content_owner_name 替换为您的实际内容所有者姓名)拥有全部内容的全部 (general[0].ratio) 所有权。事实上,此 ownership 资源表示除了 (general[0].type) 所提供的地区列表 (general[0].territories) 以外,所有者在全球各地拥有该内容,但由于该属性的值为空列表,因此实际上并未排除任何地区。
第 3.3 步:设置资产的匹配政策
YouTube 权利管理系统提供了以下两种方法,供您将匹配政策与资产相关联,或使用政策与已声明版权的视频相关联:
-
使用之前保存的政策。在此方法中,您可以使用 API 来检索已保存的政策,找到要使用的政策,然后在设置资产的匹配政策或创建版权声明时指定该政策的唯一 ID。
-
在创建资产或版权主张时定义
policy资源。在这种情况下,政策资源不会保存,因此,该政策资源无法应用于其他资产或版权主张。
建议您采用第一种方法,因为它依赖于已保存的政策。这种方法的一大好处是,如果您更新保存的政策,您的更改将自动影响使用该政策的所有资产和声明。
不过,本文档中的代码示例使用第二种方法通过 API 的 assetMatchPolicy.update 方法来设置新资产的匹配政策。(本文档还使用了第二种方法来设置使用政策,即在声明视频版权时定义的政策)。本文档之所以使用第二种方法,是因为已保存政策的名称可能因合作伙伴而异;这种方法可确保同一代码对所有人都适用。
此步骤与 XML Feed 的这一部分相对应:
<rights_policy> <name>Monetize developer videos</name> </rights_policy> <rights_admin owner="True" type="match"/> <relationship> <item path="/feed/rights_admin[1]"/> <item path="/feed/rights_policy[1]"/> <related_item path="/feed/asset[1]"/> </relationship>
您的 API 请求将 assetId 参数设置为在第 1 步中获得的 assetId。它还发送了一个 assetMatchPolicy 资源,用于设置下列属性值:
{ "rules": [ { "action": "monetize", "conditions": { "requiredTerritories": { "type": "exclude", "territories": [] } } } ] }
以下示例展示了当您将已保存的政策设为资产的匹配政策时,系统将如何构建 assetMatchPolicy 资源。您的代码需要将 PolicyID 字符串替换为唯一标识您所保存政策的 ID。
{
"policyId": "PolicyID"
}注意:XML Feed 与 YouTube 内容管理器的政策页面一样,按名称指定政策。如需检索已保存政策的 ID,请使用 policies.list 方法。政策 ID 因合作伙伴而异,即使对于默认政策也是如此。
第 3.4 步:创建视频资源并上传媒体文件
您可以使用 Data API 的 videos.insert 方法上传视频。可续传上传指南指出了使用可续传上传流程上传视频的 HTTP 调用,我们的一些 API 客户端库也支持可续传上传。(以下示例代码将可续传上传流程与 Google API Python 客户端库结合使用。)
此步骤与 XML Feed 的这一部分相对应:
<video> <title>Broadcast Yourself!: Using the YouTube Live APIs to stream to the world</title> <description>See a preview of the Google I/O presentation.</description> <genre>Entertainment</genre> <keyword>”Google I/O” “YouTube Live APIs”</keyword> <public>True</public> </video> <file type="video"> <filename>GOOG_IO_Broadcast_Yourself.mov</filename> </file> <relationship> <item path="/feed/file[1]"/> <related_item path="/feed/video[1]"/> </relationship>
如果您要编写自定义代码来进行 API 调用,您需要发送一个初始请求,该请求会创建 video 资源并返回上传网址,然后发送第二个请求,以便将视频二进制文件数据上传到该网址。如果您使用的是 Python 客户端库(如示例所示),您可以在同一请求中发送 video 资源和视频二进制文件数据。
为了创建 XML 示例中所述的视频,您的 API 请求会将 part 参数的值设置为 snippet,status,并且请求正文中的 video 资源将设置以下属性。snippet.categoryId 值 (24) 对应于 Entertainment 类别,即与 XML Feed 中的视频相关联的类别。附录中对视频类别进行了更详细的说明。
{
"snippet": {
"title": "Broadcast Yourself!: Using the YouTube Live APIs to stream to the world",
"description": "See a preview of the Google I/O presentation.",
"tags": ["Google I/O", "YouTube Live APIs"],
"categoryId": 24
},
"status": {
"privacyStatus": "private"
}
}注意:我们建议您在上传视频时将视频的隐私状态设置为 private,然后在稍后的流程中将其更新为 public。如果您希望将视频作为公开视频上传,请将 status.privacyStatus 属性设置为 public。
从 API 返回的资源中提取 id 属性。该属性标识 YouTube 分配的用于唯一标识视频的视频 ID。此值在随后的几次 API 调用中是必需的,本文档后面会标识为 videoId。
第 3.5 步:轮询 Data API 以确定视频的处理时间
某些操作(如创建参考文件)需要 YouTube 处理完你的视频后才能执行。因此,该脚本的下一步是确保视频上传已完成。
要检查上传状态,请调用 Data API 的 videos.list 方法并设置以下请求参数:
该 API 会返回 video 资源列表(仅包含一项资源),您需要检查该资源的 processingDetails.processingStatus 属性的值,以确定 YouTube 是否仍在处理该视频。当 YouTube 处理完视频后,该属性的值将会更改为 processing 以外的值,例如 succeeded 或 failed。
示例代码每 12 秒调用一次 videos.list 方法,以确定视频是否已处理完毕。此状态检查不直接对应于 XML 中的任何元素;表示批量上传在处理 XML 时隐式处理的操作。
第 3.6 步:设置广告政策
在 YouTube 处理完视频后,您就可以更新 video 资源的广告设置了。调用 Content ID API 的 videoAdvertisingOptions.update 方法,为视频设置广告政策。此操作对应于 XML Feed 的这一部分:
<ad_policy> <instream standard="long" trueview="true"> <prerolls>Allow</prerolls> <postrolls>Allow</postrolls> <midrolls>Deny</midrolls> </instream> <overlay> <adsense_for_video>Allow</adsense_for_video> <invideo>Allow</invideo> </overlay> </ad_policy> <relationship> <item path="/feed/ad_policy[1]"/> <related_item path="/feed/video[1]"/> </relationship>
此示例中显示的政策允许 YouTube 展示 TrueView 个插播广告或重叠式广告,包括“长广告”30 秒的广告,在视频开头(前贴片广告)或结尾(后贴片广告)。
若要设置广告政策,请发送一个将 videoId 参数设置为之前获取的 videoId 的请求。请求的正文是一个 videoAdvertisingOptions 资源,用于设置如下所示的属性:
{
"breakPosition": ["preroll", "postroll"],
"adFormats": ["long", "trueview_instream", "overlay"]
}第 3.7 步:声明视频版权
在此步骤中,您需要通过调用 Content ID API 的 claims.insert 方法来对自己上传的视频主张版权并设置该视频的使用政策。此步骤与 XML Feed 的这一部分相对应:
<rights_policy> <rule action="monetize"/> </rights_policy> <rights_admin owner="True" type="match"/> <claim type="audiovisual" asset="/feed/asset[1]" rights_admin="/feed/rights_admin[1]" rights_policy="/feed/rights_policy[1]" video="/feed/video[1]"/>
与资产匹配政策一样,示例脚本也定义了一次性政策,而不是将已保存的政策与视频相关联。不过,如前所述,我们鼓励您在设置使用政策和匹配政策时使用已保存的政策。
在您随请求一起发送的 claim 资源中,设置下方资源中显示的属性。请注意,assetId 和 videoId 字符串需要替换为脚本在前面步骤中获得的值。
{
"assetId": assetId,
"videoId": videoId,
"contentType": "audiovisual",
"policy": {
"rules": [
{
"action": "monetize"
}
]
}
}从 API 返回的资源中提取 id 属性。该属性标识 YouTube 分配的声明 ID,用于唯一标识声明。此值在随后的 API 调用中是必需的,在本文档后面部分将标识为 claimId。
第 3.8 步:创建引用
使用 Content ID API 的 references.insert 方法为 Content ID 系统创建引用。您可以使用已主张版权的视频作为参考内容来创建参考,也可以在 API 调用中上传参考文件。如果您要根据已主张版权的视频创建参考文件(如示例脚本那样),则该版权主张必须已存在。
在您的 API 请求中,将 claimId 请求参数设置为在上一步中获得的 claimid。此外,还要发送一个设置如下所示属性的 reference 资源:
{
"contentType": "audiovisual"
}若要创建仅供参考的资产(无已主张版权的视频),请对上述请求做出以下更改:
- 省略
claimId请求参数 - 将
assetId属性添加到上传的reference资源。 - 上传参考文件作为 API 请求的
media_body。
第 3.9 步:将视频设为公开
如果您在制作视频时遵循了最佳做法,并将其隐私状态设为了“private”,则可以在上传流程成功后将其隐私状态更改为“public”。使用 YouTube Data API 的 videos.list 和 videos.update 方法检索新上传的视频的 video 资源,然后更新该资源。
首先,使用以下请求参数调用 Data API 的 videos.list 方法:
part=statusid=videoId
此方法会返回一个包含一项资源的列表,该资源使用指定的 videoId 来描述视频。将该资源的 status.privacyStatus 属性的值更改为 public,然后调用 Data API 的 videos.update 方法。设置以下请求参数:
part=status
请求的正文是修改后的视频资源。
第 4 步:与您的内容分发系统集成
附录中的示例代码直接在脚本中提供了相应资源的具体元数据。在实际操作中,您可能需要将脚本与内容管理系统集成。为构建更完整的内容分发系统,您可以添加如下步骤:
- 通过轮询您的内容管理系统,找出需要添加或更新的资产。
- 从内容管理系统检索资产元数据。
- 使用 YouTube 为创建的资产、视频、参考文件和版权主张提供的 ID 以及用于记录资产最近更新时间的时间戳来更新内容管理系统。
附录
XML Feed 文件示例
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.youtube.com/schemas/cms/2.0" notification_email="someone@example.com" channel="your_channel" content_owner="your_name"> <asset type="web"> <title>Broadcast Yourself!: Using the YouTube Live APIs to stream to the world</title> <description>See a preview of the Google I/O presentation.</description> </asset> <video> <title>Broadcast Yourself!: Using the YouTube Live APIs to stream to the world</title> <description>See a preview of the Google I/O presentation.</description> <genre>Entertainment</genre> <keyword>”Google I/O” “YouTube Live APIs”</keyword> <public>True</public> </video> <file type="video"> <filename>GOOG_IO_Broadcast_Yourself.mov</filename> </file> <relationship> <item path="/feed/file[1]"/> <related_item path="/feed/video[1]"/> </relationship> <content_rating system="youtube">L0 N0 S0 V0 D0 F0</content_rating> <relationship> <item path="/feed/content_rating[1]"/> <related_item path="/feed/video[1]"/> </relationship> <ownership/> <relationship> <item path="/feed/asset[1]"/> <related_item path="/feed/ownership[1]"/> </relationship> <rights_policy> <name>Monetize developer videos</name> </rights_policy> <rights_admin owner="True" type="match"/> <relationship> <item path="/feed/rights_admin[1]"/> <item path="/feed/rights_policy[1]"/> <related_item path="/feed/asset[1]"/> </relationship> <ad_policy> <instream standard="long" trueview="true"> <prerolls>Allow</prerolls> <postrolls>Allow</postrolls> <midrolls>Deny</midrolls> </instream> <overlay> <adsense_for_video>Allow</adsense_for_video> <invideo>Allow</invideo> </overlay> </ad_policy> <relationship> <item path="/feed/ad_policy[1]"/> <related_item path="/feed/video[1]"/> </relationship> <claim type="audiovisual" asset="/feed/asset[1]" rights_admin="/feed/rights_admin[1]" rights_policy="/feed/rights_policy[1]" video="/feed/video[1]"/> </feed>
示例脚本
示例代码使用 Google API Python 客户端库。
#!/usr/bin/python2.6 # -*- 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 Content ID API. Command-line application that retrieves the information about given content owner. Usage: $ python yt_partner_api.py --file="/path/to/reference/file" You can also get help on all the command-line flags the program understands by running: $ python yt_partner_api.py --help To get detailed log output run: $ python yt_partner_api.py --logging_level=DEBUG \ --file="/path/to/reference/file" """ import gflags import httplib import httplib2 import json import logging import sys import time import os from apiclient.discovery import build from apiclient.errors import HttpError from apiclient.http import MediaFileUpload from oauth2client.file import Storage from oauth2client.client import AccessTokenRefreshError from oauth2client.client import flow_from_clientsecrets from oauth2client.tools import run # 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] #httplib2.debuglevel = 4 FLAGS = gflags.FLAGS # 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 = '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 will need to populate the client_secrets.json file found at: %s with information from the API Console <https://console.cloud.google.com/ > """ % os.path.join(os.path.dirname(__file__), CLIENT_SECRETS) # Flags definition # # The gflags module makes defining command-line options easy for # applications. Run this program with the '--help' argument to see # all the flags that it understands. gflags.DEFINE_enum('logging_level', 'ERROR', ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], 'Set the level of logging detail.') gflags.DEFINE_string('file', None, 'The video file to upload.') def resumable_upload(insert_request): response = None error = None retry = 0 while response is None: try: print "Uploading file..." status, response = insert_request.next_chunk() if 'id' in response: print "'video id: %s was successfully uploaded." % (response['id']) return response['id'] else: exit("The upload failed with an unexpected response: %s" % response) 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: print error retry += 1 if retry > MAX_RETRIES: exit("No longer attempting to retry.") max_sleep = 2 ** retry sleep_seconds = random.random() * max_sleep print "Sleeping %f seconds and then retrying..." % sleep_seconds time.sleep(sleep_seconds) return None def createRequest(service, resource, operation, **kwargs): request = getattr(service, resource)() request = getattr(request, operation)(**kwargs) return request def executeOperation(service, resource, operation, **kwargs): request = getattr(service, resource)() request = getattr(request, operation)(**kwargs) return_value = request.execute() print json.dumps(return_value) return return_value def main(argv): # Let the gflags module process the command-line arguments try: argv = FLAGS(argv) except gflags.FlagsError, e: print '%s\nUsage: %s ARGS\n%s' % (e, argv[0], FLAGS) sys.exit(1) # 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 https://www.googleapis.com/auth/youtube.upload', message=MISSING_CLIENT_SECRETS_MESSAGE) # Set the logging according to the command-line flag logging.getLogger().setLevel(getattr(logging, FLAGS.logging_level)) # If the Credentials don't exist or are invalid run through the native client # flow. The Storage object will ensure that if successful the good # Credentials will get 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) # Create service and retrieve content owner service. partnerApi = build("youtubePartner", "v1", http=http) dataApi = build("youtube", "v3", http=http) try: title = 'Top Ten Ridiculous test #u', monetize_policy = {'rules': [{'action': 'monetize'}]} # Create the asset kwargs = {} metadata = {'title': title, 'description': 'Wow this is a really long description'} kwargs['body'] = {'metadata': metadata, 'type': 'web'} insert_asset = executeOperation(partnerApi, 'assets', 'insert', **kwargs) asset_id = insert_asset['id'] print 'Asset ID is ' + asset_id # Set asset ownership kwargs = {'assetId': asset_id} ownership = {'ratio': 100, 'owner': 'psomusictest', 'type': 'exclude', 'territories': []} body = {'general': [ownership], 'id': asset_id} kwargs['body'] = body set_ownership = executeOperation(partnerApi, 'ownership', 'update', **kwargs) # Set match policy kwargs = {'assetId': asset_id, 'body': monetize_policy} set_match_policy = executeOperation(partnerApi, 'assetMatchPolicy', 'update', **kwargs) # Insert video using resumable upload snippet = {'title': title, 'description': 'Wow this is a really long description', 'tags': ['fizzle', 'sizzle', 'razzle dazzle'], 'categoryId': '24'} status = {'privacyStatus': 'private'} body = { 'snippet': snippet, 'status': status } kwargs = {'part': 'snippet,status', 'body': body, 'media_body': MediaFileUpload(FLAGS.file, chunksize=-1, resumable=True)} insert_video = createRequest(dataApi, 'videos', 'insert', **kwargs) video_id = resumable_upload(insert_video) if not video_id: print 'video upload failed, so the rest of this exercise is pointless' return # Poll to see when video is processed kwargs = {'id': video_id, 'part': 'processingDetails'} check_video_status = createRequest(dataApi, 'videos', 'list', **kwargs) video_processed = False sleep_seconds = 12 while not video_processed: status = check_video_status.execute() processingDetails = status['items'][0]['processingDetails'] if processingDetails['processingStatus'] != 'processing': print 'hooray, it ' + processingDetails['processingStatus'] video_processed = True elif not 'processingProgress' in processingDetails: time.sleep(sleep_seconds) else: print ('so far, we processed %d/%d parts' % ( processingDetails['processingProgress']['partsProcessed'], processingDetails['processingProgress']['partsTotal'])) time.sleep(sleep_seconds) # Claim the video body = {'assetId': asset_id, 'videoId': video_id, 'policy': monetize_policy, 'contentType': 'audiovisual'} kwargs = {'body': body} claim_video = executeOperation(partnerApi, 'claims', 'insert', **kwargs) claim_id = claim_video['id'] print 'claim ID is ' + claim_id # Create the reference body = {'assetId': asset_id, 'videoId': video_id, 'contentType': 'audiovisual'} kwargs = {'claimId': claim_id, 'body': body} create_reference = executeOperation(partnerApi, 'references', 'insert', **kwargs) # Set ad policy (update video advertising options) ads = {'breakPosition': ['preroll','postroll'], 'adFormats': ['standard_instream','trueview_instream','overlay']} kwargs = {'videoId': video_id, 'body': ads} ads = executeOperation(partnerApi, 'videoAdvertisingOptions', 'update', **kwargs) #9 Update video's privacy status to public kwargs = {'part': 'status', 'id': video_id} video = executeOperation(dataApi, 'videos', 'list', **kwargs) video['items'][0]['status']['privacyStatus'] = 'public' kwargs = {'part': 'status', 'body': video['items'][0]} video = executeOperation(dataApi, 'videos', 'update', **kwargs) except AccessTokenRefreshError: print ("The credentials have been revoked or expired, please re-run" " the application to re-authorize") if __name__ == '__main__': main(sys.argv)
其他 API 操作
使用 Data API 检索视频类别列表
示例代码将 snippet.categoryID 属性的值设置为 24,该值对应于“Entertainment”流派。如果您希望脚本查找指定类型的 ID(而不是对类别 ID 进行硬编码),则可以调用 Data API 的 videoCategories.list 方法并设置以下请求参数:
part=snippetregionCode=US(您可以将regionCode设置为其他值,以检索其他国家/地区的视频类别)
对于 API 响应中的每个 videoCategory 资源,您需要检查 snippet.title 属性的值以确定类别名称,并从所需的类别中提取 id 属性。“Entertainment”的 videoCategory 资源如下所示:类别:
{
"id": "24",
"kind": "youtube#videoCategory",
"etag": "\"idnvT0N6oxG_2o6LCWUdZsqtqtk/I5rstjIK5PCItZFyWV-uw\"",
"snippet": {
"channelId": "UCBR8-60-B28hp2BmDPdntcQ",
"title": "Entertainment"
}
}