: automatically convert image to webp when over 1Mb

This commit is contained in:
VC
2025-01-17 17:20:14 +01:00
parent f05669923f
commit 49279e7f1f
3 changed files with 690 additions and 67 deletions

723
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "oolatoocs" name = "oolatoocs"
version = "4.0.0" version = "4.1.0"
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
@@ -21,6 +21,8 @@ tokio = { version = "^1.33", features = ["rt-multi-thread", "macros"] }
toml = "^0.8" toml = "^0.8"
bsky-sdk = "^0.1" bsky-sdk = "^0.1"
atrium-api = "^0.24" atrium-api = "^0.24"
image = "^0.25"
webp = "^0.3"
[profile.release] [profile.release]
strip = true strip = true

View File

@@ -8,10 +8,12 @@ use bsky_sdk::{
rich_text::RichText, rich_text::RichText,
BskyAgent, BskyAgent,
}; };
use log::error; use image::ImageReader;
use log::{debug, error};
use megalodon::entities::attachment::{Attachment, AttachmentType}; use megalodon::entities::attachment::{Attachment, AttachmentType};
use regex::Regex; use regex::Regex;
use std::{error::Error, fs::exists}; use std::{error::Error, fs::exists, io::Cursor};
use webp::*;
/// Intermediary struct to deal with replies more easily /// Intermediary struct to deal with replies more easily
#[derive(Debug)] #[derive(Debug)]
@@ -154,10 +156,10 @@ pub async fn generate_media_records(
let mut videos: Vec<atrium_api::app::bsky::embed::video::MainData> = Vec::new(); let mut videos: Vec<atrium_api::app::bsky::embed::video::MainData> = Vec::new();
for media in media_attach.iter() { for media in media_attach.iter() {
let blob = upload_media(bsky, &media.url).await.unwrap();
match media.r#type { match media.r#type {
AttachmentType::Image => { AttachmentType::Image => {
let blob = upload_media(true, bsky, &media.url).await.unwrap();
images.push( images.push(
atrium_api::app::bsky::embed::images::ImageData { atrium_api::app::bsky::embed::images::ImageData {
alt: media alt: media
@@ -171,6 +173,8 @@ pub async fn generate_media_records(
); );
} }
AttachmentType::Gifv | AttachmentType::Video => { AttachmentType::Gifv | AttachmentType::Video => {
let blob = upload_media(false, bsky, &media.url).await.unwrap();
videos.push(atrium_api::app::bsky::embed::video::MainData { videos.push(atrium_api::app::bsky::embed::video::MainData {
alt: media.description.clone(), alt: media.description.clone(),
aspect_ratio: None, aspect_ratio: None,
@@ -204,11 +208,23 @@ pub async fn generate_media_records(
embed embed
} }
async fn upload_media(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>> {
let dl = reqwest::get(u).await?; let dl = reqwest::get(u).await?;
let bytes = dl.bytes().await?; let content_length = dl.content_length().ok_or("Content length unavailable")?;
let bytes = if content_length <= 1_000_000 || !is_image {
dl.bytes().await?.as_ref().to_vec()
} else {
// this is an image and its over 1Mb long
debug!("Img file too large: {}", content_length);
let img = ImageReader::new(Cursor::new(dl.bytes().await?))
.with_guessed_format()?
.decode()?;
let encoder: Encoder = Encoder::from_image(&img)?;
let webp: WebPMemory = encoder.encode(90f32);
webp.to_vec()
};
let record = bsky.api.com.atproto.repo.upload_blob(bytes.into()).await?; let record = bsky.api.com.atproto.repo.upload_blob(bytes).await?;
Ok(record) Ok(record)
} }