【Dart/Flutter】Bluesky APIからメディアを添付してBlueskyにポストする
概要
どうも、真也です。
この記事ではBluesky APIを使用してBlueskyへポストする際にメディアを添付する方法を紹介します。
使用パッケージ
DartでBluesky関連のAPIを使用する際には、Bluesky APIをDart/Flutter向けにラッピングしたblueskyがとても便利です。この記事でもこのblueskyを使用してポストにメディアを添付する方法を説明していきます。
パッケージをインストール
まずは先ほど紹介したblueskyをDartプロジェクトにインストールします。
With Dart:
dart pub add bluesky
dart pub get
With Flutter:
flutter pub add bluesky
flutter pub get
pubspec.yaml
に以下のようにblueskyの依存性が追加されていれば成功です。この記事ではv0.7.6
を使用します。
dependencies:
bluesky: ^0.7.6
実装
さて、blueskyをインストールできたら、実際にblueskyを使用してポストにメディアを添付するための実装を見ていきましょう。
導入
まずはblueskyを使用したことがない人向けに、簡単にblueskyを使用してポストする実装を紹介します。次のようにしてblueskyを使用してBlueskyへポストすることができます。
import 'package:bluesky/bluesky.dart' as bsky;
Future<void> main() async {
final bluesky = bsky.Bluesky.fromSession(await _session);
// ここでポストする。
await bluesky.feeds.createPost(
text: 'Hello, Bluesky!',
);
}
/// 認証
Future<bsky.Session> get _session async {
final session = await bsky.createSession(
identifier: 'shinyakato.dev',
password: 'xxxxxxx',
);
return session.data;
}
上記の例にあるように、blueskyを使用してBluesky APIを使用するためにはまずBluesky
オブジェクトのインスタンスを生成します。Bluesky
オブジェクトを生成する方法は主に二通りあり、認証を必要とする.fromSession
と認証を必要としない.anonymous
があります。今回使用するポストを送信するエンドポイントは認証が必須のため、.fromSession
からBluesky
オブジェクトのインスタンスを生成します。実際の認証処理はcreateSession
関数で行っています。
認証とBluesky
オブジェクトのインスタンスを生成できたら、あとは実際に使用するエンドポイントに対応するメソッドを使用するだけです。今回の例だとポストを送信するエンドポイントなので、例にあるbluesky.feeds.createPost
のようにFeedsService
の中のcreatePost
メソッドを使用するといったようにアクセスします。
余談ですが、blueskyは先にも触れたようにBluesky APIの主要なエンドポイントを全てサポートしているので、ポストを送信する以外にも興味のある方は以下の公式ページにあるマトリクスを確認してみてください。
メディアをアップロードする
導入でblueskyを使用してポストを送信する方法がなんとなくわかったところで、次はblueskyを使用して特定のPDSにメディアデータをアップロードする方法を紹介します。メディアのアップロードというと難しい通信処理を実装しなければいけない印象があると思いますが、blueskyを使用すると次のように簡単に実装できます。
import 'dart:io';
import 'package:bluesky/bluesky.dart' as bsky;
Future<void> main() async {
final bluesky = bsky.Bluesky.fromSession(await _session);
// アップロードする画像ファイル。
final file = File('./funny_photo.png');
final uploaded = await bluesky.repositories.uploadBlob(
// バイトデータを渡す。
file.readAsBytesSync(),
);
print(uploaded);
}
/// 認証
Future<bsky.Session> get _session async {
final session = await bsky.createSession(
identifier: 'shinyakato.dev',
password: 'xxxxxxx',
);
return session.data;
}
メディアデータを特定のPDSにアップロードするためには、上記の例でbluesky.repositories.uploadBlob
とあるようにRepositoriesService
のuploadBlob
メソッドを使用します。uploadBlob
はメディアデータを特定のPDSにアップロードするためのメソッドで、難しい処理を考えなくてもメディアのバイトデータを渡すだけでアップロードを行うことができます。アップロードが正常に完了するとアップロードデータに関するメタ情報が返却されるので、これを次のセクションで紹介する実装で使用します。
また、認証とBluesky
オブジェクトのインスタンスを生成する部分に関しては先ほど導入で触れた例とまったく同じです。
アップロードしたデータをポストに添付する
いよいよこの記事のメインディッシュです。導入とメディアのアップロードで触れた内容を応用して、以下のように実装できます。
import 'dart:io';
import 'package:bluesky/bluesky.dart' as bsky;
Future<void> main() async {
final bluesky = bsky.Bluesky.fromSession(await _session);
// アップロードする画像ファイル。
final file = File('./funny_photo.png');
final uploaded = await bluesky.repositories.uploadBlob(
// バイトデータを渡す。
file.readAsBytesSync(),
);
await bluesky.feeds.createPost(
text: 'Hello, Bluesky!',
// 画像を添付するためにはembedパラメータを使用する。
embed: bsky.Embed.images(
data: bsky.EmbedImages(
images: [
bsky.Image(
alt: 'Funny Photo', // ALTテキスト。
image: uploaded.data.blob, // アップロードした画像を添付。
),
],
),
),
);
}
/// 認証
Future<bsky.Session> get _session async {
final session = await bsky.createSession(
identifier: 'shinyakato.dev',
password: 'xxxxxxx',
);
return session.data;
}
少し難しそうな実装が増えたような感じですが、実際に追加された実装は以下のcreatePost
メソッドのembed
パラメータだけです。
embed: bsky.Embed.images(
data: bsky.EmbedImages(
images: [
bsky.Image(
alt: 'Funny Photo', // ALTテキスト。
image: uploaded.data.blob, // アップロードした画像を添付。
),
],
),
),
この記事では深く触れませんが、createPost
メソッドのembed
パラメータは文字通り埋め込み要素を扱うもので、メディアの添付以外にも特定のポストを引用することやリンクカードをポストに埋め込むことができます。
今回の場合だと画像を添付する必要があるので、embed
パラメータに対してEmbed.images
オブジェクトを渡します。Embed
オブジェクトはUnion型であり、Embed.images
はEmbed
オブジェクトの中でも画像を添付するためのオブジェクトです。上記の例にあるように、Embed.images
はEmbedImages
オブジェクトを受け取り、そのEmbedImages
に複数のImage
オブジェクトとアップロード済みの画像データを設定することができます。
この実装でDartプログラムを実行すると、アップロードした画像が添付された状態でポストが送信されることを確認できるかと思います。
ただ、ここまで見た感じだとembed
の実装は少し難しいですよね?blueskyだとユースケースに応じてもう少し簡単に書くことができます。
Embed
を生成
アップロードデータからポストに添付する画像が1枚しかない場合には、アップロードされたメディアデータから直接Embed
オブジェクトを生成することができます。先のembed
パラメータを次のように修正します。
await bluesky.feeds.createPost(
text: 'Hello, Bluesky!',
// アップロードした画像を添付。
embed: uploaded.data.blob.toEmbedImage(
alt: 'Funny Photo',
),
);
先の例との違いは一目瞭然だと思います。10行近くあった処理がたったの2行になり、直感的にも理解しやすい構造になりました。ただ、toEmbedImage
を使用した方法は添付する画像が1枚の場合のみ使用できることに注意してください。
Image
を生成
アップロードデータからポストに添付する画像が複数枚ある場合は、toImage
メソッドを使用するのが便利です。
embed: bsky.Embed.images(
data: bsky.EmbedImages(
images: [
uploaded.data.blob.toImage(alt: 'Funny Photo1'),
uploaded.data.blob.toImage(alt: 'Funny Photo2'),
],
),
),
アップロードされたBLOBからEmbedImage
を直接生成するtoEmbedImage
メソッドとは異なり、toImage
メソッドではアップロードされたBLOB単位でImage
オブジェクトを生成します。先に紹介したtoEmbedImage
ほど強力なメソッドではありませんが、Image
オブジェクトを直接生成する必要がなくネストが深くなりすぎることを防ぐこともできるので是非使ってみてください。
最後に
ここまでblueskyを使用してポストにメディアを添付する方法を紹介しました。
この記事では主にアップロードした画像をポストに添付する方法に触れましたが、先にも触れたようにblueskyは非常に強力なパッケージで主要なパッケージを全てサポートしています。既にいくつかのサードパーティのクライアントやサービスで使用されており、非常に動作が安定しているパッケージです。もしBluesky関連のクライアントやサービスなどをDartやFlutterで開発してみたい方は、是非blueskyを試してみてください。
また、私はbluesky以外のBluesky関連の便利なパッケージも以下のモノレポで開発しています。もし私の開発しているパッケージを気に入ってくれた場合や役に立った場合はGitHubスターをお願いします!
もし質問などがあればGitHubのIssueやBlueskyなどで気軽に声をかけてください。
リファレンス
atproto.dart - 公式サイト
atproto.dart - 開発リポジトリ
atproto.dart - pub.dev
Discussion