mirror of
https://framagit.org/veretcle/oolatoocs.git
synced 2025-07-20 12:31:18 +02:00
🎨: improve bsky image upload
This commit is contained in:
31
Cargo.lock
generated
31
Cargo.lock
generated
@@ -733,6 +733,21 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
@@ -740,6 +755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -748,6 +764,17 @@ version = "0.3.31"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
@@ -783,6 +810,7 @@ version = "0.3.31"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
@@ -1781,13 +1809,14 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oolatoocs"
|
name = "oolatoocs"
|
||||||
version = "4.1.1"
|
version = "4.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atrium-api",
|
"atrium-api",
|
||||||
"bsky-sdk",
|
"bsky-sdk",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"futures",
|
||||||
"html-escape",
|
"html-escape",
|
||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "oolatoocs"
|
name = "oolatoocs"
|
||||||
version = "4.1.1"
|
version = "4.1.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -9,6 +9,7 @@ edition = "2021"
|
|||||||
chrono = "^0.4"
|
chrono = "^0.4"
|
||||||
clap = "^4"
|
clap = "^4"
|
||||||
env_logger = "^0.10"
|
env_logger = "^0.10"
|
||||||
|
futures = "^0.3"
|
||||||
html-escape = "^0.2"
|
html-escape = "^0.2"
|
||||||
log = "^0.4"
|
log = "^0.4"
|
||||||
megalodon = "^0.13"
|
megalodon = "^0.13"
|
||||||
|
91
src/bsky.rs
91
src/bsky.rs
@@ -8,8 +8,9 @@ use bsky_sdk::{
|
|||||||
rich_text::RichText,
|
rich_text::RichText,
|
||||||
BskyAgent,
|
BskyAgent,
|
||||||
};
|
};
|
||||||
|
use futures::{stream, StreamExt};
|
||||||
use image::ImageReader;
|
use image::ImageReader;
|
||||||
use log::{debug, error};
|
use log::{debug, error, warn};
|
||||||
use megalodon::entities::attachment::{Attachment, AttachmentType};
|
use megalodon::entities::attachment::{Attachment, AttachmentType};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{error::Error, fs::exists, io::Cursor};
|
use std::{error::Error, fs::exists, io::Cursor};
|
||||||
@@ -152,39 +153,66 @@ pub async fn generate_media_records(
|
|||||||
let mut embed: Option<
|
let mut embed: Option<
|
||||||
atrium_api::types::Union<atrium_api::app::bsky::feed::post::RecordEmbedRefs>,
|
atrium_api::types::Union<atrium_api::app::bsky::feed::post::RecordEmbedRefs>,
|
||||||
> = None;
|
> = None;
|
||||||
let mut images = Vec::new();
|
|
||||||
let mut videos: Vec<atrium_api::app::bsky::embed::video::MainData> = Vec::new();
|
|
||||||
|
|
||||||
for media in media_attach.iter() {
|
let image_media_attach: Vec<_> = media_attach
|
||||||
match media.r#type {
|
.iter()
|
||||||
AttachmentType::Image => {
|
.filter(|x| x.r#type == AttachmentType::Image)
|
||||||
let blob = upload_media(true, bsky, &media.url).await.unwrap();
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
let video_media_attach: Vec<_> = media_attach
|
||||||
|
.iter()
|
||||||
|
.filter(|x| (x.r#type == AttachmentType::Video || x.r#type == AttachmentType::Gifv))
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
images.push(
|
// Bsky only tasks 1 video per post, so we’ll try to treat that first and exit
|
||||||
|
if !video_media_attach.is_empty() {
|
||||||
|
// treat only the very first video, ignore the rest
|
||||||
|
let media = &video_media_attach[0];
|
||||||
|
let blob = upload_media(false, bsky, &media.url).await.unwrap();
|
||||||
|
|
||||||
|
embed = Some(atrium_api::types::Union::Refs(
|
||||||
|
atrium_api::app::bsky::feed::post::RecordEmbedRefs::AppBskyEmbedVideoMain(Box::new(
|
||||||
|
atrium_api::app::bsky::embed::video::MainData {
|
||||||
|
alt: media.description.clone(),
|
||||||
|
aspect_ratio: None,
|
||||||
|
captions: None,
|
||||||
|
video: blob.data.blob,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
|
||||||
|
// returns immediately, we don’t want to treat the other medias
|
||||||
|
return embed;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stream = stream::iter(image_media_attach)
|
||||||
|
.map(|media| {
|
||||||
|
let bsky = bsky.clone();
|
||||||
|
tokio::task::spawn(async move {
|
||||||
|
debug!("Treating media {}", &media.url);
|
||||||
|
upload_media(true, &bsky, &media.url).await.map(|i| {
|
||||||
atrium_api::app::bsky::embed::images::ImageData {
|
atrium_api::app::bsky::embed::images::ImageData {
|
||||||
alt: media
|
alt: media
|
||||||
.description
|
.description
|
||||||
.clone()
|
.clone()
|
||||||
.map_or("".to_string(), |v| v.to_owned()),
|
.map_or("".to_string(), |v| v.to_owned()),
|
||||||
aspect_ratio: None,
|
aspect_ratio: None,
|
||||||
image: blob.data.blob,
|
image: i.data.blob,
|
||||||
}
|
}
|
||||||
.into(),
|
})
|
||||||
);
|
})
|
||||||
}
|
})
|
||||||
AttachmentType::Gifv | AttachmentType::Video => {
|
.buffered(4);
|
||||||
let blob = upload_media(false, bsky, &media.url).await.unwrap();
|
|
||||||
|
|
||||||
videos.push(atrium_api::app::bsky::embed::video::MainData {
|
let mut images = Vec::new();
|
||||||
alt: media.description.clone(),
|
|
||||||
aspect_ratio: None,
|
while let Some(result) = stream.next().await {
|
||||||
captions: None,
|
match result {
|
||||||
video: blob.data.blob,
|
Ok(Ok(v)) => images.push(v.into()),
|
||||||
});
|
Ok(Err(e)) => warn!("Cannot treat a specific media: {}", e),
|
||||||
}
|
Err(e) => error!("Something went wrong when joining main thread: {}", e),
|
||||||
_ => {
|
|
||||||
error!("Not an image, not a video, what happened here?");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,19 +224,14 @@ pub async fn generate_media_records(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if a video has been uploaded, it takes priority as you can only have 1 video per post
|
|
||||||
if !videos.is_empty() {
|
|
||||||
embed = Some(atrium_api::types::Union::Refs(
|
|
||||||
atrium_api::app::bsky::feed::post::RecordEmbedRefs::AppBskyEmbedVideoMain(Box::new(
|
|
||||||
videos[0].clone().into(),
|
|
||||||
)),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
embed
|
embed
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn upload_media(is_image: bool, bsky: &BskyAgent, u: &str) -> Result<Output, Box<dyn Error>> {
|
async fn upload_media(
|
||||||
|
is_image: bool,
|
||||||
|
bsky: &BskyAgent,
|
||||||
|
u: &str,
|
||||||
|
) -> Result<Output, Box<dyn Error + Send + Sync>> {
|
||||||
let dl = reqwest::get(u).await?;
|
let dl = reqwest::get(u).await?;
|
||||||
let content_length = dl.content_length().ok_or("Content length unavailable")?;
|
let content_length = dl.content_length().ok_or("Content length unavailable")?;
|
||||||
let bytes = if content_length <= 1_000_000 || !is_image {
|
let bytes = if content_length <= 1_000_000 || !is_image {
|
||||||
|
Reference in New Issue
Block a user