Kindle で購入した書籍をブクログへ自動で登録する
はじめに
いきなりですが、みなさん読書の管理ってどうしていますか?
僕は、ブクログ というサービスを使っています。以前は、読書メーター を使っていたんですが、ブクログは本に記載されている ISBN コードや Amazon の Asin コードから本を登録できる[1]ということを知って最近移行しました。
どうせなら自動化したいなと思い、調べてみました。すると同じことを考えた先人たちがいらっしゃったので参考にしつつやってみることにしました。当記事はその紹介です。
作ったもの
Kindle で書籍を購入した際に Amazon からメールが届きます。そのメールから使いたい Asin コードだけを抜き出して、購入した書籍をブクログに登録します。その際、処理のログをスプレッドシートへ登録します。
これらの処理は、TypeScript で書いていて GitHub でバージョン管理しています。デプロイは GitHub Actions を使って Google Apps Script へ自動で行い、Google Apps Script のトリガーで定期実行させます。
作ったものの全体像
ソースコードはこちら。
作成手順
以下ポイントだけピックアップします。
ローカルで Google Apps Script を使う
Amazon のメールアドレスとして登録しているのが Gmail なので、それを扱いやすい Google Apps Script ( 以下 GAS ) が選択肢として挙げられました。
また、Clasp を使うとローカルで GAS を扱うことができます。そのメリットとしては下記です。
- コードを Git 管理しやすくなる点
- Clasp は TypeScript をサポートしている点
- 好きなエディタを使うことができる点
まずは、Clasp CLI を導入します。
# Clasp をインストール
$ npm install -g @google/clasp
# 確認
$ clasp --version
# ブラウザが開くので、Google アカウントで認証します
$ clasp login
プロジェクトの作成
Clasp CLI を使って作成します。--type
オプションを使って同時にプロジェクトに紐づくスプレッドシートも作成します。
$ clasp create --title "kindle-booklog-sync" \
--type sheets \
--rootDir ./src
ローカルに appsscript.json
を含む雛形が作成されていれば OK です。
GAS で Gmail を検索する
実際に ./src
ディレクトリに TS ファイルを作成して書いていく訳ですが Google のサービスを扱う場合は GAS を使うと下記のように非常に簡単です。
interface GmailApp {
search(query: string): GmailThread[]
}
const searchEmail = (): GmailThread[] => {
return GmailApp.search("from:digital-no-reply@amazon.co.jp in:inbox")
}
ちなみに、メールの検索には実際に Kindle で書籍を購入した際に送られてくるメールアドレスを from に指定しています。
ブクログに Asin コードを使って書籍を登録する
ログインの処理などは必要ですが、今回は省略して実際に登録する処理だけピックアップしました。
UrlFetchApp.fetch()
というメソッドを使って HTTP のリクエストを送ることができます。返り値は HTTPResponse
で、ステータスコードやレスポンスボディを取得できます。
const uploadBook = (cookies: string[], asinList: string[]): HTTPResponse => {
const url = 'https://booklog.jp/input'
return UrlFetchApp.fetch(url, {
method: 'post',
headers: {
Cookie: cookies.join(';'),
Referer: url
},
payload: {
isbns: asinList.join("\n"),
category_id: 0, // なし
status: 4 // 積読
}
})
}
category_id
はブクログ上でのカテゴリです。事前に作っておいてその ID を指定しても良いですし、僕みたいに 0 とすると 未選択
になります。
status
は読書状況です。0: 未設定
, 1: 読みたい
, 2: いま読んでる
, 3: 読み終わった
となっているので、とりあえず購入したばかりなので 4: 積読
にしました。
結果をスプレッドシートに書き込む
上記の HTTP レスポンスをスプレッドシートに残しておきます。
getSheetByName()
メソッドの引数にはシートの名前を指定しました。事前に好きな名前にしておきましょう。
const log = (asin: string, text: string): void => {
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('log') // シート名を記載
.appendRow([new Date(), asin, text])
}
実行した後で見てみるとちゃんとデータが残っていました。
ブクログを確認
ブクログの方も確認してみると登録ができていました。良さげですね。
GitHub Actions でデプロイ
今回は git tag
をトリガーに実行されるスクリプトを作成しました。長くなってしまったのでコードの折りたたんでおきます。
env
セクションで使用している環境変数は事前に GitHub 上に登録しておく必要があります。
リポジトリ TOP
> Settings
> Secrets
で登録画面に行くことができます。
.github/workflows/deploy.yml
name: Deployment
on:
push:
tags:
- "v*"
jobs:
deploy:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: ['14.16.x']
env:
CLASP_ACCESS_TOKEN: ${{ secrets.CLASP_ACCESS_TOKEN }}
CLASP_CLIENT_ID: ${{ secrets.CLASP_CLIENT_ID }}
CLASP_CLIENT_SECRET: ${{ secrets.CLASP_CLIENT_SECRET }}
CLASP_EXPIRY_DATE: ${{ secrets.CLASP_EXPIRY_DATE }}
CLASP_ID_TOKEN: ${{ secrets.CLASP_ID_TOKEN }}
CLASP_REFRESH_TOKEN: ${{ secrets.CLASP_REFRESH_TOKEN }}
CLASP_SCRIPT_ID: ${{ secrets.CLASP_SCRIPT_ID }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup node
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- name: Set env
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache node modules
uses: actions/cache@v2
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-
- name: Create authentication file
run: |
echo $(cat <<-EOS
{
"token": {
"access_token": "${CLASP_ACCESS_TOKEN}",
"scope": "https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/script.webapp.deploy openid https://www.googleapis.com/auth/script.projects https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/service.management https://www.googleapis.com/auth/logging.read https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/script.deployments https://www.googleapis.com/auth/drive.metadata.readonly",
"token_type": "Bearer",
"id_token": "${CLASP_ID_TOKEN}",
"expiry_date": ${CLASP_EXPIRY_DATE},
"refresh_token": "${CLASP_REFRESH_TOKEN}"
},
"oauth2ClientSettings": {
"clientId": "${CLASP_CLIENT_ID}",
"clientSecret": "${CLASP_CLIENT_SECRET}",
"redirectUri": "http://localhost"
},
"isLocalCreds": false
}
EOS
) > ~/.clasprc.json
- name: Create clasp application file
run: |
echo $(cat <<-EOS
{
"scriptId": "${CLASP_SCRIPT_ID}",
"rootDir": "./src",
"fileExtension": "ts"
}
EOS
) > ./.clasp.json
- name: Get version
id: version
run: echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/}
- name: Deploy to GAS
run: npx @google/clasp push --force
- name: Add version
run: npx @google/clasp version ${{ steps.version.outputs.VERSION }}
GitHub Actions が正常に完了したら clasp open
と実行して完了しているか確認します。
トリガーを設定
GAS へのデプロイができたところで定期実行させるためのトリガーを設定します。左側のメニューの中からトリガーを選択肢、「トリガーを追加」で設定できます。僕は毎日実行にしておきました。
まとめ
これまで GAS はブラウザのエディタで書くことが多かったので、いつも使っているエディタを使えるのはエディタの機能をそのまま使えて効率がいいし、ストレスなく実装できました。また、なんといっても TypeScript で型定義ができる点は非常にいいですね。
また、GitHub 上で管理できる点はかなり大きいと感じました。(今回の内容はプライベートですが)チームで開発する際には必須になってくるのと、GitHub Actions を使えるというのが大きなメリットです。
読んでくださった方で、自分はこんな読書管理しているよというものがあればぜひ教えてください!
参考にさせていただいたサイト
Discussion