GAS + Feedlyで担当アイドルを継続的にエゴサする

> 注意 : 加筆修正したものを [Zenn](https://zenn.dev/arrow2nd/articles/0955d0135b5b75) に投稿しています。

## きっかけ

**Twitterで [担当アイドル](https://idollist.idolmaster-official.jp/detail/20088) を検索してツイートを眺める**ということをよくするのですが、

「いちいちTwitter開いて検索するのめんどくさい...」
「普段 Feedly (RSSリーダ) をよく開くのでここで見れたら最高なのでは？？」

という気持ちになった結果

**『Twitterの検索結果をRSSフィード化して、Feedlyで読めるようにしよう！』**
と思ったのがきっかけです。

## 構成図的なもの

![構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/baa20626-cab2-9ed9-24cf-6e0616a50ccc.png)

## 準備

### 1. TwitterAPIのBearer Tokenを取得

Twitterの投稿を検索するのに必要です。

取得方法については、[公式ドキュメント](https://developer.twitter.com/ja/docs/authentication/oauth-2-0/bearer-tokens) をご参照ください。

### 2. ディレクトリを作成

```sh
mkdir gas-ego-search
cd gas-ego-search
```

### 3. claspをインストール

ブラウザからポチポチやっても良かったのですが、今回は [clasp](https://github.com/google/clasp) というGASのプロジェクトをローカルで管理できるCLIツールを利用しました。

npm もしくは yarn からインストールできます。

```sh
npm install -g @google/clasp
# or 
yarn global add @google/clasp
```

インストールができたら、Google アカウントでログインしておきます。

```sh
clasp login
```

### 4. Google Apps Script API を有効化

claspを使用するには Google Apps Script API を有効化する必要があります。

GASの管理画面の左下にある「設定」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/8c3c5f3a-2970-e017-2860-15bed02c0e03.png)

Google Apps Script APIの項目を「オン」にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/8069a756-9210-b35e-b32e-6ada1eeda59a.png)

これで clasp が使えるようになりました！🎉

## つくる！

### 1. プロジェクトを作成

早速 clasp を使ってプロジェクトを作成していきます。

```sh
clasp create gas-ego-search
? Create which script?
  standalone
  docs
❯ sheets # 今回はスプレッドシートを使いたいのでこれを選択
  slides
  forms
  webapp
  api
```

これで Enter を押すと、

```sh
? Create which script? sheets
Created new Google Sheet: https://drive.google.com/open?id=[ドキュメントID]
Created new Google Sheets Add-on script: https://script.google.com/d/[スクリプトID]/edit
Cloned 1 file.
└─ /path/to/gas-ego-search/appsscript.json
```

スプレッドシートとそれに紐づいたスクリプトが作成されます。
便利......:hatching_chick:

また、ここまでの操作でディレクトリ内は以下のようになります。

```
  .
  ├── .clasp.json
  └── appsscript.json
```

### 2. appsscript.json を編集

`clasp create` した際についてくる、GAS の実行環境に関する設定ファイルです。

今回は以下のように編集しました。
詳しい構造については [公式のドキュメント](https://developers.google.com/apps-script/manifest) をご覧ください。

```jsonc
{
  // タイムゾーンを東京に変更
  "timeZone": "Asia/Tokyo",
  // Webアプリとしての公開設定
  "webapp": {
    "access": "ANYONE_ANONYMOUS",
    "executeAs": "USER_DEPLOYING"
  },
  // 以降はそのまま
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}
```

### 3. スプレッドシートを編集

`Created new Google Sheet: ` の後に続く URL にアクセスして、スプレッドシートを開きます。

以下にように、エゴサしたいアイドルを列挙して保存しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/6db8670f-5b63-661a-a0b9-0e087e230228.png)

### 4. Bearer Token をプロパティに追加

Twitter の Bearer Token をハードコードしたくないので、プロパティに追加します。いわゆる環境変数です。

`clasp open` でスクリプトエディタを開いて、上部メニューの「ファイル」から「プロジェクトのプロパティ」を選択します。[^1]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/45aa4eb3-b0b2-bf16-3064-c94af2365b7b.png)

「スクリプトのプロパティ」内にある「行を追加」から追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/cdcb2f87-9dcd-c213-427e-a95fedd2715f.png)
ここでは `twitterToken` という名前にしました。

### 5. コードを書く

このままコードを追加していっても良いのですが、`rootDir` を変更して

```jsonc:.clasp.json
{
  "scriptId": "xxxxxxxxxxxxxxxxxxxx",
  "rootDir": "./src", // ここを変更
  "parentId": ["xxxxxxxxxxxxxxxxxxx"]
}
```

以下のようなディレクトリ構成にしました。

また、コードの見通しを良くするため、処理毎にファイルを分けました。

```
  .
  ├── .clasp.json
  └── /src
    ├── appsscript.json
    ├── createXML.js    # 検索結果からRSS(XML)を作成するやつ
    ├── main.js         # メインのやつ
    ├── sheets.js       # スプレッドシートから検索ワードを読込むやつ
    ├── template.html   # RSS(XML)のテンプレートファイル
    └── twitter.js      # Twitterで検索するやつ
```

（大した内容ではないのですが）簡単に全体の流れについて説明します。

```js:main.js
// プロパティを読み込む
const config = PropertiesService.getScriptProperties().getProperties()

function doGet() {
  // スプレッドシートから検索ワードを取得
  const searchWords = getSearchWordsFromSS()

  // ツイートを検索する
  const results = fetchSearchResults(config.twitterToken, searchWords)

  // 検索結果を整形する
  const items = createOembedItems(results)

  // テンプレートにデータを埋め込んで返す
  return createXML(items)
}
```

`doGet()` は公開したURLにアクセスがあった際に呼ばれる関数です。

ですので、アクセスがあったら

1. スプレッドシートから検索ワード（エゴサするアイドル名）を読込む
1. それぞれをTwitterで検索
1. 検索結果から必要な情報を抽出して整形
1. 検索結果をテンプレートファイルに埋め込む
1. 生成したRSS(XML)を返す

という流れで処理が行われます。

また、短期間に大量にアクセスされるとAPIの上限に達してしまうという問題がありますが、今回使う Feedly は更新間隔が **1時間に1回程度** とのことなので考慮していません。（よくない）

詳しくは以下のリポジトリにコードがありますので、ご参照ください...！

https://github.com/arrow2nd/gas-twitter-rss

push して反映します。

```sh
clasp push
? Manifest file has been updated. Do you want to push and overwrite? Yes
└─ src/appsscript.json
└─ src/createXML.js
└─ src/main.js
└─ src/sheets.js
└─ src/template.html
└─ src/twitter.js
Pushed 6 files.
```

### 6. Webアプリとして公開

`clasp open` でスクリプトエディタを開きます。

「公開」から「ウェブアプリケーションとして導入」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/4bc571dc-9e02-91ad-b93d-4cf88e1dc97d.png)

モーダルが開くので「更新」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/714f6ece-48df-74a2-41bd-bed049fc74c3.png)

許可がいるよ！って言われるので確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/b04e4346-488a-1988-3bbd-c7e9537dd43e.png)

別ウィンドウが開くので画面に沿って使用するGoogleアカウントを選択します。

こんな感じの警告がでてきますが、自分が書いたスクリプトなので、左下の「詳細」から「（安全ではないページ）に移動」を選択して先に進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/12999998-1676-bc42-f627-52a768d7b87b.png)

問題がなければ「許可」します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/32c12411-8ecc-1608-9213-7d02c283f169.png)

以上で公開できました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/230257df-918a-1504-fb10-ea9b5173adcc.png)

`Current web app URL:` 以下に表示されているURLにアクセスすると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/b9bd23e5-a9b6-6437-bfa2-42f5432bdd0c.png)

ちゃんと動いてそうです！いえー:v_tone1::v_tone1::v_tone1:

URL はこれから使用するのでコピーしておきます。

### 7. Feedlyに追加

[Feedly](https://feedly.com) を開いて、左のほうにある「＋」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/d9f041cd-488f-644b-2533-0231cd0cd595.png)

先ほどコピーした URL を貼り付けて Enter を押すと...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/f1e8ba7c-252c-0ed1-2ce8-6b3f630a9c2a.png)

でてきました！！（名前は気にしないでください）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/4898246c-a309-2832-590f-3e4ff2d477aa.png)

FOLLOW ボタンを押してフィードを追加すれば完了です！

## まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286055/ab19abc3-4ff2-a989-7245-bc59e42794a8.png)

見逃してしまっていた情報や、ファンアート、気になる考察などが見つかったりするので、とても重宝しています！

~~（担当のガシャが来ていて、自分が引けていないときは地獄の空間になりますが...）~~

また、最初はTypeScriptで開発していたのですが、うまくgsファイルに変換してくれず「ん〜〜〜」となっていたところ、[なにやら制限](https://github.com/google/clasp/blob/master/docs/typescript.md)があることを知りました。

こういうのは最初に目を通しておくべきですね......。気をつけます。

## 参考

- [Google Apps Scriptでお手軽RSS配信サービスを作る](https://www.infoscoop.org/blogjp/2014/11/27/gas-rss-service/)

[^1]: メニューが見当たらない場合、以前のUIに戻す必要があります。画面右上にあたりにある「以前のエディタを使用」をクリックしてください。