Youtube Data APIを試してみた

# はじめに
Youtube Data APIを使ったサンプルを動かしてみました。

# 環境
言語：Java11
Youtube Data API：v3-rev20210915-1.32.1

# コードを書く前に
## Googleアカウント周りの設定
Youtube Data APIを使用するには、Googleアカウントが必要です。

### Googleアカウントを登録する
プログラム登録は[こちら](https://accounts.google.com/signup/v2/webcreateaccount?continue=https%3A%2F%2Faccounts.google.com%2FManageAccount%3Fnc%3D1&hl=ja&flowName=GlifWebSignIn&flowEntry=SignUp)

### Google Cloud周りの設定
APIリクエストを送信できるようにするため、Google Cloudで必要なものを各種設定します。
設定は[こちら](https://console.cloud.google.com/apis/dashboard)

#### プロジェクトを作成する
まずはプロジェクトを作成します。
コンソール画面から「プロジェクトを作成」を選択します。
![スクリーンショット 2022-10-29 13.16.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/eb0624e0-6889-5f2e-9c2c-1920e849f1de.png)

プロジェクトの作成画面に遷移しますので、プロジェクト名など必要な事項を入力して「作成」ボタンを押下します。

![スクリーンショット 2022-10-29 13.17.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/c77259c3-a087-57fa-2a1b-67b6925814d3.png)

コンソール画面上に作成したプロジェクト名が表示されていれば成功です。
![スクリーンショット 2022-10-29 13.18.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/7f395aad-727a-7f17-36ca-f0207dec58e7.png)

#### YouTube Data APIを有効化する
次にGoogleのサービスを利用するためにYouTube Data APIを有効にします。
「＋APIとサービスの有効化」を押下します。
![スクリーンショット 2022-10-29 13.28.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/4e9b8e35-e13e-c18b-dcd3-da304440a98e.png)

APIライブラリの検索画面が表示されます。
「youtube」と検索すると「youtube data api v3」と候補に上がってくるので、検索を続けます。
![スクリーンショット 2022-10-29 13.29.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/7e1f8c67-cef2-af9a-291f-58da6be6df75.png)

検索結果に「Youtube Data Api v3」が出てきますので、押下します。
![スクリーンショット 2022-10-29 13.30.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/f589285c-5c3a-67d2-9d9b-79a2bcec4d7c.png)

「有効にする」ボタンが表示されるので、続けて押下します。
![スクリーンショット 2022-10-29 13.30.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/c4c2f279-d5a5-f5d6-c7b6-6fd21c613224.png)

結果、「Youtube Data Api v3」のステータスが有効になっていれば成功です。
![スクリーンショット 2022-10-29 13.30.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/fbb0bd45-cc08-3e46-8c66-b3ac0da06ddd.png)

#### 認証情報を生成する
最後にAPIにアクセスする時に使用する認証情報を生成します。
「認証情報を作成」ボタンを押下します。
![スクリーンショット 2022-10-29 13.40.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/bc12c0da-23ae-34a6-c85c-f9b3c35a4fcc.png)

使用するAPI、データの種類を選択し次に進みます。
![スクリーンショット 2022-10-29 13.41.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/04ad5ddc-51e5-7d73-9083-007f4bd42e67.png)

認証で使用するAPIキーが表示されるので、コピーして控えておきます。
「完了」ボタンを押下したら完了です。
![スクリーンショット 2022-10-29 13.41.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569086/c16b6119-3198-0c27-7ea5-53814d866db1.png)

# サンプルコードを動かしてみる
## ライブラリを追加
[こちら](https://github.com/googleapis/google-api-java-client-services/tree/main/clients/google-api-services-youtube/v3) を参考にbuild.gradleにライブラリを追加します。

```build.gradle
repositories {
    mavenCentral()
}

dependencies {
    compile 'com.google.apis:google-api-services-youtube:v3-rev20210915-1.32.1'
    // ・・・
}
```

## サンプルコード
[こちら](https://v3.oneplus-solution.com/9624afde44b61a8196f8/youtube/v3/docs/search/list?hl=ja) のページに記載されているサンプルコードを参考に動かしてみます。

### propertiesを作成
サンプルコードを読み取ると、認証情報のAPIキーはpropertiesファイルから読み取るようにしています。
なので、「youtube.properties」という名前のファイルを作成します。
作成したファイルはサンプルコードのクラスと同階層に配置します。

```youtube.properties
youtube.apikey=xxxxxxxxxxxxxx
```

### サンプルコードを実装
サンプルコードを実際に実装してみます。
使用しているJsonFactoryクラスが使用出来ないなど、細かい箇所に最新と差異があるようなので、都度書き換えてます。

```Search.java
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.ResourceId;
import com.google.api.services.youtube.model.SearchListResponse;
import com.google.api.services.youtube.model.SearchResult;
import com.google.api.services.youtube.model.Thumbnail;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/**
 * 検索語に基づいてビデオのリストを出力します。
 */
public class Search {

    /** プロパティのファイル名。 */
    private static String PROPERTIES_FILENAME = "youtube.properties";

    /** HTTPトランスポート */
    private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();

    /** JSONファクトリ */
    private static final JsonFactory JSON_FACTORY = new GsonFactory();

    /** HTTPリクエストの初期化クラス */
    private static final HttpRequestInitializer HTTP_REQUEST_INITIALIZER = new HttpRequestInitializer() {
        public void initialize(HttpRequest request) throws IOException {}
    };

    /** 返される動画の最大数 (50 = ページあたりの上限) */
    private static final long NUMBER_OF_VIDEOS_RETURNED = 25;

    /** すべてのAPIリクエストを行うためのYoutubeオブジェクト */
    private static YouTube youtube;

    /**
     * YouTubeオブジェクトで動画を検索します。
     * 検索結果があれば、ビデオの名前とサムネイルを出力します。
     *
     * @param args command line args.
     */
    public static void main(String[] args) {
        // プロパティファイルを読みます。
        Properties properties = new Properties();
        try {
            InputStream in = Search.class.getResourceAsStream("/" + PROPERTIES_FILENAME);
            properties.load(in);

        } catch (IOException e) {
            System.err.println("There was an error reading " + PROPERTIES_FILENAME + ": " + e.getCause()
                    + " : " + e.getMessage());
            System.exit(1);
        }

        try {
            /**
             * 1.Youtubeオブジェクトを生成します。
             * 　オブジェクトの生成にはHTTPトランスポート、JSONファクトリが必要です。
             * 　※HTTPリクエストの初期化クラスは必須ではありませんが、今回はサンプルを参考に指定しておきます。
             *
             * 2.続いてアプリケーション名を指定しておきます。
             *   アプリケーション名を指定すると各リクエストのUserAgentヘッダーに使用されます。
             *   指定していなければ、nullが設定されます。
             */
            youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, HTTP_REQUEST_INITIALIZER)
                    .setApplicationName("youtube-cmdline-search-sample").build();

            List<String> part = new ArrayList<>(Arrays.asList("id", "snippet"));
            YouTube.Search.List search = youtube.search().list(part);

            // プロパティファイルに定義したAPIキーを設定する
            String apiKey = properties.getProperty("youtube.apikey");
            search.setKey(apiKey);

            // ユーザーから検索キーワードを受け取り、設定します。
            String queryTerm = getInputQuery();
            search.setQ(queryTerm);

            // 動画のみを検索対象にします
            // もし、プレイリストやチャンネルも検索対象とする場合は「playlist」、「channel」なども追加します
            search.setType(new ArrayList<>(Arrays.asList("video")));

            // 返される情報を必要なフィールドのみに減らします
            // ※呼び出しをより効率的にする効果があるようです
            search.setFields("items(id/kind,id/videoId,snippet/title,snippet/thumbnails/default/url)");

            // 検索結果として取得してくる件数を指定します
            search.setMaxResults(NUMBER_OF_VIDEOS_RETURNED);

            // 検索を実行し、結果を取得します。
            SearchListResponse searchResponse = search.execute();
            List<SearchResult> searchResultList = searchResponse.getItems();

            // 検索結果があれば、内容を出力します。
            if (searchResultList != null) {
                prettyPrint(searchResultList.iterator(), queryTerm);
            }
        } catch (GoogleJsonResponseException e) {
            System.err.println("There was a service error: " + e.getDetails().getCode() + " : "
                    + e.getDetails().getMessage());
        } catch (IOException e) {
            System.err.println("There was an IO error: " + e.getCause() + " : " + e.getMessage());
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    /*
     * ターミナル経由でユーザーからのクエリターム (文字列) を返します。
     */
    private static String getInputQuery() throws IOException {

        String inputQuery = "";

        System.out.print("Please enter a search term: ");
        BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
        inputQuery = bReader.readLine();

        if (inputQuery.length() < 1) {
            // 何も入力しない場合は、デフォルトで「YouTube Developers Live」になります。
            inputQuery = "YouTube Developers Live";
        }
        return inputQuery;
    }

    /*
     * Iterator 内のすべての SearchResults を出力します。
     * 印刷された各行には、タイトル、ID、およびサムネイルが含まれます。
     *
     * @param iteratorSearchResults Iterator of SearchResults to print
     * @param query Search query (String)
     */
    private static void prettyPrint(Iterator<SearchResult> iteratorSearchResults, String query) {

        System.out.println("\n=============================================================");
        System.out.println(
                "   First " + NUMBER_OF_VIDEOS_RETURNED + " videos for search on \"" + query + "\".");
        System.out.println("=============================================================\n");

        if (!iteratorSearchResults.hasNext()) {
            System.out.println(" There aren't any results for your query.");
        }

        while (iteratorSearchResults.hasNext()) {

            SearchResult singleVideo = iteratorSearchResults.next();
            ResourceId rId = singleVideo.getId();

            // APIリソースのタイプがビデオであれば、内容を出力します。
            if (rId.getKind().equals("youtube#video")) {
                Thumbnail thumbnail = (Thumbnail)singleVideo.getSnippet().getThumbnails().get("default");

                System.out.println(" Video Id:" + rId.getVideoId());
                System.out.println(" Title: " + singleVideo.getSnippet().getTitle());
                System.out.println(" Thumbnail: " + thumbnail.getUrl());
                System.out.println("\n-------------------------------------------------------------\n");
            }
        }
    }
}
```

### 実行してみる
サンプルコードを実装出来たら動かしてみます。
コンソールから検索キーワードを求められるので、「ゲーム」と検索してみます。

```
> Task :Search.main()
Please enter a search term: ゲーム
```

以下のように動画情報が検索されました。

```
=============================================================
   First 25 videos for search on "ゲーム".
=============================================================

 Video Id:h4AVwjBDWQg
 Title: 【STEAM】10月リリースの高評価な最新作ゲーム10選
 Thumbnail: https://i.ytimg.com/vi/h4AVwjBDWQg/default.jpg

-------------------------------------------------------------

 Video Id:FnCt3Ezv0oM
 ・・・
```

# 参考文献
https://developers.google.com/youtube/v3/getting-started?hl=ja

https://developers.google.com/youtube/v3/quickstart/java?hl=ja

https://github.com/googleapis/google-api-java-client-services/tree/main/clients/google-api-services-youtube/v3

https://developers.google.com/resources/api-libraries/documentation/youtube/v3/java/latest/index.html