YouTube Data API v3を利用してプレイリストのインポート機能を実装する

YouTubeにはプレイリスト(再生リスト)のインポート機能がないので、YouTube Data API v3を利用して簡単なものを自作した。

プレイリストのインポート機能を実装するには、APIで挿入 (insert) 操作をリクエストする必要がある。

このAPIリクエストを実行するには、OAuth 2.0認証を行い、アプリケーション(今回の場合は自作インポート機能プログラム)によるユーザーアカウントへのアクセスが許可されなければならない。

また、このアクセス許可は、ユーザーのリソース操作全てを許可するわけではなく、スコープという仕組みを導入して許可する範囲を限定している。

プレイリストのインポート機能に必要な挿入 (insert) 操作を行う場合は、スコープ https://www.googleapis.com/auth/youtube が許可される必要がある。

OAuth 2.0認証のやり取りを行い、承認されたクライアントオブジェクトをセットアップするためのコードが下記になる。


require_once '/path/to/google-api-php-client/vendor/autoload.php';

require_once 'OAuthClient.php';

$CLIENT_ID = '_CLIENT_ID_';
$CLIENT_SECRET = '_CLIENT_SECRET_';
$REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob';
$TOKEN_FILENAME = "token.json";
$CODE = '_CODE_';

try
{
  $gclient = new Google_Client();
  $oauth = new OAuthClient($gclient, $CLIENT_ID, $CLIENT_SECRET, $REDIRECT_URI, $TOKEN_FILENAME, $CODE);
  $oauth->setScopes('https://www.googleapis.com/auth/youtube');
  $client = $oauth->getAuthorizedClient();
}
catch(Exception $e)
{
  switch($e->getCode())
  {
    case OAuthClient::EMPTY_CODE:
    case OAuthClient::INVALID_CODE:
      echo $e->getMessage() . "\n";
      echo $oauth->getAuthUrl() . "\n";
      exit;
    case OAuthClient::INVALID_TOKEN_FILE:
      echo $e->getMessage() . "\n";
      exit;
    default:
      throw $e;
  }
}

$youtube = new Google_Service_YouTube($client);

OAuth 2.0認証の一連の処理は OAuthClient クラスにまとめてある。このクラスの getAuthorizedClient() を呼べば、承認されたクライアントオブジェクトが返ってくる。詳細は前の記事で説明したので、それを参照のこと。
OAuth 2.0 認証で YouTube Data API v3 を利用する


ここからは本題のインポート機能について説明する。

インポート機能は次の3つの処理から成る。

  1. インポートファイルの読み込み
  2. プレイリスト作成
  3. プレイリストに動画を追加

まず、下記はインポートファイルの読み込みとプレイリストの作成を行う部分。


$importFileName = "import.tsv";

$videoIds = extractVideoIds($importFileName);

$playlistName = preg_replace('/^(.+)\.tsv$/', '$1', $importFileName);
echo "creating a playlist \"$playlistName\"...\n";

$playlistSnippet = new Google_Service_YouTube_PlaylistSnippet();
$playlistSnippet->setTitle($playlistName);
$playlistSnippet->setDescription("created with the YouTube Data API v3 [" . date('Y-m-d H:i:s') . "]");

$playlistStatus = new Google_Service_YouTube_PlaylistStatus();
$playlistStatus->setPrivacyStatus('private');

$youTubePlaylist = new Google_Service_YouTube_Playlist();
$youTubePlaylist->setSnippet($playlistSnippet);
$youTubePlaylist->setStatus($playlistStatus);

$playlistResponse = $youtube->playlists->insert('snippet,status', $youTubePlaylist, []);
$playlistId = $playlistResponse['id'];

echo "done.\n\n";


function extractVideoIds($filename)
{
  $videoIds = [];

  $file = file_get_contents($filename);

  if (!$file)
    exit("Error: Can't open file: $filename\n");

  echo "reading \"$filename\"...\n";

  foreach (str_getcsv($file, "\n") as $row)
  {
    if (empty($row))
      continue;

    $cols = str_getcsv($row, "\t");

    $videoId = preg_replace('|^https://www.youtube.com/watch\?v=(.+)$|', '$1', $cols[0]);
    $videoIds[] = $videoId;
  }

  echo "done.\n\n";

  return $videoIds;
}

インポートできるファイルは、下記のようなYouTubeの動画URLとタイトルが TSV(タブ区切り)形式で保存されたファイルを想定している。


YouTube動画URL1	動画タイトル1
YouTube動画URL2	動画タイトル2
YouTube動画URL3	動画タイトル3
...

このファイルを読み込んで動画IDだけ抽出する。

続いてプレイリストの作成では、まず、snippet プロパティと status プロパティの値を保持する PlaylistSnippetPlaylistStatus オブジェクトをそれぞれ作成する。

PlaylistSnippet オブジェクトの作成では、snippet プロパティ内の snippet.title プロパティと snippet.description(プレイリストの説明)の値を setTitle()setDescription() でそれぞれセットする。上記のコードの例では、title にはインポートファイルのファイル名、description には文字列 created with the YouTube Data API v3 とそれにタイムスタンプを付加したものをセットしている。

PlaylistStatus オブジェクトの作成では、status プロパティ内の status.privacyStatus プロパティの値をセットする。有効な値は、publicprivateunlisted の3つで、デフォルトは public となる。上記のコードの例では、private をセットし、作成するプレイリストは非公開のものとして設定している。

PlaylistSnippetPlaylistStatus オブジェクトを作成したら、それらを Playlist オブジェクト $youTubePlaylistsetSnippet()setStatus() でそれぞれセットする。そして、$youtube->playlists->insert('snippet,status', $youTubePlaylist, []) でAPIリクエストを行い、プレイリストの作成が完了する。insert() の引数 'snippet,status' は、書き込み操作対象となるプロパティを特定するものである。

APIレスポンスに作成されたプレイリストIDが含まれているのでそれを取得する。

次に、このIDを使って、プレイリストに動画をインポートしてプレイリストを完成させていく。


foreach ($videoIds as $i => $videoId)
{
  echo "$i: videoId: $videoId ";

  $resourceId = new Google_Service_YouTube_ResourceId();
  $resourceId->setVideoId($videoId);
  $resourceId->setKind('youtube#video');

  $playlistItemSnippet = new Google_Service_YouTube_PlaylistItemSnippet();
  $playlistItemSnippet->setPlaylistId($playlistId);
  $playlistItemSnippet->setResourceId($resourceId);

  $playlistItem = new Google_Service_YouTube_PlaylistItem();
  $playlistItem->setSnippet($playlistItemSnippet);
  $playlistItemResponse = $youtube->playlistItems->insert('snippet', $playlistItem, []);

  echo "inserted.\n";
}

echo "\ndone.\n";

プレイリストはプレイリストアイテムから構成され、インポートする動画一つ一つに対応するプレイリストアイテムを作成して、それらをプレイリストに挿入していくのが主な処理となる。

プレイリストアイテムの作成手順は前述のプレイリスト作成と同様で、プレイリストアイテムの snippet プロパティの値を保持する PlaylistItemSnippet オブジェクトを作成し、それを PlaylistItem オブジェクトの setSnippet() に渡してセットし、PlaylistItem オブジェクト $playlistItem をセットアップする。そして、$youtube->playlistItems->insert('snippet', $playlistItem, []) でAPIリクエストを行い、プレイリストにプレイリストアイテムを挿入し、動画一つのインポートが完了する。

違う点は、プレイリストアイテムとプレイリストの紐付け、また、プレイリストアイテムと動画IDを紐付けるために ResourceId オブジェクトを作成する必要があるというところ。

プレイリストアイテムとプレイリストの紐付けは、PlaylistItemSnippet オブジェクトの setPlaylistId() にプレイリストIDを渡して行う。

プレイリストアイテムと動画IDの紐付けは、ResourceId オブジェクトを作成し、setVideoId() で動画IDをセット、setKind() でリソースタイプをセットする。リソースタイプは動画の場合、youtube#video となる。そして、ResourceId オブジェクトを PlaylistItemSnippet オブジェクトの setResourceId() に渡し、プレイリストアイテムと動画IDが紐付けられる。