0
votes

I am trying to get a list of my youtube channels from a java app using the com.google.api.services.youtube.YouTube class. .

First of all I have enabled the Service Account credentials (https://console.developers.google.com > Credentials ) and I have enabled the following apis : -YouTube Analytics API -YouTube Data API -Analytics API

To make a call to the Youtube service I create a Credential object using the following code.


/** Global instance of the HTTP transport. */
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();

private static Credential authorize() throws Exception 
{

List<String> scopes = new ArrayList<String>();
    scopes.add("https://www.googleapis.com/auth/youtube");  
    scopes.add("https://www.googleapis.com/auth/yt-analytics.readonly");
    scopes.add("https://www.googleapis.com/auth/youtube.readonly");
    scopes.add("https://www.googleapis.com/auth/youtubepartner-channel-audit");

    GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
        .setJsonFactory(JSON_FACTORY)
        .setServiceAccountPrivateKeyFromP12File(new File("C://file.privatekey.p12"))
        .setServiceAccountId("[email protected]")
        .setServiceAccountScopes(scopes)
        .build();
        return credential;
  }

After that I call the Youtube service to get my channels


/** Global instance of the HTTP transport. */
  private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();


  /** Global instance of the JSON factory. */
  private static final JsonFactory JSON_FACTORY = new JacksonFactory();


  /** Global instance of Youtube object to make general YouTube API requests. */
  private static YouTube youtube;

  /** Global instance of YoutubeAnalytics object to make analytic API requests. */
  private static YouTubeAnalytics analytics;


public String getDefaultChannelId(){
      try{
      Credential credential = authorize();
      // YouTube object used to make all non-analytic API requests.
      youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
        .setApplicationName("API Project")
        .build();

      YouTube.Channels.List channelRequest = youtube.channels().list("id,snippet");
      channelRequest.setMine(true);
      channelRequest.setMaxResults(50L);
    channelRequest.setFields("items(id,snippet/title,contentDetails,status,kind,etag,auditDetails)");
      ChannelListResponse channels = channelRequest.execute();

      System.out.println(channels.getItems());

      // List of channels associated with user.
      List<Channel> listOfChannels = channels.getItems();

      // Grab default channel which is always the first item in the list.
      Channel defaultChannel = listOfChannels.get(0);
      String channelId = defaultChannel.getId();
      return channelId;
    }catch(Exception ex){
      ex.printStacktrace();
    }
}

The authorization code seems to work without any problem. The problem is with the getDefaultChannelId() method which returns a channel with id UC9i22sTxrX0IQk4AkT_Og3w . I tried to navigate using the browser to my youtube channel using tha url : http://www.youtube.com/channel/UC9i22sTxrX0IQk4AkT_Og3w but the channel does not exist..

The line I used to print the channels results "System.out.println(channels.getItems());" displays the following json string.

[{"etag":"\"BDC7VThyM9nfoSQm1_kOyhtJTEw/yJvLzly7DMctrvFV5drOtgksadM\"","id":"UC9i22sTxrX0IQk4AkT_Og3w","kind":"youtube#channel","snippet":{"title":""}}

For some reason the youtube service does not return the right list of channels for the specific credential object. But why????

1

1 Answers

3
votes

You can not use Service Account with Youtube API : https://developers.google.com/youtube/v3/guides/moving_to_oauth#service_accounts. Youtube API is supposed to raise an error with service account but apparently it doesn't.

You should instead create a client ID of type Installed Application then retrieve a refresh token for your user (https://developers.google.com/accounts/docs/OAuth2InstalledApp) and use this token to create credentials.

Here is an example (store clientId, clientSecret, refreshToken and accessToken wherever you like, as soon as you keep it secret, token response should be cached) :

private String clientId;
private String clientSecret;
private String refreshToken;
private String accessToken;
private TokenResponse tokenResponse;

private Credential createCredential() {
    final GoogleCredential.Builder builder = new GoogleCredential.Builder();
    builder.setTransport(HTTP_TRANSPORT);
    builder.setJsonFactory(JSON_FACTORY);
    builder.setClientSecrets(clientId, clientSecret);
    builder.addRefreshListener(new CredentialRefreshListener() {
        @Override
        public void onTokenResponse(final Credential credential,
                final TokenResponse tokenResponse) throws IOException {
            this.tokenResponse = tokenResponse;
        }

        @Override
        public void onTokenErrorResponse(final Credential credential,
                final TokenErrorResponse tokenErrorResponse)
                throws IOException {
            this.tokenResponse = null;
            // trace error
        }
    });
    return builder.build();
}

private YouTube getYoutube() {
    final Credential credential = createCredential();
    if (this.tokenResponse == null) {
        credential.setAccessToken(this.accessToken);
        credential.setRefreshToken(this.refreshToken);
    } else {
        credential.setFromTokenResponse(this.tokenResponse);
    }

    final YouTube youtube = new YouTube.Builder(HTTP_TRANSPORT,
            JSON_FACTORY, credential).setApplicationName("*****").build();
    return youtube;
}