komura-c.log

komura-cのWeb技術、音、生活のメモの備忘ログ

CloudFunctionsからYouTubeAPIで特定チャンネル動画を取得する

作成 更新

先日9/27に行われたCAMPのハッカソンにてCloudFunctionsでYouTubeAPIを使った実装をしたので、知見を共有します。

Cloud Funtions for Firebaseとは

Cloud Functionsを見れば大体の内容は分かります。 大胆に言えば、Node.jsというJavaScript環境をサーバーレス(事前にサーバーを購入するのではなくGoogleの実行環境を利用する)で運用するものです。 Firebase Cloud Functionを作る Webhookで受け取ったデータでFirestoreを更新するを見ればどういう風に実装していけばいいかが大体掴めます。

YouTubeAPI

YouTubeここでフロント側での実装方法が分かります。HTTPリクエストというものを送るとJSONという形式でデータが返ってきます。

実装

まず、FunctionsからHTTPリクエストを送ろうとして詰まりました。Ninoさんのアドバイスでnode-fetchを使えばできると言われましたが、googleapisというGoogleAPIを使用するためのライブラリがあったのでそれを使うことにしました。 functionsディレクトリのコンソールでnpm i googleapisをしてインストールします。 その後最初に以下を記述します。

const { google } = require('googleapis');
google.options({
  headers: {
    "Referer": "https://xxxxx" // YouTubeAPIで制限をかけているリファラー
  },
});
const apiKey = functions.config().youtube.api_key;
const youtube = google.youtube({ version: 'v3', auth: apiKey });

googleapisのオプションでリファラーに記述された場所からリクエストを送っているよと指示しています。Cloud Functionsからはデフォルトでリファラーが送られないので、リファラーの記述がないとAPIの認証エラーになります。(ここも詰まりました)その後あらかじめ環境変数に入れたAPIキーを呼び出して、youtubeAPIで使うように引数に入れています。Firebase Cloud Functionsの環境設定を見ると分かります。 取得処理は以下になります。

async function getMoviesByChannelId(channelId: string, nextPageToken?: string) {
  youtube.search.list({ // ここの引数でAPIのオプションを指定している
    part: 'snippet',
    channelId,
    maxResults: 50, // 一回のリクエストでは最大50件しか返ってこない
    order: `viewCount`,
    type: `video`,
    videoEmbeddable: true,
    videoSyndicated: true,
    pageToken: nextPageToken ? nextPageToken : '',
  })
    .then(async (response: any) => {
      const resData: {
        "nextPageToken": string,
        "items": [] // ここに動画データの配列が入る
      } = response.data;
      const videos: [] = resData.items;
      await createVideos(videos, channelId);
      const nextToken = response.data?.nextPageToken; // 次リクエストのトークンがあれば入れる
      if (nextToken) {
        await getMoviesByChannelId(channelId, nextToken); // 次リクエストのトークンがあればもう一度実行する
      }
      return;
    })
    .catch((error: any) => {
      functions.logger.warn(error);
      return;
    });
}

今回の設計ではフロント側でAPIを使って保存したChannelIdを利用してチャンネル動画を保存する処理をしています。特に、nextTokenを用いて再帰(その関数自体を実行する)処理をするところがポイントです。createVideosという関数内でFirestoreに保存しています。

コード

youtube-room/functions/src/room-videos.function.ts こうリファクタリングした方がよいなどご指摘をお待ちしております。


> 一覧に戻る