Ruby から Bluesky に投稿してみようとあれこれやってみたのでメモ。
Gem
Bluesky のプロトコルについて何もわかってないので Gem を探す。
bluesky という gem が見つかったけど、これは違うやつっぽい。 bskyrb というのがあったので使ってみる。 atproto というのもあったけどこれは調べてない。
% gem install bskyrb Fetching bskyrb-0.5.3.gem Fetching httparty-0.21.0.gem Fetching xrpc-0.0.4.gem When you HTTParty, you must party hard! Successfully installed httparty-0.21.0 Successfully installed xrpc-0.0.4 Successfully installed bskyrb-0.5.3 Parsing documentation for httparty-0.21.0 Installing ri documentation for httparty-0.21.0 Parsing documentation for xrpc-0.0.4 unknown encoding name "'application/json'," for lib/xrpc/client.rb, skipping Installing ri documentation for xrpc-0.0.4 Parsing documentation for bskyrb-0.5.3 Installing ri documentation for bskyrb-0.5.3 Done installing documentation for httparty, xrpc, bskyrb after 0 seconds 3 gems installed
Bskyrb
README に書かれてる通りだけどこんな感じで使う。
require 'bskyrb' username = 'tmtms.bsky.social' password = 'xxxxxxxxxxxxxxxxx' pds_url = 'https://bsky.social' credentials = Bskyrb::Credentials.new(username, password) session = Bskyrb::Session.new(credentials, pds_url) bsky = Bskyrb::RecordManager.new(session)
Post(投稿)
bsky.create_post('API からの投稿テスト') #=> # {"uri"=> # "at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyy7fmciva2w", # "cid"=>"bafyreifpmd2ovx5cmytpnje35pgzr7cdkacaksxeh42nfdlwxaotehtpve"}
戻り値の uri
の at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyy7fmciva2w
は、https://staging.bsky.app/profile/tmtms.bsky.social/post/3jyy7fmciva2w に対応してるっぽい。よくわかってないけど。
投稿の取得
Post の URI かブラウザで見るときの URL を指定する。
bsky.get_post_by_url('at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyy7fmciva2w') または bsky.get_post_by_url('https://staging.bsky.app/profile/tmtms.bsky.social/post/3jyy7fmciva2w') #=> # #<Bskyrb::AppBskyFeedDefs::PostView:0x00007f3ffb2c8660 # @author= # {"did"=>"did:plc:vgflzemtmzcqr3eyrtt4wh7c", # "handle"=>"tmtms.bsky.social", # "displayName"=>"tmtms / とみたまさひろ", # "avatar"=> # "https://cdn.bsky.social/imgproxy/JpuYoHvseSZTA4-XJl6NOTJWMrBDO46GFNfNLxAJ8aM/rs:fill:1000:1000:1:0/plain/bafkreiho7263tsofusirvy2soncqqiewwd5747qfh7655t2ydfitou37ni@jpeg", # "viewer"=>{"muted"=>false, "blockedBy"=>false}, # "labels"=>[]}, # @cid="bafyreifpmd2ovx5cmytpnje35pgzr7cdkacaksxeh42nfdlwxaotehtpve", # @embed=nil, # @indexedAt="2023-06-25T10:03:06.127Z", # @labels=[], # @likeCount=2, # @record= # {"text"=>"API からの投稿テスト", # "$type"=>"app.bsky.feed.post", # "createdAt"=>"2023-06-25T19:03:04.236+09:00"}, # @replyCount=0, # @repostCount=1, # @uri="at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyy7fmciva2w", # @viewer= # {"repost"=> # "at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.repost/3jyya4rb26n2m", # "like"=> # "at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.like/3jyyaaxqcbv2m"}>
Like(いいね)
投稿の URI を指定して like
。
bsky.like('at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyy7fmciva2w') #=> # {"uri"=> # "at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.like/3jyyaaxqcbv2m", # "cid"=>"bafyreicq3afwv4ayry7bu3plcfvmhjr5xwpkqneztsqr6y2bs5jt5fxjpq"}
Repost(再投稿)
Twitter でいうところのリツイート。
bsky.repost('at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyy7fmciva2w') #=> # {"uri"=> # "at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.repost/3jyya4rb26n2m", # "cid"=>"bafyreihiahaprk52am5ukogenkz7xtw3npi2cu7oqwszkjudu2wxmtzi74"}
テキスト中の URL
こんな風にテキスト中に URL 文字列を含めてもリンクにはならない。
bsky.create_post("テスト https://tmtms.net") #=> # {"uri"=> # "at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyyanhmjry2x", # "cid"=>"bafyreib24x7xh3kbjyck2d67fj7qie2w7xdxxjihl64vaf6oyauagpr6dy"}
リンクになってる投稿を取得して見てみる。
bsy.get_post_by_url('https://staging.bsky.app/profile/tmtms.bsky.social/post/3jyybr2bcdl2a') #=> # #<Bskyrb::AppBskyFeedDefs::PostView:0x00007f3ffb2615f0 # @author= # {"did"=>"did:plc:vgflzemtmzcqr3eyrtt4wh7c", # "handle"=>"tmtms.bsky.social", # "displayName"=>"tmtms / とみたまさひろ", # "avatar"=> # "https://cdn.bsky.social/imgproxy/JpuYoHvseSZTA4-XJl6NOTJWMrBDO46GFNfNLxAJ8aM/rs:fill:1000:1000:1:0/plain/bafkreiho7263tsofusirvy2soncqqiewwd5747qfh7655t2ydfitou37ni@jpeg", # "viewer"=>{"muted"=>false, "blockedBy"=>false}, # "labels"=>[]}, # @cid="bafyreig4rfs7xdlpzq7ewjzn5itvosyccifz3sj2hhowj6mop46e7xflzq", # @embed=nil, # @indexedAt="2023-06-25T10:45:17.362Z", # @labels=[], # @likeCount=0, # @record= # {"text"=>"リンクのテスト https://tmtms.net", # "$type"=>"app.bsky.feed.post", # "facets"=> # [{"index"=>{"byteEnd"=>39, "byteStart"=>22}, # "features"=> # [{"uri"=>"https://tmtms.net", # "$type"=>"app.bsky.richtext.facet#link"}]}], # "createdAt"=>"2023-06-25T10:45:17.066Z"}, # @replyCount=0, # @repostCount=0, # @uri="at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyybr2bcdl2a", # @viewer={}>
どうやら、テキストの何バイト目から何バイト目までがリンクで URI みたいな指定がされてるぽい。投稿時に同じような指定をすればよさそう。
bskyrb のコードを読んでみたら post
の代わりに create_record
を使えば JSON で色々指定できるぽい。
data = { 'collection' => 'app.bsky.feed.post', 'repo' => session.did, 'record' => { '$type' => 'app.bsky.feed.post', 'createdAt' => Time.now.iso8601(3), 'text' => 'ホームページはこちら', 'facets' => [ { 'index' => {'byteStart' => 21, 'byteEnd' => 30}, 'features' => [ { 'uri' => 'https://tmtms.net/', '$type' => 'app.bsky.richtext.facet#link', }, ], }, ], }, } bsky.create_record(data) #=> # {"uri"=> # "at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyycpsqjuc2b", # "cid"=>"bafyreidsaocpktig5jxud45x3jhdtaq2755cmsoibkh4oxc2yyjeqvummi"}
「こちら」の部分がリンクになった!
リンクカード
アプリやブラウザから投稿するときに本文中に URL が含まれていると「Add link card」という表示が出て、そこをクリックすると og:image や og:title などがカード形式で表示される。 Twitter は特に何もしなくても表示されたんだけど、Bluesky は今のところ(?)「Add link card」を押さないとカードがつかないまま。
↓
API の投稿で同じことをやるには次のような感じでやればいいっぽい。
まずサムネイル画像をアップロードする。
HTTParty.post( bsky.upload_blob_uri(session.pds), body: File.read('tengu.jpg'), headers: { "Content-Type" => 'image/jpeg', "Authorization" => "Bearer #{session.access_token}", } ) #=> # {"blob"=> # {"$type"=>"blob", # "ref"=> # {"$link"=>"bafkreifwykwd2waeshgjze5rccphfsoqfjykjv2fa6psbxc65ym2nf6id4"}, # "mimeType"=>"image/jpeg", # "size"=>117643}}
Bskyrb は、bsky.upload_blob('tengu.jpg', 'image/jpeg')
で上と同じことができるようにしてるっぽいんだけど、Content-Type の指定が無視されてしまうバグがあって使えなかった。そのうち直るんじゃないかな。たぶん。
この戻り値の blob
を投稿時に embed
の thumb
に指定する。
data = { 'collection' => 'app.bsky.feed.post', '$type' => 'app.bsky.feed.post', 'repo' => session.did, 'record' => { '$type' => 'app.bsky.feed.post', 'createdAt' => Time.now.iso8601(3), 'text' => 'ブログへのリンク。画像と説明はダミー。', 'embed' => { '$type' => 'app.bsky.embed.external', 'external' => { 'uri' => 'https://blog.tmtms.net/', 'title' => 'tmtms のメモ', 'description' => '天狗はブログの内容とは関係ないよ', 'thumb' => { '$type' => 'blob', 'mimeType'=>'image/jpeg', 'size' => 117643, 'ref' => { '$link' => 'bafkreifwykwd2waeshgjze5rccphfsoqfjykjv2fa6psbxc65ym2nf6id4', }, }, }, }, }, } bsky.create_record(data) #=> # {"uri"=> # "at://did:plc:vgflzemtmzcqr3eyrtt4wh7c/app.bsky.feed.post/3jyyli7jvjr2y", # "cid"=>"bafyreiao4a7zpyqddspkv3nciiq7xhzhsjv6snmicgyp73plagj4pvmply"}
できた! 🎉🎉🎉
プロトコルのことを何もわかってないままだけど、一応ひと通りの投稿はできるようになった。
しかし、もともと Twitter の自分の投稿を拾って Bluesky に投げたいと思って調べてたんだけど、Twitter の API が使えなくなってしまったのでどうしたもんかなー…。