主にこの記事を参考にした。
Crosspost from Mastodon to Bluesky - Maurice Renck
RSSをフェッチして転送している形に近いけど、MastodonというかActivityPubプロトコルにはoutboxというjsonでの直近10件程度のポストを取得できる仕組みがある。公開アカウントならこれを定期的にフェッチしてbskyの公式APIで投稿すれば良い。
下準備として、bskyにログインして設定からアプリパスワードを作成しておく。
設定ファイル(.env)にMastodonのインスタンス、ID、bskyのハンドル、PDSサーバーのアドレス、アプリパスワードを設定しておく。
lastProcessedPostId.txtというファイルに、一番最後にクロスポスト投稿した時刻を保存しておくことで重複を避けているらしい。
改善の余地
元のコードでは、画像を含むポストは画像なしでそのまま転送、リプライは全て無視していた。この辺は一応治せるはず。
クオート記号のエスケープ
outboxにはHTMLタグがそのまま埋め込まれてるので、それを取り除く処理は書かれている。しかしクオート記号が"
に変換されてるのが処理されてない(このエスケープ、何…?)
ので、そのバグは修正した。
画像のアップロード(不完全)
bskyのAPIでは画像も4枚までアップロードできる。やってる人もいる。
Node.js (Typescript) で Bluesky に画像を自動投稿する Bot を作る (その1)Node.js - Qiita
ただし、画像のサイズは1MBまでの制限がある。Mastodonの方がこの制限はゆるいので、適当にスマホで撮った写真だと普通に2MBとか行ってたりする。ので、画像サイズを適当に縮小してから送る必要があるだろう。
…なのだが、試しに小さいサイズの画像でアップロードしてみてもなぜかエラーのレスポンスが返ってきてしまう。これはPDSをセルフホストしているせいのような気がする。
ので、今は諦めて画像のURLをoutboxから取得してそのURLをテキストとしてそのまま添付している。
自分へのリプライを取得(これも不完全)
他人へのリプライはともかく、自分でのリプライのツリーは結構使うので無視したくない。
もとのコードはitem.object.inReplyTo===null
のものだけを抜き出してたので、IDもチェックして自分相手だったら無視せず投稿することにした。
bskyのAPIで、リプライ先を指定した投稿もできる。ただそうすると、Mastodonでの投稿URLと、bskyでの投稿URLの対をどこかデータベースに保管しなくてはならない。これはだるいのでやめた。そもそも自分宛のリプライくらいなら普通の連投でもそこまで不自然ではあるまい。