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

Java 如何通过YouTube数据API v3从我自己的YouTube频道获取所有视频,java,youtube-api,youtube-data-api,Java,Youtube Api,Youtube Data Api,我需要从我自己的YouTube频道获取所有视频的ID和标题。有些视频未列出,但我也想获得它们。我使用此版本的客户端库: <dependency> <groupId>com.google.apis</groupId> <artifactId>google-api-services-youtube</artifactId> <version>v3-rev222-1.25.0</version>

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

<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-youtube</artifactId>
    <version>v3-rev222-1.25.0</version>
</dependency>
但有一个例外:

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和标题?

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

对于较长的答案,请耐心听我说:

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

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

  • 私人的
  • 公开的
  • 未上市
为了获得频道上传的所有视频的ID,不管它们的隐私状态如何,您必须在发出OAuth授权请求的同时调用API端点,该端点使用设置为频道上传播放列表ID的参数进行查询(即:向API传递有效的访问令牌;仅使用API密钥将使端点仅返回公共视频):

List scopes=Lists.newArrayList(
"https://www.googleapis.com/auth/youtube.readonly“”;//或“../auth/youtube”
凭证=授权(作用域,“myuploads”);
youtube=新建youtube.Builder(
Auth.HTTP_传输、Auth.JSON_工厂、凭证)
.setApplicationName(“myuploads”)
.build();
请注意,如果上面循环开头的
videoIdList
大小为
N
,因为
Videos.list
端点的参数可以指定为以逗号分隔的视频ID列表,则循环代码会减少对
Videos.list
端点的调用次数,从
N
Math.floor(N/50)+(N%50?1:0)
通过适当使用刚才提到的
id
功能

上传播放列表ID--
uploadsPlaylistId
--可以通过调用使用设置为频道ID的参数查询的端点,或者使用设置为
true
的参数查询的端点来轻松获得:

YouTube.Channels.List channelRequest =
    youtube.channels().list("contentDetails");
channelRequest.setMine(true);
channelRequest.setFields("items/contentDetails/relatedPlaylists/uploads");
ChannelListResponse channelResult = channelRequest.execute();
请注意,上面我使用的参数for仅从API获取所需的信息

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

转换为Java后,此属性路径将成为以下getter链,以:

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

请注意,对于给定的频道,您只需获得上传播放列表ID一次,然后根据需要多次使用它。通常,频道ID及其相应的上传播放列表ID通过
s/^UC([0-9a-zA-Z-]{22})$/UU\1/
进行关联


对于上述API调用的几乎完整实现(不包括填充列表的循环
videoList
),我建议使用Google提供的以下示例程序:。构建列表的循环与中的循环类似。方法
Auth.authorize
的实现可以在中找到。

有五年前的,不确定是否仍然有效。感谢您的精彩回答。请例如,将播放列表项的
nextPageToken
添加到
setFields
中确实,你说得对!我修正了我的答案。
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);
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();
}
YouTube.Channels.List channelRequest =
    youtube.channels().list("contentDetails");
channelRequest.setMine(true);
channelRequest.setFields("items/contentDetails/relatedPlaylists/uploads");
ChannelListResponse channelResult = channelRequest.execute();