为特定 YouTube 订阅生成视频上传列表

Generating list of video uploads for a particular YouTube subscription

我正在尝试从我订阅的频道生成视频列表。

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.PlaylistItemListResponse;
import com.google.api.services.youtube.model.SubscriptionListResponse;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.Collections;

public class ApiExample {
    private static final String CLIENT_SECRETS= "client_secret.json";
    private static final Collection<String> SCOPES =
            Collections.singletonList("https://www.googleapis.com/auth/youtube.readonly");

    private static final String APPLICATION_NAME = "Stack Overflow MRE";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

    /**
     * Create an authorized Credential object.
     *
     * @return an authorized Credential object.
     * @throws IOException in the event that the client_secrets.json file is not found
     */
    public static Credential authorize(final NetHttpTransport httpTransport) throws IOException {
        // Load client secrets.
        InputStream in = ApiExample.class.getResourceAsStream(CLIENT_SECRETS);
        GoogleClientSecrets clientSecrets =
                GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow =
                new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
                        .build();
        return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
    }

    /**
     * Build and return an authorized API client service.
     *
     * @return an authorized API client service
     * @throws GeneralSecurityException, IOException
     */
    public static YouTube getService() throws GeneralSecurityException, IOException {
        final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        Credential credential = authorize(httpTransport);
        return new YouTube.Builder(httpTransport, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }

    /**
     * Call function to create API service object. Define and
     * execute API request. Print API response.
     *
     * @throws GeneralSecurityException, IOException, GoogleJsonResponseException
     */
    public static void main(String[] args)
            throws GeneralSecurityException, IOException {
        YouTube youtubeService = getService();
        // Define and execute the API request
        YouTube.Subscriptions.List request = youtubeService.subscriptions()
                .list("snippet");
        SubscriptionListResponse response = request.setMine(true).setMaxResults(1L).execute();
        String channelId = response.getItems().get(0).getSnippet().getResourceId().getChannelId();

        YouTube.PlaylistItems.List playListRequest = youtubeService.playlistItems().list("snippet");
        PlaylistItemListResponse playlistResponse = playListRequest.setPlaylistId(channelId).execute();
        playlistResponse.getItems().forEach(System.out::println);
    }
}

我已阅读YouTube API to fetch all videos on a channel, however my question is a little different because I am trying to get the list of videos from a Subscription, rather than from a Channel

我试图隔离频道 ID,以便按照 video from Google Developers 中有关如何执行此操作的说明进行操作。我用了 String channelId = response.getItems().get(0).getSnippet().getResourceId().getChannelId();

但是,当我 运行 上面的代码应该以 JSON 符号打印出该频道的视频列表时,我却看到了这个错误:

Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 404 Not Found
{
  "code" : 404,
  "errors" : [ {
    "domain" : "youtube.playlistItem",
    "location" : "playlistId",
    "locationType" : "parameter",
    "message" : "The playlist identified with the request's <code>playlistId</code> parameter cannot be found.",
    "reason" : "playlistNotFound"
  } ],
  "message" : "The playlist identified with the request's <code>playlistId</code> parameter cannot be found."
}
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:150)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.interceptResponse(AbstractGoogleClientRequest.java:321)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1067)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
    at ApiExample.main(ApiExample.java:93)

显然,我没有正确隔离频道ID,否则我误解了视频。从 YouTube 订阅中获取视频的正确方法是什么?

编辑

我的主要方法中的以下更改起作用了:

public static void main(String[] args)
            throws GeneralSecurityException, IOException {
    YouTube youtubeService = getService();
    // Define and execute the API request
    YouTube.Subscriptions.List request = youtubeService.subscriptions()
            .list("snippet")
    SubscriptionListResponse response = request.setMine(true).setMaxResults(1L).execute();
    String channelId = response.getItems().get(0).getSnippet().getResourceId().getChannelId();

    YouTube.Channels.List channelRequest = youtubeService.channels().list("contentDetails");
    ChannelListResponse channelResponse = channelRequest.setId(channelId).execute();
    String playListID = channelResponse.getItems().get(0).getContentDetails().getRelatedPlaylists().getUploads();

    YouTube.PlaylistItems.List playListRequest = youtubeService.playlistItems().list("snippet");
    PlaylistItemListResponse playlistResponse = playListRequest.setPlaylistId(playListID).execute();
    playlistResponse.getItems().forEach(System.out::println);
}

上面代码的问题归结为以下文档条目:

playlistId (string)

The playlistId parameter specifies the unique ID of the playlist for which you want to retrieve playlist items. Note that even though this is an optional parameter, every request to retrieve playlist items must specify a value for either the id parameter or the playlistId parameter.

现在事情应该明白了:playlistId是播放列表的ID,因此不能是频道的ID。

但要列出给定频道(由其 ID 标识)的所有上传视频,必须执行以下操作:

调用设置为该频道上传播放列表 ID 的 PlaylistItems.list API endpoint queried with the parameter playlistId

通过调用设置为您频道 ID 的 Channels.list endpoint queried with the parameter id 可以很容易地获得后一个 ID。

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

的值

items[0].contentDetails.relatedPlaylists.uploads.

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

结尾

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

请注意,对于给定的频道,您只需获取一次上传播放列表 ID,然后根据需要多次使用它。

通常,一个频道ID和它对应的上传播放列表ID通过s/^UC([0-9a-zA-Z_-]{22})$/UU/关联。