implement posts with images

This commit is contained in:
Denis-Cosmin NUTIU 2024-12-31 12:11:46 +02:00
parent 0997ab8c20
commit 97cdfbb7ef
3 changed files with 51 additions and 5 deletions

View file

@ -3,9 +3,9 @@ mod token;
use crate::bluesky::atproto::{ATProtoServerCreateSession, BlobResponse}; use crate::bluesky::atproto::{ATProtoServerCreateSession, BlobResponse};
use anyhow::anyhow; use anyhow::anyhow;
use base64::prelude::BASE64_STANDARD;
use base64::Engine; use base64::Engine;
use reqwest::Body; use reqwest::Body;
use std::io::Write;
use token::Token; use token::Token;
/// The BlueSky client used to interact with the platform. /// The BlueSky client used to interact with the platform.
@ -85,17 +85,28 @@ impl BlueSkyClient {
} }
/// Uploads an image. /// Uploads an image.
async fn upload_image(&mut self, payload: Vec<u8>) -> Result<BlobResponse, anyhow::Error> { pub async fn upload_image_by_url(
let base64_data = BASE64_STANDARD.encode(payload); &mut self,
image_url: &str,
) -> Result<BlobResponse, anyhow::Error> {
let data: Vec<u8> = self
.client
.get(image_url)
.send()
.await?
.bytes()
.await?
.to_vec();
Ok(self Ok(self
.client .client
.post("https://bsky.social/xrpc/com.atproto.repo.uploadBlob") .post("https://bsky.social/xrpc/com.atproto.repo.uploadBlob")
.header("Content-Type", "image/png") .header("Content-Type", "image/jpeg")
.header( .header(
"Authorization", "Authorization",
format!("Bearer {}", self.auth_token.access_jwt), format!("Bearer {}", self.auth_token.access_jwt),
) )
.body(base64_data) .body(data)
.send() .send()
.await? .await?
.json() .json()

View file

@ -20,6 +20,7 @@ pub struct Blob {
} }
impl Blob { impl Blob {
#![allow(dead_code)]
pub fn new(link: &str, mime_type: &str, size: i64) -> Self { pub fn new(link: &str, mime_type: &str, size: i64) -> Self {
Blob { Blob {
_type: "blob".to_string(), _type: "blob".to_string(),
@ -235,4 +236,18 @@ mod tests {
Ok(()) Ok(())
} }
#[test]
fn test_blob_new_serialization() -> Result<(), anyhow::Error> {
let blob = Blob::new("asa", "image/jpeg", 1);
let json = serde_json::to_string(&blob)?;
assert_eq!(
json,
r#"{"$type":"blob","ref":{"$link":"asa"},"mimeType":"image/jpeg","size":1}"#
);
Ok(())
}
} }

View file

@ -32,6 +32,18 @@ fn setup_graceful_shutdown(running: &Arc<AtomicBool>) {
}); });
} }
/// Embeds an image to a post.
async fn add_image_to_post(
client: &mut BlueSkyClient,
image_url: &str,
record: &mut bluesky::atproto::ATProtoRepoCreateRecord,
) -> Result<(), anyhow::Error> {
let thumb = client.upload_image_by_url(image_url).await?;
record.record.embed.as_mut().unwrap().external.thumb = Some(thumb.blob);
Ok(())
}
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), anyhow::Error> { async fn main() -> Result<(), anyhow::Error> {
env_logger::init(); env_logger::init();
@ -70,6 +82,14 @@ async fn main() -> Result<(), anyhow::Error> {
Ok(post) => { Ok(post) => {
let mut data: bluesky::atproto::ATProtoRepoCreateRecord = post.clone().into(); let mut data: bluesky::atproto::ATProtoRepoCreateRecord = post.clone().into();
data.repo = args.bluesky_handle.clone(); data.repo = args.bluesky_handle.clone();
if let Some(image_link) = post.image.clone() {
let result =
add_image_to_post(&mut bluesky_client, &image_link, &mut data).await;
if let Err(err) = result {
warn!("Failed to upload image: {err}")
}
}
let json = serde_json::to_string(&data); let json = serde_json::to_string(&data);
match json { match json {
Ok(json) => { Ok(json) => {