Skip to content

Instantly share code, notes, and snippets.

@Boehrsi
Created December 15, 2024 13:26
Show Gist options
  • Save Boehrsi/e2cbecfb7256cf378a6a2e73463259b5 to your computer and use it in GitHub Desktop.
Save Boehrsi/e2cbecfb7256cf378a6a2e73463259b5 to your computer and use it in GitHub Desktop.
Post Bluesky entries including link preview card
import 'package:bluesky/atproto.dart';
import 'package:bluesky/bluesky.dart';
import 'package:bluesky/core.dart';
import 'package:bluesky_text/bluesky_text.dart';
import 'package:http/http.dart' as http;
import 'package:metadata_fetch/metadata_fetch.dart';
Future<void> postEntry(PostDataEntry postData, String username, String password) async {
try {
// Create the Bluesky session. As the login is done by username and password it is
// suggested to create an app-specifc password, to avoid using your normal credentials
final session = await createSession(
identifier: username,
password: password,
);
// Create the actual Bluesky object from the session
final bluesky = Bluesky.fromSession(
await session.data,
);
// Format the text to make links and tags clickable within your post
final blueskyText = BlueskyText(postData.text);
final facets = await blueskyText.entities.toFacets();
// Post the content, including the card and your defined text
final entry = await bluesky.feed.post(
text: blueskyText.value,
facets: facets.map(Facet.fromJson).toList(),
embed: await fetchDataAndUploadMedia(bluesky, postData.url),
);
print(entry);
} on UnauthorizedException catch (e) {
print(e);
} on XRPCException catch (e) {
print(e);
}
}
Future<Embed?> fetchDataAndUploadMedia(Bluesky bluesky, String url) async {
// Fetch / extract web content
final data = await MetadataFetch.extract(url);
final title = data?.title;
final description = data?.description;
// Upload media to Bluesky
Blob? blob = await fetchAndUploadImage(bluesky, data?.image);
// If everything was fetched and the media upload was successful, return the formatted data
if (title != null && description != null && blob != null) {
return Embed.external(
data: EmbedExternal(
external: EmbedExternalThumbnail(
uri: url,
title: title,
description: description,
blob: blob,
),
),
);
}
// If something went wrong, return null
return null;
}
Future<Blob?> fetchAndUploadImage(Bluesky bluesky, String? imageUrl) async {
if (imageUrl != null) {
try {
// Fetch the image from the web
final uri = Uri.parse(imageUrl);
final http.Response response = await http.get(uri);
// Upload the image to Bluesky and return the blog, which is needed to create the post
final uploadResponse = await bluesky.atproto.repo.uploadBlob(response.bodyBytes);
return uploadResponse.data.blob;
} catch (e) {
print(e);
}
}
// If something went wrong, return null
return null;
}
class PostDataEntry {
final String url;
final String text;
PostDataEntry({required this.url, required this.text});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment