如何通过 YouTube Data API v3 从我自己的 YouTube 频道获取所有视频

Posted

技术标签:

【中文标题】如何通过 YouTube Data API v3 从我自己的 YouTube 频道获取所有视频【英文标题】:How to get all videos from my own YouTube channel via YouTube Data API v3 【发布时间】:2021-03-13 04:52:12 【问题描述】:

我需要从我自己的 YouTube 频道获取所有视频的 ID 和标题。有些视频未列出,但我也想获得它们。我使用这个版本的客户端库:

<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-youtube</artifactId>
    <version>v3-rev222-1.25.0</version>
</dependency>

根据我使用此 Java 代码的文档:

YouTube.Search.List request = youtubeService.search()
            .list("id,snippet");
SearchListResponse response = request.setChannelId(channelId)
            .setForMine(true)
            .setMaxResults(50L)
            .setType("video")
            .execute();

但是得到了这个异常:

400 Bad Request
GET https://www.googleapis.com/youtube/v3/search?channelId=channelId&forMine=true&maxResults=50&part=id,snippet&type=video

  "code" : 400,
  "errors" : [ 
    "domain" : "youtube.search",
    "location" : "parameters.",
    "locationType" : "other",
    "message" : "The request contains an invalid combination of search filters and/or restrictions. Note that you must set the <code>type</code> parameter to <code>video</code> if you set either the <code>forContentOwner</code> or <code>forMine</code> parameters to <code>true</code>. You must also set the <code>type</code> parameter to <code>video</code> if you set a value for the <code>eventType</code>, <code>videoCaption</code>, <code>videoCategoryId</code>, <code>videoDefinition</code>, <code>videoDimension</code>, <code>videoDuration</code>, <code>videoEmbeddable</code>, <code>videoLicense</code>, <code>videoSyndicated</code>, or <code>videoType</code> parameters.",
    "reason" : "invalidSearchFilter"
   ],
  "message" : "The request contains an invalid combination of search filters and/or restrictions. Note that you must set the <code>type</code> parameter to <code>video</code> if you set either the <code>forContentOwner</code> or <code>forMine</code> parameters to <code>true</code>. You must also set the <code>type</code> parameter to <code>video</code> if you set a value for the <code>eventType</code>, <code>videoCaption</code>, <code>videoCategoryId</code>, <code>videoDefinition</code>, <code>videoDimension</code>, <code>videoDuration</code>, <code>videoEmbeddable</code>, <code>videoLicense</code>, <code>videoSyndicated</code>, or <code>videoType</code> parameters."

此外,我在此页面上使用交互式工具时遇到了同样的错误:

https://developers.google.com/youtube/v3/docs/search/list?apix=true.

如果我删除 .setForMine(true) 它可以正常工作,但不会给我未列出的视频(只给我公开视频)。

是否有可能通过 API 从我自己的频道中获取所有视频(包括未列出)的 ID 和标题?

【问题讨论】:

五年前的***.com/questions/32454378/…,不知道还能不能用 【参考方案1】:

对您的问题的简短回答是:确实,有一个 API 可以提供您频道的所有视频元数据,包括未列出视频的元数据。 p>

对于更长的答案,请耐心等待:

首先,请注意给定视频具有以下类型的隐私状态:

status.privacyStatus(字符串) 视频的隐私状态。 此属性的有效值为:

私人 公开 未列出

要获取您频道上传的所有视频的 ID,无论其隐私状态如何,您都必须调用 PlaylistItems.list API 端点,并将参数 playlistId 设置为您频道的上传播放列表的 ID ,在发出 OAuth 授权请求时(即:向 API 传递一个有效的访问令牌;仅使用 API 密钥将使端点仅返回公共视频):

List<String> scopes = Lists.newArrayList(
    "https://www.googleapis.com/auth/youtube.readonly"); // or ".../auth/youtube"

Credential credential = Auth.authorize(scopes, "myuploads");

youtube = new YouTube.Builder(
    Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential)
    .setApplicationName("myuploads")
    .build();

List<String> videoIdList = new ArrayList<String>();

YouTube.PlaylistItems.List playlistItemRequest =
    youtube.playlistItems().list("contentDetails");
playlistItemRequest.setFields("nextPageToken,items/contentDetails/videoId");
playlistItemRequest.setMaxResults(50);
playlistItemRequest.setPlaylistId(uploadsPlaylistId);

String nextToken = "";
do 
    playlistItemRequest.setPageToken(nextToken);
    PlaylistItemListResponse playlistItemResult = playlistItemRequest.execute();

    for (PlaylistItem playlistItem: playlistItemResult.getItems())
        videoIdList.add(playlistItem.getContentDetails().getVideoId());

    nextToken = playlistItemResult.getNextPageToken();
 while (nextToken != null);

现在,Videos.list API 端点将为您提供由videoIdList 收集 ID 的视频的所有元数据。

List<Video> videoList = new ArrayList<Video>();
while (videoIdList.size() > 0) 
    int endIndex = videoIdList.size() < 50 ? videoIdList.size() : 50;
    List<String> subList = videoIdList.subList(0, endIndex);

    YouTube.Videos.List videosRequest =
        youtube.videos().list("id,contentDetails,status,snippet, statistics");
    videosRequest.setId(String.join(",", subList));
    VideoListResponse videosResponse = videoRequest.execute();

    videoList.AddAll(videosResponse.getItems());

    subList.clear();

请注意,如果videoIdList 在上述循环开始时的大小为N -- 因为Videos.list 端点的参数id 可以指定为以逗号分隔的视频ID 列表 -- ,循环代码通过适当使用刚才提到的id的特性,将Videos.list端点的调用次数从N减少到Math.floor(N / 50) + (N % 50 ? 1 : 0)

上传播放列表 ID -- uploadsPlaylistId -- 可以很容易地通过调用Channels.list 端点来获得设置为true:

YouTube.Channels.List channelRequest =
    youtube.channels().list("contentDetails");
channelRequest.setMine(true);
channelRequest.setFields("items/contentDetails/relatedPlaylists/uploads");
ChannelListResponse channelResult = channelRequest.execute();

请注意,上面我使用 fields 参数从 API 中仅获取所需的信息。

然后将在端点的 JSON 响应中作为属性值找到上传播放列表 ID:

items[0].contentDetails.relatedPlaylists.uploads.

翻译成Java,这个属性路径会变成下面的getter链,以getUploads结尾:

channelResult.getItems().get(0).getContentDetails().getRelatedPlaylists().getUploads().

请注意,对于给定的频道,您只需获取一次上传播放列表 ID,然后就可以根据需要多次使用它。通常,频道 ID 与其对应的上传播放列表 ID 以s/^UC([0-9a-zA-Z_-]22)$/UU\1/ 关联。

对于我上面描述的 API 调用的几乎完整实现(不包括填充列表 videoList 的循环),我建议使用来自 Google 的以下示例程序:MyUploads.java。构造列表videoList 的循环类似于GeolocationSearch.java 中的循环。方法Auth.authorize的实现见Auth.java

【讨论】:

非常感谢您的精彩回答。请将nextPageToken 添加到setFields 以请求播放列表项

以上是关于如何通过 YouTube Data API v3 从我自己的 YouTube 频道获取所有视频的主要内容,如果未能解决你的问题,请参考以下文章

如何使用来自 YouTube Data API V3 的 enpoint 搜索通过 channelId 获取频道图标

YouTube Data v3 API - 如何从频道请求所有视频?

使用 YouTube Data API v3 确定 YouTube 频道的上传速率

如何使用 YouTube Data API v3 更改页面结果

如何使用新的 YouTube Data API (V3) 获取某个频道的上传视频列表?

如何使用新的 YouTube Data API (V3) 获取某个频道的上传视频列表?