💙

bluesky_cliでコマンドラインから簡単にBluesky SocialのAPIを叩く

2023/04/04に公開

概要

こんにちは、真也です。

今日は私が開発保守しているCLIツールの「bluesky_cli」を紹介します。

https://github.com/myConsciousness/atproto.dart/tree/main/packages/bluesky_cli

https://pub.dev/packages/bluesky_cli

Dart言語製のツールですが、一度インストールしてしまえばプラットフォームに依存せず実行が可能ですので、Bluesky SocialのAPIをコマンドラインから叩いてみたい方は是非使ってみてください。

そもそも「Bluesky Socialとは何?」という方は、以下の記事を参考にしてください。簡単に説明すると、Twitterと瓜二つの分散型SNSです。

https://zenn.dev/kato_shinya/articles/lets-try-bluesky-social

前提

先にも簡単に触れましたが、今回紹介するbluesky_cliをインストールするためには、まずDart言語がPCにインストールされている必要があります。

Dart言語のインストールについては任意の方法でしていただいて構いませんが、以下のようにHomebrewのコマンドを使用すると簡単にインストールできます。

brew install dart-sdk

または、以下のようなWebページを参考にしてください。

https://dart.dev/get-dart

bluesky_cliのインストール

Dart言語だけインストールできたら、bluesky_cliをインストールするのはとても簡単です。

次のコマンドを任意のディレクトリで実行してください。

dart pub global activate bluesky_cli

以下のような出力を確認できれば成功です。

katoshinya@Katos-MacBook-Pro ~ % dart pub global activate bluesky_cli
+ ansi_styles 0.3.2+1s... (1.0s)
+ args 2.4.0
+ async 2.11.0
+ at_identifier 0.0.3
+ at_uri 0.0.3
+ bluesky_cli 0.0.5
+ cli_launcher 0.3.1
+ cli_util 0.3.5 (0.4.0 available)
+ collection 1.17.1
+ freezed_annotation 2.2.0
+ http 0.13.5
+ http_parser 4.0.2
+ json_annotation 4.8.0
+ meta 1.9.1
+ nsid 0.0.3
+ path 1.8.3
+ source_span 1.9.1
+ string_scanner 1.2.0
+ term_glyph 1.2.1
+ typed_data 1.3.1
+ xrpc 0.0.6
+ yaml 3.1.1
Building package executables... (1.0s)
Built bluesky_cli:bsky.
Installed executable bsky.
Activated bluesky_cli 0.0.5.

dart pub global activateでインストールされたDartプログラムはインストールした際にコンパイルされるため、起動がとても速くプラットフォームに依存せず実行が可能です。

https://qiita.com/takutaro/items/79d5cfe51138e45060c8

bluesky_cliを使ってみる

bluesky_cliがインストールできたら、実際に使ってみましょう。

サポートしているコマンド一覧

まず、bluesky_cliでサポートしているコマンドは以下のとおりです。
以下の表を見ていただければわかるのですが、既にほぼ全てのエンドポイントをサポートしています。

Usage: bsky <command> [arguments]

Global options:
-h, --help        Print this usage information.
    --identifier  Handle or email address for authentication.
                  (defaults to environment variable "BLUESKY_IDENTIFIER")
    --password    Bluesky password for authentication.
                  (defaults to environment variable "BLUESKY_PASSWORD")
    --service     Name of the service sending the request. Defaults to "bsky.social".
    --pretty      Enable to output JSON in pretty format.
    --status      Enable to output status code and reason phrase.
    --request     Enable to output request method and URI.
    --verbose     Enable verbose logging.

Available commands:
  actors-typeahead     Show the typeahead for actors.
  delete               Delete a specific contents from repository.
  feed                 Show the feed of specific actor.
  follow               Follow an user.
  followers            Show the followers.
  follows              Show the following users.
  like                 Like a specific post.
  likes                Show the likes of specific post.
  mute                 Mute an user.
  mutes                Show the muted users.
  notification-count   Show the count of notification of authenticated user.
  notifications        Show the notifications of authenticated user.
  popular              Show the popular contents.
  post                 Post to Bluesky Social.
  profile              Show the profile of specific user.
  profiles             Show the profiles of specific users.
  repost               Repost a specific post.
  reposted-by          Show the actors reposted specific post.
  search-actors        Search the actors based on term.
  seen-notifications   Update all notifications to read.
  suggestions          Show the actor suggestions.
  thread               Show the thread of specific post.
  timeline             Show the timeline of authenticated user.
  unmute               Unmute an user.

Run "bsky help <command>" for more information about a command.

認証情報の設定

Bluesky SocialのAPIを使用するためには認証情報の設定が必要です。

例えば以下のように実行するコマンドに認証情報を渡すことができます。

bsky timeline --identifier=shinyakato.dev --pasword=xxxxxxxx

Bluesky SocialではまだOAuth認証がサポートされていないため、現在使用できる認証情報はBluesky Socialへログインする際のハンドルまたはメールアドレスパスワードです。ハンドルまたはメールアドレスidentifierオプションに設定し、パスワードpasswordオプションに設定してください。

ただ、コマンドを叩くたびに認証情報を渡すのは面倒ですよね?

そんな方のためにbluesky_cliでは環境変数から認証情報を渡せる仕組みを提供しています。以下の環境変数に認証情報を設定してください。

環境変数 対応するオプション
BLUESKY_IDENTIFIER identifier
BLUESKY_PASSWORD password

例えば.zprofileだと次のように環境変数を設定します。

export BLUESKY_IDENTIFIER=shinyakato.dev
export BLUESKY_PASSWORD=xxxxxxxx

上記の環境変数が反映されると、次のようにコマンドを実行することができます。

bsky timeline

簡単ですね。

ポストを投稿してみる

Bluesky Socialへポストを投稿するためには、postコマンドを使用できます。

bsky post --text="Hello, Bluesky"

通信が成功すると以下のようにレスポンス情報が出力されます。

{"uri":"at://did:plc:iijrtk7ocored6zuziwmqq3c/app.bsky.feed.post/3jsjhoencus2n","cid":"bafyreibithakaywd6irbdx3oonf3xo367rds2gdwyhpqk6tzugyvvdpiru"}

投稿したポストを削除してみる

先に投稿したポストを削除してみましょう。

ポストの削除を行うためにはdeleteコマンドを使用できます。必須オプションのuriには、先にポストを投稿した際に取得したレスポンスに設定されたuriフィールドの値を設定してください。例えば、先の例だとat://did:plc:iijrtk7ocored6zuziwmqq3c/app.bsky.feed.post/3jsjhoencus2nです。

bsky delete --uri=at://did:plc:iijrtk7ocored6zuziwmqq3c/app.bsky.feed.post/3jsjhoencus2n

また、今回は投稿したポストの削除をするためにdeleteコマンドを使用しましたが、ポストの他にもlikeコマンドやrepostコマンドで作成したLikeやRepostもこのdeleteコマンドで同じように削除できます。なぜこれらのコンテンツをURIだけで判別できるかというと、URI中にコンテンツの発生源があるためです。

例えば、先に使用したURIであるat://did:plc:iijrtk7ocored6zuziwmqq3c/app.bsky.feed.post/3jsjhoencus2nには、app.bsky.feed.postというコレクションの中の3jsjhoencus2nというIDに紐づくデータという情報があります。Likeであればこのコレクション名がapp.bsky.feed.likeになり、Repostであればapp.bsky.feed.repostといったような感じです。

こうした共通的な規格があるため、特定のコンテンツを削除する際には基本的にdeleteコマンドにURIを渡すだけで可能です。

タイムラインを取得してみる

Bluesky Socialのタイムラインを取得するためには、timelineコマンドを使用できます。

timelineコマンドは追加のオプション無しでも使用できるのですが、データ量が多いため今回はlimitオプションを使用して実行してみます。

bsky timeline --limit=2
{"feed":[{"post":{"uri":"at://did:plc:vnzkv2glj4v4d6afdnw2fhzj/app.bsky.feed.post/3jsjhqjwpvs2n","cid":"bafyreibeypqge5ododmi6re25rsr7hhpicippe5uu2nnacl4ewoh7zoj3m","author":{"did":"did:plc:vnzkv2glj4v4d6afdnw2fhzj","handle":"alexmedick.com","displayName":"Alex Medick","avatar":"https://cdn.bsky.social/imgproxy/8gYBe18Nk9nAjRZ_Hr4D-PaTIHSqQcFRHJX9fZCPXZo/rs:fill:1000:1000:1:0/plain/bafkreih32nsm5znowuax4xxoip4xqotlyurid4zmqic672rb4e3thr5yvu@jpeg","viewer":{"muted":false,"following":"at://did:plc:iijrtk7ocored6zuziwmqq3c/app.bsky.graph.follow/3jrkseh7mdk22"}},"record":{"text":"peace, love, and punk rock 🤙","$type":"app.bsky.feed.post","createdAt":"2023-04-04T04:51:16.609Z"},"replyCount":0,"repostCount":0,"likeCount":0,"indexedAt":"2023-04-04T04:51:16.827Z","viewer":{}}},{"post":{"uri":"at://did:plc:j5jithq57v6uw5hctknexohb/app.bsky.feed.post/3jsjhppdwd22y","cid":"bafyreie6jrc5fj3ajbjkrmk3ykwuis64vizyvle6c7jewxgorl43gm5msa","author":{"did":"did:plc:j5jithq57v6uw5hctknexohb","handle":"jojo.bsky.social","displayName":"ジョジョ","avatar":"https://cdn.bsky.social/imgproxy/wjqT1Wi1utlX8hwKu2UqHaun90cS_ObMImzZm7Ei38s/rs:fill:1000:1000:1:0/plain/bafkreieomnqie5uwzkasmosrnfeypjlhrxsca66tzi4rqeiilq3vw3d5lu@jpeg","viewer":{"muted":false,"following":"at://did:plc:iijrtk7ocored6zuziwmqq3c/app.bsky.graph.follow/3jrkwk2xsec2o","followedBy":"at://did:plc:j5jithq57v6uw5hctknexohb/app.bsky.graph.follow/3jrkw3eaf2s2d"}},"record":{"text":"今日の午後に期末評価のミーティングがあるけどまだ何の準備もしてない。ドイツ人並みにアピールすんの苦手だから嫌なんだよなー。","$type":"app.bsky.feed.post","createdAt":"2023-04-04T04:50:48.845Z"},"replyCount":0,"repostCount":0,"likeCount":0,"indexedAt":"2023-04-04T04:50:48.948Z","viewer":{}}}],"cursor":"1680583848948::bafyreie6jrc5fj3ajbjkrmk3ykwuis64vizyvle6c7jewxgorl43gm5msa"}

また、timelineコマンドのようにlimitオプションを指定できるエンドポイントでは、cursorオプションを使用することでページングが可能です。上記のtimelineコマンドのレスポンスを見ていただくと"cursor"フィールドがあると思いますが、このフィールドの値を次のように使用します。

bsky timeline --limit=2 --cursor=1680583848948::bafyreie6jrc5fj3ajbjkrmk3ykwuis64vizyvle6c7jewxgorl43gm5msa

そうすると、先のページに続くタイムラインを取得できます。

{"feed":[{"post":{"uri":"at://did:plc:srdu2w3qc3aqh2ovez4rvql4/app.bsky.feed.post/3jsjhxbttpc2x","cid":"bafyreianxuwohpvmyap5tlak5w5e6kiqn6mlrbllib6idrxzxbhepawdri","author":{"did":"did:plc:srdu2w3qc3aqh2ovez4rvql4","handle":"blackrabbit.bsky.social","displayName":"inle","avatar":"https://cdn.bsky.social/imgproxy/NC5qYA2ka8AktHS2TwtXwZvNRPsdJ0H0_V9_S9XzcmQ/rs:fill:1000:1000:1:0/plain/bafkreia2dv3zqlbbkiudzl6hdd3lxvbmmg3pmsejng4hp3ncx2xsjm24ca@jpeg","viewer":{"muted":false,"following":"at://did:plc:iijrtk7ocored6zuziwmqq3c/app.bsky.graph.follow/3jrmr7manvk2r"}},"record":{"text":"이제 인용도 됩니다!","$type":"app.bsky.feed.post","embed":{"$type":"app.bsky.embed.record","record":{"cid":"bafyreiem2wuafijlgzue3s7mqqz6mwlxtxszopuoinzuv32wdjgjom5awu","uri":"at://did:plc:m3ypzsr5qa7z3adodk4hp7f2/app.bsky.feed.post/3jsjgsaj2kc27"}},"createdAt":"2023-04-04T04:55:02.805Z"},"embed":{"$type":"app.bsky.embed.record#view","record":{"$type":"app.bsky.embed.record#viewRecord","uri":"at://did:plc:m3ypzsr5qa7z3adodk4hp7f2/app.bsky.feed.post/3jsjgsaj2kc27","cid":"bafyreiem2wuafijlgzue3s7mqqz6mwlxtxszopuoinzuv32wdjgjom5awu","author":{"did":"did:plc:m3ypzsr5qa7z3adodk4hp7f2","handle":"iksalkkun.bsky.social","displayName":"익살꾼","avatar":"https://cdn.bsky.social/imgproxy/736xpp9qcqpPA_Di2sTc14x-WqXRyKelSvrKGDkAwGg/rs:fill:1000:1000:1:0/plain/bafkreibrofta34acszjvscsnscdyb5j5z4ndiauifgiom7dkm7sof4wcxm@jpeg","viewer":{"muted":false,"following":"at://did:plc:iijrtk7ocored6zuziwmqq3c/app.bsky.graph.follow/3jrmr7lb35s22","followedBy":"at://did:plc:m3ypzsr5qa7z3adodk4hp7f2/app.bsky.graph.follow/3jsjgkpd3ws27"}},"value":{"text":"검색이 완전 잘 되진 않네 근데 검색 있으니까 완전 트위터다","$type":"app.bsky.feed.post","createdAt":"2023-04-04T04:34:20.161Z"},"embeds":[],"indexedAt":"2023-04-04T04:34:20.309Z"}},"replyCount":0,"repostCount":0,"likeCount":0,"indexedAt":"2023-04-04T04:55:03.225Z","viewer":{}}},{"post":{"uri":"at://did:plc:vok247eewjmbmo3kxaizct2i/app.bsky.feed.post/3jsjhwizhrs2x","cid":"bafyreicvlbwjjxedc4j7iffnad5macs3vlqmxcvwworpoik2ctepquwsru","author":{"did":"did:plc:vok247eewjmbmo3kxaizct2i","handle":"baiser.bsky.social","displayName":"baiser","avatar":"https://cdn.bsky.social/imgproxy/FUFsResb2OivchlouMCXu-41-kRZlN2MhMLPt1n4NI4/rs:fill:1000:1000:1:0/plain/bafkreicrwuidebqva6wpm6sfc6ie4ajywbbjxr6ti27im7wrbiybck4xtm@jpeg","viewer":{"muted":false,"following":"at://did:plc:iijrtk7ocored6zuziwmqq3c/app.bsky.graph.follow/3jqk6a7hyik2s","followedBy":"at://did:plc:vok247eewjmbmo3kxaizct2i/app.bsky.graph.follow/3jqk72ccmns2y"}},"record":{"text":"The Blueからいろいろしてみています。ログアウトはどこでするのかな?⭐︎","$type":"app.bsky.feed.post","createdAt":"2023-04-04T04:54:36.257Z"},"replyCount":0,"repostCount":0,"likeCount":0,"indexedAt":"2023-04-04T04:54:37.195Z","viewer":{}}}],"cursor":"1680584077195::bafyreicvlbwjjxedc4j7iffnad5macs3vlqmxcvwworpoik2ctepquwsru"}

レスポンスを整形する

コマンドを実行した際に出力されるJSONを整形した状態で出力することもできます。

以下のようにprettyオプションを指定してください。

bsky profile --actor=shinyakato.dev --pretty
{
    "did": "did:plc:iijrtk7ocored6zuziwmqq3c",
    "handle": "shinyakato.dev",
    "displayName": "Shinya Kato 🤯",
    "description": "Dart/Flutter & atproto enthusiast\nContrib. bluesky-social/atproto\n\nThe author of many OSS packages for Dart/Flutter\n\nDeveloping Bluesky related packages 👇\nhttps://github.com/myConsciousness/atproto.dart\n\nGitHub: https://github.com/myConsciousness",
    "avatar": "https://cdn.bsky.social/imgproxy/JF97YphLyIEWfq4KJNO_ZCYm9v_zNcRj7sSB8UZrRBw/rs:fill:1000:1000:1:0/plain/bafkreidqn4z6ocv5snxuqguarboozqdusam2tehccnu23yab7g2sgv64dq@jpeg",
    "banner": "https://cdn.bsky.social/imgproxy/0ijMnNxGs3aYg9Xsb5YkfehBkZo2WRJReLgMtljXPM0/rs:fill:3000:1000:1:0/plain/bafkreiaz67sqpaacxjtbj7texvnz5tlnfpthman4kvciymxg2jc2vayd4m@jpeg",
    "followsCount": 3252,
    "followersCount": 410,
    "postsCount": 805,
    "indexedAt": "2023-03-25T14:57:25.791Z",
    "viewer": {
        "muted": false
    }
}

ステータスコードとリクエストURLを表示する

初期状態では非表示になっていますが、オプションを指定することでレスポンスを取得した際のステータスコードや、送信したリクエストのURL情報などを表示することができます。

ステータスコードを表示するためにはstatusオプションを、リクエストURLを表示するためにはrequestオプションを指定してください。

bsky profile --actor=shinyakato.dev --status --request
200 OK
GET https://bsky.social/xrpc/app.bsky.actor.getProfile?actor=shinyakato.dev
{"did":"did:plc:iijrtk7ocored6zuziwmqq3c","handle":"shinyakato.dev","displayName":"Shinya Kato 🤯","description":"Dart/Flutter & atproto enthusiast\nContrib. bluesky-social/atproto\n\nThe author of many OSS packages for Dart/Flutter\n\nDeveloping Bluesky related packages 👇\nhttps://github.com/myConsciousness/atproto.dart\n\nGitHub: https://github.com/myConsciousness","avatar":"https://cdn.bsky.social/imgproxy/JF97YphLyIEWfq4KJNO_ZCYm9v_zNcRj7sSB8UZrRBw/rs:fill:1000:1000:1:0/plain/bafkreidqn4z6ocv5snxuqguarboozqdusam2tehccnu23yab7g2sgv64dq@jpeg","banner":"https://cdn.bsky.social/imgproxy/0ijMnNxGs3aYg9Xsb5YkfehBkZo2WRJReLgMtljXPM0/rs:fill:3000:1000:1:0/plain/bafkreiaz67sqpaacxjtbj7texvnz5tlnfpthman4kvciymxg2jc2vayd4m@jpeg","followsCount":3252,"followersCount":410,"postsCount":805,"indexedAt":"2023-03-25T14:57:25.791Z","viewer":{"muted":false}}

取得したレスポンスをファイルに出力する

これはbluesky_cliの機能ではないですが、以下のようにして取得したレスポンスをファイルに出力することができます。

bsky timeline > timeline.json

最後に

ここまで簡単に紹介してきましたが、bluesky_cliのインストール方法と使い方がわかったかと思います。Bluesky SocialのAPIをコマンドラインから叩いてみたい方は、是非使ってみてください!

また、Dart/Flutterで使用できるAT ProtocolやBluesky Social関連のパッケージを以下のリポジトリで開発していますので、興味のある方は覗いてみてください。もし役に立ったと感じた方はGitHubスターもお願いします、開発の励みになります!🙏

https://github.com/myConsciousness/atproto.dart

GitHubで編集を提案

Discussion