Bluesky APIでの投稿取得とSocial CiterのBluesky対応

product
概要

SNSの投稿引用整形サービスSocial Citer | GNU social JP」で分散SNSの投稿引用整形用サービスSocial Citerの公開を告知しました。その後、Misskey対応など細かい修正などを行っており、今回Bluesky APIに対応しました (Support Bluesky API · d083b090d8 – NotABug.org: Free code hosting)。Bluesky APIでの投稿取得方法の調査で試行錯誤したので、手順などをまとめておきます。

BlueskyでのMastodon著者Eugen Rochkoの偽アカウントの登場 | GNU social JP」でBlueskyでの投稿を複数回引用する必要が発生し、Blueskyのユーザーや話題が増えるにつれて、そろそろ対応が必要に思っていました。4月中旬の「アプリ: Blueskyの公式Androidアプリの公開 | GNU social JP」と「BlueskyのGo言語のバックエンド技術者の求人 | GNU social JP」の記事で再び引用が必要になったので、急遽対応しました。

画面イメージと引用のイメージは以下となります。

引用投稿にも対応しています。Blueskyでの投稿取得は現状認証が必須のため、ユーザー名とパスワードの入力欄をBlueskyのためだけに追加しました。

なお、Social Citerは基本的に私しか使わないので、入力の手間を省くためハンドルの入力欄は私のハンドルをデフォルトで入力しています。

手順

Social CiterでBlueskyに対応するにあたって、Bluesky APIでの投稿取得方法を調査したので今後のためにその情報を整理して記載しておきます。

記事: gihyo.jpでのBlueskyの記事2件の公開 | GNU social JP」で紹介した「開発視点から見る、新しい分散型SNS「Bluesky」とAT Protocolの可能性 | gihyo.jp」と以下の投稿を参考にしました。

<https://staging.bsky.app/profile/pfrazee.com/post/3jtqhia5mxe2z>の投稿を取得するとします。

Bluesky APIでは「XRPC | AT Protocol」のXRPCを使った通信で、「com.atproto.server | AT Protocol」などのLexiconの定義に沿った情報のやりとりを行います。

現状はほとんどの操作は認証が必要で、JWT認証でトークンを取得してから該当APIを呼び出す必要があります。また、投稿主の特定のためにハンドルからDIDも必要です。

以下の手順で該当投稿を取得します。

  1. JWTを取得
  2. 該当投稿ユーザーのDIDを取得
  3. 投稿取得

curlコマンドの例とともに記載します。

1. まず最初にJWTを以下のコマンドで取得します。

HANDLE=senooken.bsky.social
PW=password
curl -H "Content-Type:application/json" \
       "https://bsky.social/xrpc/com.atproto.server.createSession" \
       -d '{"identifier":"'$HANDLE'","password":"'$PW'"}'
{"did":"did:plc:p5tmg6syre5qqol2k3fvi7x6",
"handle":"senooken.bsky.social","email":"xxx@senooken.jp",
"accessJwt":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6ImNvbS5hdHByb3RvLmFjY2VzcyIsInN1YiI6ImRpZDpwbGM6cDV0bWc2c3lyZTVxcW9sMmszZnZpN3g2IiwiaWF0IjoxNjgxOTgyMDM5LCJleHAiOjE2ODE5ODkyMzl9.sd0ouBhB1oT3Z4FnRww9lhjwx0LNrnQ5z0WWokZqgb8",
"refreshJwt":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6ImNvbS5hdHByb3RvLnJlZnJlc2giLCJzdWIiOiJkaWQ6cGxjOnA1dG1nNnN5cmU1cXFvbDJrM2Z2aTd4NiIsImp0aSI6IjgvSWc5cXg3Wm5JMFBDWE1wRnllb1J1bWZEOHg0bWEwOFZmMEk4akdhVjAiLCJpYXQiOjE2ODE5ODIwMzksImV4cCI6MTY4OTc1ODAzOX0._dYrnMgj_5HzFIbreEgVY99dwWzUFds8uFjF39szqUc" }

自分のハンドル、パスワードをPOSTしてJWTを取得しています。応答のaccessJwtが投稿取得時に必要になります。

2. 続いて投稿ユーザーのDIDを取得します。これはJWTは不要です。

HANDLE=pfrazee.com
curl "https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=$HANDLE"
{"did":"did:plc:ragtjsm2j2vknwkz3zp4oxrd"}

3. 必要な情報が揃ったので投稿を取得します。

JWT="Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6ImNvbS5hdHByb3RvLmFjY2VzcyIsInN1YiI6ImRpZDpwbGM6cDV0bWc2c3lyZTVxcW9sMmszZnZpN3g2IiwiaWF0IjoxNjgxOTgyMDM5LCJleHAiOjE2ODE5ODkyMzl9.sd0ouBhB1oT3Z4FnRww9lhjwx0LNrnQ5z0WWokZqgb8","refreshJwt":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6ImNvbS5hdHByb3RvLnJlZnJlc2giLCJzdWIiOiJkaWQ6cGxjOnA1dG1nNnN5cmU1cXFvbDJrM2Z2aTd4NiIsImp0aSI6IjgvSWc5cXg3Wm5JMFBDWE1wRnllb1J1bWZEOHg0bWEwOFZmMEk4akdhVjAiLCJpYXQiOjE2ODE5ODIwMzksImV4cCI6MTY4OTc1ODAzOX0._dYrnMgj_5HzFIbreEgVY99dwWzUFds8uFjF39szqUc"
DID="did:plc:ragtjsm2j2vknwkz3zp4oxrd" URI=at://$DID/app.bsky.feed.post/3jtqhia5mxe2z curl -H "$JWT" "https://bsky.social/xrpc/app.bsky.feed.getPostThread?depth=0&uri=$URI"
{"thread":{"$type":"app.bsky.feed.defs#threadViewPost","post":{"uri":"at://did:plc:ragtjsm2j2vknwkz3zp4oxrd/app.bsky.feed.post/3jtqhia5mxe2z","cid":"bafyreibnoomzhzj7qhcphhdeufjur4egobufmhqpsbgowthhp4eomfzrt4","author":{"did":"did:plc:ragtjsm2j2vknwkz3zp4oxrd","handle":"pfrazee.com","displayName":"Paulinho Frazee✌️","avatar":"https://cdn.bsky.social/imgproxy/9Th8ZuZuEvfOEohn22gMWnj7f7Cj31bonAtJSTUMH0s/rs:fill:1000:1000:1:0/plain/bafkreiftyjy6k3t2yi5hh7gwin4p4hkuhp3kqxbzbbzr4gjsgotvcyk73e@jpeg","viewer":{"muted":false,"following":"at://did:plc:p5tmg6syre5qqol2k3fvi7x6/app.bsky.graph.follow/3jt5qj2jrqc2u"},"labels":[]},"record":{"text":"? Android is finally here! ?\n\nGoogle takes a while to update their search so here’s the direct link:\n\nhttps://play.google.com/store/apps/details?id=xyz.blueskyweb.app&hl=en_US","$type":"app.bsky.feed.post","embed":{"$type":"app.bsky.embed.external","external":{"uri":"https://play.google.com/store/apps/details?id=xyz.blueskyweb.app&hl=en_US","thumb":{"$type":"blob","ref":{"$link":"bafkreic6icsy4nbab2arkv7vwp67insqxx6ugnfucm4zvoudyec6hy6zfa"},"mimeType":"image/jpeg","size":739413},"title":"Bluesky - Apps on Google Play","description":"See what's next"}},"facets":[{"index":{"byteEnd":183,"byteStart":110},"features":[{"uri":"https://play.google.com/store/apps/details?id=xyz.blueskyweb.app&hl=en_US","$type":"app.bsky.richtext.facet#link"}]}],"createdAt":"2023-04-19T17:00:27.839Z"},"embed":{"$type":"app.bsky.embed.external#view","external":{"uri":"https://play.google.com/store/apps/details?id=xyz.blueskyweb.app&hl=en_US","title":"Bluesky - Apps on Google Play","description":"See what's next","thumb":"https://cdn.bsky.social/imgproxy/4PfzmMUos9qzbVFgncTua1Zg3qvHxKNZE13Jz5avjnc/rs:fit:1000:1000:1:0/plain/bafkreic6icsy4nbab2arkv7vwp67insqxx6ugnfucm4zvoudyec6hy6zfa@jpeg"}},"replyCount":117,"repostCount":411,"likeCount":772,"indexedAt":"2023-04-19T17:00:27.924Z","viewer":{"like":"at://did:plc:p5tmg6syre5qqol2k3fvi7x6/app.bsky.feed.like/3jtsculvsrb2o"},"labels":[]}}}

depth=0のパラメーターで返信ツリーを取得せず該当投稿のみを取得しています。

投稿パーマリンクのセグメントの末尾の文字列が投稿ID相当になるようなので、ここを抜粋してDIDと組み合わせたURIにしてuriパラメーターに指定しました。

結論

Social CiterのBluesky API対応と、その際に調査したBluesky APIでの投稿取得方法の紹介でした。

現状ほとんどの操作でJWT認証が必要で、やや使いにくいです。GET系APIは認証なしでも使えるとありがたいです。

JWT認証という私にととっては未知の謎の認証技術が登場して理解に時間がかかりましたが、APIを使う分には単にリクエストして応答を使用するだけなので簡単でした。

APIとしては、Misskey APIとことなり引用投稿が元投稿ときれいな入れ子になっていない、画像はHTTPのURIなのに、投稿URLはdidになっているなどやや汚くていまいちな部分を感じました。

Social CiterでBlueskyに対応できたことで、今後のBluesky関係の記事作成時の投稿引用が大幅に楽になります。

コメント

Copied title and URL