⚡ Twitterの検索/リストやRSSを一括でチェック & 既読管理できるツールをFirebaseで作った

お久しぶりです 🙌
以前 [Web ページをそのまま保存するツール] (https://qiita.com/yarnaimo/items/66f3b71077d15a22699d) を作った [@yarnaimo](https://twitter.com/yarnaimo) です。

みなさんは RSS などの情報収集にどのようなツールを使っていますか？

私は今まで Google Apps Script と Fusion Tables を使って RSS を Slack に流していたのですが、Fusion Tables が 12 月に消滅してしまうということで（？）この機会に Firebase や React などを使って新しく情報収集ツールを作ってみました。

## ✨ 作ったもの

> ![android-chrome-192x192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/5c047305-6f11-6082-b0e7-2097b99b9171.png)<br> **Sodafloat**<br>https://github.com/yarnaimo/sodafloat

![sodafloat-home-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/297216d6-5861-c096-7288-d1932969336d.gif)

Sodafloat は **Twitter と RSS の情報を一括でチェック & 既読管理**できるツールです！

**各自で Firebase プロジェクトを作成しデプロイ**していただく形になっています。

## 📌 Sodafloat の機能

-   Sodafloat は **Firebase** で動作します。**Twitter の検索クエリやリスト、RSS フィードの URL** などを登録しておくと **Cloud Functions** が自動的に巡回し、更新があれば **Firestore** に保存します。未読のツイートや記事は **Firebase Hosting** 上の Web ページでチェックできます。(Web ページは Next.js を使って Cloud Functions 経由で SSR しています)
-   Web ページのレイアウトは**マルチタブ**になっていて、 Twitter や RSS から取得した情報を任意のタブに表示できます。<br>各タブではすべての情報がフラットに表示されるのではなく、**各サイトや検索クエリごとに分かれたカード**で表示されます。
-   RSS の記事は複数選択してまとめて開くことができます。
-   各カードの**既読ボタンを押さないと既読にならない**ので、途中で別のタブに移動した場合などでも Slack のように意図せず既読になることがありません。
-   RSS を巡回する際には記事の **OGP タグ**も取得するので**サムネイル**が表示できます。
-   Twitter 検索機能はエゴサやパブサなどにも便利です。
-   **PWA** にも対応しています。

---

## 🚀 デプロイ方法

Sodafloat は各自で Firebase にデプロイしていただく形になっていますが、**個人で利用する範囲内であれば基本的に無料**で運用することができます。

### 1. Firebase プロジェクトの作成

まず Firebase プロジェクトとデータベースを作成します。これには Google アカウントが必要です。

-   プロジェクトの作成

    -   **[Firebase Console](https://console.firebase.google.com)** を開きます。
    -   **`プロジェクトを追加`** をクリックします。
    -   **`プロジェクト名`** とその下の **`プロジェクト ID`** を設定します。例えば ID を `project-id` にした場合、Web ページの URL が `https://project-id.web.app` のようになります。プロジェクト名はあとから変更できますが、**ID は変更できません**。
    -   Google アナリティクスは必要ないのでオフにして **`プロジェクトを作成`** をクリックします。しばらく待つとプロジェクトの作成が完了します。

-   データベースの作成
    -   プロジェクト画面の左にある **`Database`** を開きます。
    -   **`データベースの作成`** をクリックします。
    -   セキュリティルールは `本番環境で開始` を選択します。
    -   Firestore のロケーションを選択します。日本で使う場合、**`asia-northeast1`** (東京リージョン) が最も高速でおすすめです。

### 2. プランの変更・課金設定

Sodafloat は Cloud Functions で外部への通信を行うので、Firebase プロジェクトを **Blaze プラン**に切り替える必要があります。Blaze プランは従量課金制ですが、個人で利用する範囲内であればほぼ無料枠に収まると思います。

-   Blaze プランへのアップグレード

    -   プロジェクト画面の左上にある `アップグレード` をクリックします。
    -   `Blaze プラン` を選択します。
    -   請求先をまだ登録していない場合、次の画面で**カード情報などを入力し購入を確定**します。すでに登録している場合は **`購入`** をクリックすると Blaze プランへのアップグレードが完了します。

-   1 日あたりの費用制限の設定

    -   https://console.cloud.google.com/appengine/settings を開き、`Google Cloud Platform` のロゴの右にあるメニューから**作成したプロジェクトを選択**します。
    -   `アプリケーションの設定` の中の **`編集`** をクリックし、**1 日の使用量上限**を入力して保存します。とりあえず **`0 ドル`** で運用してみて無料枠に収まらなかった場合に増やすのがいいと思います。

-   予算アラートの設定
    -   費用制限の設定画面の左上のメニューから **`お支払い`** をクリックし、その中の **`予算とアラート`** を開いて **`予算の作成`** をクリックします。作成したプロジェクトを `プロジェクト` 欄で指定し、任意の金額やルールを指定します。

### 3. デプロイの準備 → デプロイ

Sodafloat のデプロイには **git, Node.js, yarn** が必要です。また `yarn global add firebase-tools` で **Firebase CLI** をインストールしておいてください。

-   Sodafloat の **GitHub リポジトリをローカルに clone** してディレクトリに移動し、設定ファイル用のディレクトリを作成します。

```sh
git clone https://github.com/yarnaimo/sodafloat.git
cd sodafloat
mkdir -p src/.config
```

-   yarn で依存関係をインストールします。時間がかかるので、待っている間に **Firebase にデプロイする手前**まで並行して進めてもらっても構いません。

```sh
yarn
```

-   Web アプリの設定

    -   プロジェクト画面の左上にある `歯車アイコン` → `プロジェクトの設定` を開きます。<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/09b76dde-b53b-0d72-5d63-e70c71addc47.png)
    -   `マイアプリ` の **`</>`** ボタンをクリックします。<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/7aab6d71-6ee5-7bb2-21e9-69ae2d626987.png)

    -   アプリのニックネームを設定し、Firebase Hosing のオプションにチェックを入れて `アプリを登録` します。このニックネームは**あとから変更できます。**
    -   **`(2)`** 以降の内容は行わず `次へ` を数回クリックしてください。
    -   すると先ほどの `マイアプリ` のところにアプリの情報が表示されるので、`Firebase SDK snippet` の中の **`構成`** をクリックします。
    -   右下のボタンで**スクリプトをコピー**します。
    -   コピーしたスクリプトの**先頭に `export`** を加えたものを `src/.config/firebase-web.ts` として保存します。

```src/.config/firebase-web.ts
export const firebaseConfig = {
  apiKey: "xxx",
  authDomain: "xxx",
  // 省略
  appId: "xxx"
};
```

-   以下のように `.firebaserc` ファイルを作成します。

```..firebaserc
{
  "projects": {
    "default": "ここにプロジェクト ID を入力"
  }
}
```

-   **Firebase CLI で Google アカウントにログイン**し、**Firebase にデプロイ**します。

```sh
firebase login
yarn deploy
```

`✔ Deploy complete!` と表示されたらデプロイ完了です！！

### 4. アプリの初期設定

最後にアプリの初期設定を行います。

-   🔒 ログイン・管理者の設定

    -   プロジェクト画面の左にある **`Authentication`** を開き、**`ログイン方法`** をクリックします。
    -   **`Google`** をクリックし、Google ログインを有効にして保存します。
    -   次の URL の `project-id` の部分を**プロジェクト ID** に置き換えて**別タブ**で開き、Google アカウントで**アプリにログイン**します。 <br>`https://project-id.web.app/login`
    -   **`ログイン方法`** の画面に戻り、隣にある **`ユーザー`** をクリックします。するとログインしたユーザーが表示されるはずなので、右のボタンで **UID をコピー**します。
    -   左にある **`Database`** を開き、**`コレクションを開始`** をクリックします。
    -   コレクション ID を **`admin`** にして次に進みます。
    -   ドキュメント ID 欄に先ほどコピーした **UID** を貼り付け、フィールドは空のまま保存します。
    -   Web ページに戻りリロードします。

    以上で、**`admin` に保存された UID のユーザーのみ**がデータベースにアクセスできるようになりました :shield:

-   Twitter アクセストークンの設定

    -   Twitter から情報を取得したい場合は Twitter API の**アクセストークン**を Firestore に保存する必要があります。
    -   **`コレクションを開始`** をクリックし、コレクション ID に **`twitterAccounts`**、ドキュメント ID に **`default`** を指定します。ドキュメントには以下のフィールドを追加し、Twitter のトークンなどをそれぞれ入力して保存してください。

        -   consumerKey
        -   consumerSecret
        -   token
        -   tokenSecret
        -   lists **(空の array)**

        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/671559b9-3848-9f25-753a-8c294188db27.png)

        :warning: `array` を選択すると 0 番目のアイテムが追加されますが、**右のボタンで削除**して空の配列にしてください。

        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/dc6d0157-e0b4-384e-ed71-6326bd05d331.png)

-   タイムライン (タブ) とソースの追加
    -   Web ページの右上の **`+`** をクリックするとタイムライン (タブ) が追加できます。アイコンは **[Material Design Icons](https://materialdesignicons.com/)** から選べます。ここでは試しに名前を `Tech`、アイコンを `cellphone-link` にして保存してみます。<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/b24b0c8f-78b9-d2e3-b52b-576f189d5780.png)
    -   すると Tech タブが表示されたと思います。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/3de0f1f7-bff4-0729-d993-c12b5ab9b3eb.png)
    -   次に左上のロゴをクリックして **`Feed ソースの一覧`** を開きます。
    -   **`Feed ソースを追加`** をクリックし、 RSS フィードの URL と保存先タイムラインを入力して保存します。(この例は GIGAZINE です)<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/52ff9e80-2a48-1bda-9f1c-7ca96af8d131.png)
    -   しばらく (最大で 1 時間) 待つとタイムラインに記事の一覧が表示されます。記事を開きたいときは、選択状態にしてから右上の **`開く`** でまとめて開きます。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/68c1a37d-6b19-3682-7e01-72885b3ea954.png)
    -   **`すべて既読`** をクリックするとそのカード内の記事を既読にできます。

    Twitter の検索/リストも `Tweet ソースの一覧` から同じように追加できます。

Web ページは Cloud Functions 経由で表示していますが、Cloud Functions は一定時間アクセスがないとスリープ状態になるようなので Google Apps Script か https://cron-job.org 辺りで定期的に起こすのが良いでしょう。

---

## 技術的な話

-   言語はすべて **TypeScript** で書いていて Web フレームワークは **React / Next.js** を使っています。データ自体を SSR しているわけではないのでパフォーマンス面では Next.js を使うメリットは少ないですが、ディレクトリにファイルを置くだけでいい感じにルーティングしてくれたり Babel の設定が楽だったりするので採用しました。ちなみにこちらは宗教戦争の画像です。<br>![20190824-204518.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83774/6a88b814-99b2-3782-c7d3-a9d4bd953657.png)
-   UI には **[RMWC](rmwc.io)** (React Material Web Components)、CSS-in-JS は **[Emotion](emotion.sh)** を使っています。
-   Firestore のデータの操作には自作の **[BlueSpark](https://qiita.com/yarnaimo/items/fb98e126db34fbc04e88)** というライブラリを使っています。
-   開発期間は 1 ヶ月ぐらいです。
-   Sodafloat という名前は Search と Feed からきています。[^soda]

[^soda]: 某コンテンツのクリームソーダも関係してます

## まとめ

Sodafloat を使うと Twitter や RSS の情報を効率的に収集することができます。ぜひ使ってみてください！！

---

- Twitter - [@yarnaimo](https://twitter.com/yarnaimo)
- Github - [@yarnaimo](https://github.com/yarnaimo)