太陽がまぶしかったから

C'etait a cause du soleil.

note.com のフォロークリエーターリストと同期する記事更新RSSフィードを生成

note.com のフォローフィードを作りたい

 Google Alert の登録キーワードRSSフィードの応用として、note.com のフォローと同期するフィードを作成したい。note ではクリエーターをフォローすることができるが、自分が記事を読みに行くのはSlackでの通知ありきなので、RSS登録との二重管理が煩雑になっていた。

 これを解決するヒントして、はてなブログには「読者になる」で自分が購読リストに入れたユーザー全体でのフィードを生成する機能がある。このフィードさえ購読しておけば、はてなブログの読書登録との同期ができて心地が良い。

 note にも同じような機能があれば良いのだけど、見つからなかったので作ることとした。

note.com 非公式APIでクリエーターフォロー一覧を取得

 note にはクリエーターごとのRSSフィードが以下の形式で取得できる。

https://note.com/{creator_id}/rss

 ユーザーがフォローしているクリエーターIDの一覧が取得できればあとはよしなにフィードを集約すれば実現できそう。フォロークリエータ一覧は note の非公式APIからGET形式で取得できる。

https://note.com/api/v2/creators/{creator_id}/followings?page={page}

 フォロー情報はクリエータの公開情報という立て付けなので、特に認証も必要ないようだ。ページごとに取れるフォロークリエーターは12件であり、次のページない場合には data.isLastPagetrue となるため、そこまで取得する。

 あくまで画面表示のために使われているであろうAPIエンドポイントであるため、本来的には利用すべきではないのだろうけれども公式機能がないのだから仕方がない。何度も取得して負荷をかけないように取得結果をGCS上にストアして再利用することでフィード確認処理のたびに取得しないようにしている。

RSSの集約と ETag キャッシュ処理の実装

 フォロークリエーターリストが生成できたらあとはRSSフィードを取得するだけではあるが、毎回全てのユーザーに更新を確認しても処理負荷をかけてしまうのでいくつかの戦略によって処理量を削減している。

 要するに言えば成果物やバージョン識別子を保存しておいて、必要な場合のみ note.com に問い合わせるようにしている。また生成するフィードの本文情報などは先に紹介した Google Alert フィード変換と同様に Slack のカード生成ありきのものに縮減している。

Cloud Functions から Google Cloud Storage を使う

 各種ファイルについては GCS に保存して、必要に応じて使っている。処理実体が Cloud Functions であるためサービスアカウントの権限管理さえできていればプログラム内での認証処理が特に不要なのが便利。

    def __init__(
        self, bucket_name, blob_name, ttl=timedelta(hours=2), is_refresh=False
    ):
        self._blob = storage.Client().get_bucket(bucket_name).blob(blob_name)

...

    def download_as_string(self) -> str | None:
        if self.is_exists():
            return self._blob.download_as_text()
        return None

 この程度の簡単な記述で指定バケット内の指定ファイルをテキスト(str)として取り扱うことができる。ファイル内容の更新も blob.upload_from_string() だけだ。

One Fact in One Place のための仕組みを実現するための逆行

 以上までで、note.com のフォロークリエーターリストと同期する記事更新RSSフィードを生成できるようになったので、Slackに登録しておけばnote.comのフォローリストと同期して更新を検知することができ、Slackのフィード購読との二重管理をする必要がなくなる。

 情報管理をするには「One Fact in One Place」が大事だといわれている。ひとつの事実を複数の場所に置くから不整合が起きたり、N重のメンテナンスが必要になってしまうのだ。その一方で、非公式APIや複数フィードを何度も note 側に読みにいく訳にはいかず、自身のGCSにキャッシュさせることによる N Place への逆行と複雑性が発生しているのが難しい。

 昨今では、はてなブログから note に執筆場所を移すブロガーや経営者などが増えてきているように感じる。note 自身がはてなブログのようにフォローユーザーフィード生成を提供してくれればことが足りたのだけど、提供してくれないからこそ課題解決と学習の機会を得られたとも言える。欲を言えば有料記事かどうかのフラグがあるとありがたいのだけどフィードからは難しいようだ。