🎉

AirtableAPI, YoutubeAPIと連動したVideoMemoAPPをNuxtJSで構築

2021/01/06に公開

1. アプリの概要

Youtube の PlayLis 等から動画のリストデータを作成し、これら動画に対して学んだことや、動画に対する評価(5 段階)を付与し一覧画面で確認できる、動画学習支援アプリケーション。また、一覧画面で登録したビデオとメモを記入した本数が表示され、学習の進捗も確認できます。

Github のレポジトリ

2. メイン機能概要

image1

左から、

  1. トップページ(再生リストの一覧)

    再生リスト名称と、それぞれの再生リスト毎のビデオの総本数と memo を記入したビデオの本数が表示されます。

  2. VideoList ページ(それぞれの再生リストの一覧)

    タイトル名称によるフィルタ機能とソート機能(rating、memo の有り無し、ビデオ公開日)があります。

  3. 個別 Video ページ

    YoutubeVideo を再生しながら、memo の記入と rating の入力ができます。

3. コードの説明

3.1. Airtable データの取得(vuex)

Airtable データベースとの連携については、以下の通り整理しました。<br />
データ取得側は、vuex から、Airtable の API エンドポイントにアクセスし、store に一旦データを格納する。
データ更新側は、各ページから、直接 Airtable の API エンドポイントにアクセスしデータの更新を行う。

今回の開発では、Nuxt の動的ルーティングと vuex の store のデータ更新のタイミングが合わず、ページが開かれたとき、ひとつ前に表示したページのデータが表示されてしまい、問題となりました。
ページの中のコードとしては、以下のようなイメージでした。

./sample.js
async mounted () {
 await '(1)ストアのfetch関数(action)をdispatchする処理'
 await '(2)ストアのデータを取得する処理(getters)'
}

このように async/await で非同期処理を記述することで、(1)の処理がおわってから、(2)の処理が始まるはずなので、問題ないとおもっていましたが、実際には、(1)の処理:action の dispatch が完了すると、vuex 内の store の更新を待たず、(2)の処理がはじまってしまい、問題となっていました。
暫定処置として、(2)の処理については、setTimeout を設定することにしましたが、これは本質的な対応ではないと思っていました。
これについては、Nuxt の asyncData メソッド、fetch メソッド、prefetch の設定等いろいろ試してみましたが、どれもうまく行きませんでした。最終的に、vuex の store を watch することが必要だと気づきました。

公式:Vuex.Store インスタンスメソッド - watch -

https://vuex.vuejs.org/ja/api/#watch

最終的なコードは以下のようになりました。
(個別 Video ページの例)

./pages/Video/_id.vue

  async mounted() {
    this.isLoading = true;

    const queryString = await this.$nuxt.$route.query.id.split("?");
    this.recordId = await queryString[0];
    this.tableId = await queryString[1];

    const dispatchInfo = {
      tableId: this.tableId,
      currentPage: "VideoPage",
      recordId: this.recordId
    };

    await this.$store.dispatch("fetchAirTableRecord", dispatchInfo);

    this.$store.watch(
      () => this.$store.getters["airTableRecord"],
      record => {
        const airtableRecord = this.$store.getters["airTableRecord"];
        this.rating = airtableRecord.rating;
        this.memoData = airtableRecord.memo;
        this.isLoading = false;
      }
    );
  },

AirtableAPI を使用する際に、今回気づいた注意点は以下になります。

  1. 値がないもの、checkbox が false の場合、フィールドそのものがないので注意が必要、fetch 関数内で、ブランクの値を付与し、undefined とならないようにする必要があります。

  2. Airtable フィールドの初期設定の頭文字が大文字なので、必要に応じて小文字にする。

  3. post、update 時にテーブル側の型と合わせないとエラー(ratiing 情報の扱いで数値型と文字型で不一致の際にエラーがでました)

<a id="markdown-32-個別-video-表示画面airtable-データの更新" name="32-個別-video-表示画面airtable-データの更新"></a>

3.2. 個別 Video 表示画面(Airtable データの更新)

データの更新は、個別 Video の表示とメモの入力が一体となった画面で行います。youtube 画面の表示と rating の ★ 印を表示・入力する為に、それぞれ以下のライブラリを使用しました。

データ更新のタイミングとしては、★rating については、クリックして rating を変更した場合は値は即時更新、メモデータについては、データを入力し、送信ボタンを押したときに更新するようにしました。

最終的なコードは以下のようになりました。
(メモデータ送信の submitMemo 関数)

./pages/Video/_id.vue
    submitMemo() {
      const app_id = process.env.AIRTABLE_APP_ID;
      const app_key = process.env.AIRTABLE_API_KEY;
      const tableId = this.tableId;

      const data = {
        records: [
          {
            id: this.recordId,
            fields: {
              memo: this.memoData
            }
          }
        ]
      };

      this.$axios
        .patch("https://api.airtable.com/v0/" + app_id + "/" + tableId, data, {
          headers: {
            Authorization: "Bearer " + app_key,
            "Content-Type": "application/json"
          }
        })
        .then(response => {
          const items = response.data.records;
          this.$toast.show("Item Saved");
        })
        .catch(error => {
          console.log(error);
        });
    }

3.3. ログイン認証機能(FirebaseAuth を使用)

今回のアプリは個人利用を想定していますので、ログイン認証機能については、FirebaseAuth を使用し、シンプルなものを実装しました。ナビゲーションガードは middleware に記述しました。

Login

./middleware/auth.js
import { auth } from "../plugins/firebase";

const middleware = ({ route, store, redirect }) => {
  auth().onAuthStateChanged((user) => {
    if (user) {
      return;
    } else if (!user && (route.path == "/SignUp" || route.path == "/SignUp/")) {
      return;
    } else if (!user && !(route.path == "/login" || route.path == "/login/")) {
      return redirect("/login");
    }
  });
};

export default middleware;

3.4. YoutubePlayList データ csv ダウンロード機能。

初期設定の為に必要な、YoutubePlayList データを取得する為に、YoutubeAPI 経由で、PlayList データを csv ダウンロードする機能を作成しました。入力フィールドに任意の PlayListId を入力すると、該当の csv データが出力されます。デフォルトでは、一度に 50 件までしかデータを取得できませんが、これを 100 件取得できるようにしました。

csvDownload

csv 出力用のコードは以下のリンクのものを参考にさせていただきました。

Vue のデータを CSV 形式でダウンロードする

4. 初期設定について

  1. ソースコードの.env ファイルに、Yotube,Airtable,Firebase に関する情報を設定します。
  2. Airtable の設定
    base テーブルを新規に作成し、PlayListIndex と各 VideoList のテーブルを設定します。
  3. VideoMemoApp の Settings の画面から、自分が取り込みたい、Youtube の PlaylistId を入力すると csv データが出力されます。この csv ファイルを Airtable の各 VideoList のテーブルにコピーします。

airtableSetting

5. 技術スタック

  • NuxtJs
  • Vuex
  • FirebaseAuth
  • Airtable(AirtableAPI)
  • YoutubeAPI
  • tailwindCSS

6. 主な使用ライブラリ

7.拡張

  • PlayList の登録は初回は一括して、csv ファイル経由で行いますが、VideoData の追加は、zappier と airtable 連携機能を使用し自動化できます。

  • 記入した Videomemo データは、Airtable の API を介して、Web サイトに展開することも可能です。

arch

Discussion