IAintFixingIt
IAintFixingIt

Reputation: 242

how to call client_secrets.json from an external directory java?

I basically have a dynamic WEB-APP which through a servlet I am trying to retrieve a youtube video comments.

Although there is alot of article about it in the web but I don't know why none worked for me.

First Attempt:

private static int counter = 0;
private static YouTube youtube;

public static void getYoutubeOauth() throws Exception {
    List<String> scopes = Lists.newArrayList("https://www.googleapis.com/auth/youtube.force-ssl");

    Credential credential = Auth.authorize(scopes, "commentthreads");
    youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential).build();

    String videoId = "KIgxmV9xXBQ";

    // Get video comments threads
    CommentThreadListResponse commentsPage = prepareListRequest(videoId).execute();

    while (true) {
        handleCommentsThreads(commentsPage.getItems());

        String nextPageToken = commentsPage.getNextPageToken();
        if (nextPageToken == null)
            break;

        // Get next page of video comments threads
        commentsPage = prepareListRequest(videoId).setPageToken(nextPageToken).execute();
    }

    System.out.println("Total: " + counter);
}

With this I am getting nullpointerexception at line: Credential credential = Auth.authorize(scopes, "commentthreads");

If you can please explain what is scope and where do you get it from.

Second Attempt I tried creating a different function for getting credentials.

Second Attempt:

   public static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
public static final JsonFactory JSON_FACTORY = new JacksonFactory();
private static final String CREDENTIALS_DIRECTORY = ".oauth-credentials";

public static Credential authorize(List<String> scopes, String credentialDatastore) throws IOException {

    // Load client secrets.
    Reader clientSecretReader = new InputStreamReader(
            Auth.class.getResourceAsStream("/home/hazrat/Documents/eclipse-jee-neon-3-linux-gtk-x86_64/eclipse/client_secrets.json"));
    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, clientSecretReader);

    // Checks that the defaults have been replaced (Default = "Enter X here").
    if (clientSecrets.getDetails().getClientId().startsWith("Enter")
            || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
        System.out.println(
                "Enter Client ID and Secret from https://console.developers.google.com/project/_/apiui/credential "
                        + "into src/main/resources/client_secrets.json");
        return null;
    }

    // This creates the credentials datastore at ~/.oauth-credentials/${credentialDatastore}
    FileDataStoreFactory fileDataStoreFactory = new FileDataStoreFactory(new File(System.getProperty("user.home") + "/" + CREDENTIALS_DIRECTORY));
    DataStore<StoredCredential> datastore = fileDataStoreFactory.getDataStore(credentialDatastore);

    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, scopes).setCredentialDataStore(datastore)
            .build();

    // Build the local server and bind it to port 8080
    LocalServerReceiver localReceiver = new LocalServerReceiver.Builder().setPort(8080).build();

    // Authorize.
    return new AuthorizationCodeInstalledApp(flow, localReceiver).authorize("user");
}

Here also Im getting an nullpointerexception at line Reader clientSecretReader = new InputStreamReader(... although If I would try nano /home/hazrat/Documents/eclipse-jee-neon-3-linux-gtk-x86_64/eclipse/client_secrets.json in my terminal I can access the file.

Question: How to authorize my web-app and read client_secrets.json from an external directory.

Upvotes: 1

Views: 686

Answers (1)

IAintFixingIt
IAintFixingIt

Reputation: 242

Was a bit painful but made the second solution working.

So what I was doing wrong was that I was calling Auth.class.getResourceAsStream which it requires the data to be available to classLoader but to my classLoader it was not.

so what I had to do is to request my client_secrets.json from an external directory which then you have to use FileInputStream other than getResourceAsStream.

Both FileInputStream and getResourceAsStream works fine but they differ on your situation and different code.

public static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
public static final JsonFactory JSON_FACTORY = new JacksonFactory();
private static final String CREDENTIALS_DIRECTORY = ".oauth-credentials";

public static Credential authorize(List<String> scopes, String credentialDatastore) throws IOException {
    Reader clientSecretReader = new InputStreamReader(
            new FileInputStream("/client_secrets.json"));
    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, clientSecretReader);
    System.out.println(clientSecretReader.toString());
    if (clientSecrets.getDetails().getClientId().startsWith("Enter")
            || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
        System.out.println(
                "Enter Client ID and Secret from https://console.developers.google.com/project/_/apiui/credential "
                        + "into src/main/resources/client_secrets.json");
        return null;
    }
    FileDataStoreFactory fileDataStoreFactory = new FileDataStoreFactory(new File(System.getProperty("user.home") + "/" + CREDENTIALS_DIRECTORY));
    DataStore<StoredCredential> datastore = fileDataStoreFactory.getDataStore(credentialDatastore);

    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, scopes).setCredentialDataStore(datastore)
            .build();
    LocalServerReceiver localReceiver = new LocalServerReceiver.Builder().setPort(8081).build();

    return new AuthorizationCodeInstalledApp(flow, localReceiver).authorize("user");
}

private static int counter = 0;
private static YouTube youtube;

public static void getYoutubeOauth() throws Exception {
    List<String> scopes = Lists.newArrayList("https://www.googleapis.com/auth/youtube.force-ssl");
    Credential credential = authorize(scopes, "commentthreads");
    youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential).build();

    String videoId = "KIgxmV9xXBQ";

    // Get video comments threads
    CommentThreadListResponse commentsPage = prepareListRequest(videoId).execute();

    while (true) {
        handleCommentsThreads(commentsPage.getItems());

        String nextPageToken = commentsPage.getNextPageToken();
        if (nextPageToken == null)
            break;

        commentsPage = prepareListRequest(videoId).setPageToken(nextPageToken).execute();
    }

    System.out.println("Total: " + counter);
}

private static YouTube.CommentThreads.List prepareListRequest(String videoId) throws Exception {

    return youtube.commentThreads()
                  .list("snippet,replies")
                  .setVideoId(videoId)
                  .setMaxResults(100L)
                  .setModerationStatus("published")
                  .setTextFormat("plainText");
}

private static void handleCommentsThreads(List<CommentThread> commentThreads) {

    for (CommentThread commentThread : commentThreads) {
        List<Comment> comments = Lists.newArrayList();
        comments.add(commentThread.getSnippet().getTopLevelComment());

        CommentThreadReplies replies = commentThread.getReplies();
        if (replies != null)
            comments.addAll(replies.getComments());

        System.out.println("Found " + comments.size() + " comments.");

        // Do your comments logic here
        counter += comments.size();
    }
}

Note: change FileInputStream location to your own location.

Then you can call getYoutubeOauth and hope for getting a working response :)

Upvotes: 1

Related Questions