blog.komura-c.page

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 こうリファクタリングした方がよいなどご指摘をお待ちしております。


> 一覧に戻る