YouTube Data API v3 を使って再生リスト内で検索できるツールをつくってみる

# はじめに
YouTube Data API を用いて再生リストに入っている動画のみを検索できるツールでもつくろうかと思います。
Webツールとしてなので言語は PHP を使います。

## YouTube Data API を利用するには
YouTube Data APIを利用するにはYouTube Data API v3 を有効化する必要があるのでAPI KEYがない場合は以下のページに従ってください。(GCPですが、このAPIは無料です)

https://qiita.com/kaburankattara/items/240a457f79ade800a4fb

# YouTube Data API

### 再生リスト内の簡易的な動画情報を取得

https://developers.google.com/youtube/v3/docs/playlistItems/list?hl=ja

- パラメータ
    - key: APIキー
    - playlistId: 再生リストのID
    - part: 取得するデータの種類 (contentDetails, id, snippet, status)
    - maxResults: 取得最大数 (0-50まで)
    - pageToken: 前後ページトークン nextPageTokenやprevPageToken
- メソッド: GET
```
https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&key=(API_KEY)&playlistId=(再生リストのID)
```

### 動画情報を取得
https://developers.google.com/youtube/v3/docs/videos/list

- パラメータ
    - key: APIキー
    - id: 動画のID
    - part: 取得するデータの種類
- メソッド: GET

```
https://www.googleapis.com/youtube/v3/videos?part=snippet,statistics,status&key=(API_KEY)&id=(動画のID)
```

# PHP のcURL 関数を使う
```php
$api_url = "...";

$ch = curl_init(); // 初期化
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); // メソッドの指定
curl_setopt($ch, CURLOPT_URL, $api_url); // URLの指定
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 受け取ったレスポンスデータを返す
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // SSL証明書の検証をしない
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // SSL証明書とホストが一致するか確認
$res = json_decode(curl_exec($ch), true); // レスポンスデータをJSONから配列に
curl_close($ch); // 閉じる
```

# 再生リスト内の動画を検索するツールをつくってみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1015774/59f4b4ed-d494-49ab-7b29-96c75b9fe38b.png)

```php
<?php
$html = "";

if (isset($_GET['playlist']) && isset($_GET['q'])) {
    $playlistId = $_GET['playlist'];
    $word = $_GET['q'];
  
    $apiKey = getenv("API_KEY"); // 環境変数から取得

    // URLからIDを抽出、もともとIDである場合はそのまま
    if (preg_match('/(?:list=)([^&]+)/', $playlistId, $m))
        $playlistId = $m[1];
  
    $api_url = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&key=$apiKey&playlistId=$playlistId";

    $pageToken = ''; // 初回の場合は空にしておく、再生リストの次ページ用トークン

    while (true) {
        $ch = curl_init(); // 初期化
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); // メソッドの指定

        // URLの指定
        curl_setopt($ch, CURLOPT_URL, $api_url 
                    . (empty($pageToken) ? '' : '&pageToken=' . $pageToken)); 
      
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 受け取ったレスポンスデータを返す
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // SSL証明書の検証をしない
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); // SSL証明書とホストが一致するか確認
        $res = curl_exec($ch); // 実行してレスポンスデータを突っ込む
        curl_close($ch);

        $data = json_decode($res, true); // JSONから配列に (JSON形式で返ってくるので)
          
        if (isset($data['items'])) {
            if (empty($pageToken)) // 初回のみ
                $html .= "<h2>\"" . $word . "\" の検索結果</h2>\n";
          
            $found = false;
            foreach ($data['items'] as $item) {
                $title = $item['snippet']['title'];
                $id = $item['snippet']['resourceId']['videoId'];
    
                // キーワードがタイトルに含まれているか
                if (stripos($title, $word) !== false) {
                    $found = true;
                    $html .= '<p><a href="https://www.youtube.com/watch?v='. $id . '" target="_blank">' . $title . "</a></p>\n";
                }
            }
        } else {
            break;
        }

        if (isset($data['nextPageToken']) && $data['nextPageToken'] !== $pageToken) {
            $pageToken = $data['nextPageToken'];
        } else {
            break;
        }
    }
}
?>

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>YouTube再生リスト内検索ツール</title>
</head>
<body>
    <h1>YouTube再生リスト内検索ツール</h1>
    <?= $html ?>
    <form method="GET">
        <input type="text" name="playlist" placeholder="再生リストURLまたはID" size="80" value="<?= isset($_GET['playlist']) ? $_GET['playlist'] : '' ?>" required />
        <br /><br />
        <input type="text" name="q" placeholder="検索キーワード" value="<?= isset($_GET['q']) ? $_GET['q'] : '' ?>" required />
        <input type="submit" value="検索" />
    </form>
</body>
</html>
```

キャッシュ機構とかは作ってないので毎度実行するたびに時間がかかるので一度処理した再生リストはキャッシュとして保存しておくべきかもですね。

API側にもサーバー側にも負荷がかかるため、ぶっちゃけPHPじゃなくてJSでクライアント側の開発でもよかったかもしれません（笑）

## 50個よりも多くの動画を取得するには
一度に取得できる動画数は50個ですが、それより多く取得したいならばpageToken を使います。

レスポンスにあるjsonにはnextPageTokenが入っています。
つまり、二回目は pageTokenというパラメータにそのnextPageTokenを入れてあげるといいのです。