diff --git a/crates/api_common/src/request.rs b/crates/api_common/src/request.rs index 9b8821fff..934e45c0c 100644 --- a/crates/api_common/src/request.rs +++ b/crates/api_common/src/request.rs @@ -66,14 +66,89 @@ pub async fn fetch_link_metadata(url: &Url, context: &LemmyContext) -> LemmyResu }) } -/// Generate post thumbnail in background task, because some sites can be very slow to respond. +/// Generates and saves a post thumbnail and metadata. /// /// Takes a callback to generate a send activity task, so that post can be federated with metadata. /// /// TODO: `federated_thumbnail` param can be removed once we federate full metadata and can /// write it to db directly, without calling this function. /// https://github.com/LemmyNet/lemmy/issues/4598 -pub fn generate_post_link_metadata( +pub async fn generate_post_link_metadata( + post: Post, + custom_thumbnail: Option, + federated_thumbnail: Option, + send_activity: impl FnOnce(Post) -> Option + Send + 'static, + local_site: Option, + context: Data, +) -> LemmyResult<()> { + let metadata = match &post.url { + Some(url) => fetch_link_metadata(url, &context).await.unwrap_or_default(), + _ => Default::default(), + }; + + let is_image_post = metadata + .content_type + .as_ref() + .is_some_and(|content_type| content_type.starts_with("image")); + + // Decide if we are allowed to generate local thumbnail + let allow_sensitive = local_site_opt_to_sensitive(&local_site); + let allow_generate_thumbnail = allow_sensitive || !post.nsfw; + + let thumbnail_url = if is_image_post { + if allow_generate_thumbnail { + match post.url { + Some(url) => generate_pictrs_thumbnail(&url, &context) + .await + .ok() + .map(Into::into), + None => None, + } + } else { + None + } + } else { + // Use custom thumbnail if available and its not an image post + if let Some(custom_thumbnail) = custom_thumbnail { + proxy_image_link(custom_thumbnail, &context).await.ok() + } + // Use federated thumbnail if available + else if let Some(federated_thumbnail) = federated_thumbnail { + proxy_image_link(federated_thumbnail, &context).await.ok() + } + // Generate local thumbnail if allowed + else if allow_generate_thumbnail { + match metadata.opengraph_data.image { + Some(url) => generate_pictrs_thumbnail(&url, &context) + .await + .ok() + .map(Into::into), + None => None, + } + } + // Otherwise use opengraph preview image directly + else { + metadata.opengraph_data.image + } + }; + + let form = PostUpdateForm { + embed_title: Some(metadata.opengraph_data.title), + embed_description: Some(metadata.opengraph_data.description), + embed_video_url: Some(metadata.opengraph_data.embed_video_url), + thumbnail_url: Some(thumbnail_url), + url_content_type: Some(metadata.content_type), + ..Default::default() + }; + let updated_post = Post::update(&mut context.pool(), post.id, &form).await?; + if let Some(send_activity) = send_activity(updated_post) { + ActivityChannel::submit_activity(send_activity, &context).await?; + } + Ok(()) +} + +/// Generates a post thumbnail in background task, because some sites can be very slow to respond. +pub fn generate_post_link_metadata_background( post: Post, custom_thumbnail: Option, federated_thumbnail: Option, @@ -82,71 +157,16 @@ pub fn generate_post_link_metadata( context: Data, ) { spawn_try_task(async move { - let metadata = match &post.url { - Some(url) => fetch_link_metadata(url, &context).await.unwrap_or_default(), - _ => Default::default(), - }; - - let is_image_post = metadata - .content_type - .as_ref() - .is_some_and(|content_type| content_type.starts_with("image")); - - // Decide if we are allowed to generate local thumbnail - let allow_sensitive = local_site_opt_to_sensitive(&local_site); - let allow_generate_thumbnail = allow_sensitive || !post.nsfw; - - let thumbnail_url = if is_image_post { - if allow_generate_thumbnail { - match post.url { - Some(url) => generate_pictrs_thumbnail(&url, &context) - .await - .ok() - .map(Into::into), - None => None, - } - } else { - None - } - } else { - // Use custom thumbnail if available and its not an image post - if let Some(custom_thumbnail) = custom_thumbnail { - proxy_image_link(custom_thumbnail, &context).await.ok() - } - // Use federated thumbnail if available - else if let Some(federated_thumbnail) = federated_thumbnail { - proxy_image_link(federated_thumbnail, &context).await.ok() - } - // Generate local thumbnail if allowed - else if allow_generate_thumbnail { - match metadata.opengraph_data.image { - Some(url) => generate_pictrs_thumbnail(&url, &context) - .await - .ok() - .map(Into::into), - None => None, - } - } - // Otherwise use opengraph preview image directly - else { - metadata.opengraph_data.image - } - }; - - let form = PostUpdateForm { - embed_title: Some(metadata.opengraph_data.title), - embed_description: Some(metadata.opengraph_data.description), - embed_video_url: Some(metadata.opengraph_data.embed_video_url), - thumbnail_url: Some(thumbnail_url), - url_content_type: Some(metadata.content_type), - ..Default::default() - }; - let updated_post = Post::update(&mut context.pool(), post.id, &form).await?; - if let Some(send_activity) = send_activity(updated_post) { - ActivityChannel::submit_activity(send_activity, &context).await?; - } - Ok(()) - }); + generate_post_link_metadata( + post, + custom_thumbnail, + federated_thumbnail, + send_activity, + local_site, + context, + ) + .await + }) } /// Extract site metadata from HTML Opengraph attributes. diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 6e760bb3e..58ae4e6cf 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -161,7 +161,8 @@ pub async fn create_post( |post| Some(SendActivityData::CreatePost(post)), Some(local_site), context.reset_request_count(), - ); + ) + .await?; // They like their own post by default let person_id = local_user_view.person.id; diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index 034108d8e..3737079a0 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -116,7 +116,8 @@ pub async fn update_post( |post| Some(SendActivityData::UpdatePost(post)), Some(local_site), context.reset_request_count(), - ); + ) + .await?; build_post_response( context.deref(), diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index ff11c985c..0b7ca2e18 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -24,7 +24,7 @@ use chrono::{DateTime, Utc}; use html2text::{from_read_with_decorator, render::text_renderer::TrivialDecorator}; use lemmy_api_common::{ context::LemmyContext, - request::generate_post_link_metadata, + request::generate_post_link_metadata_background, utils::{ get_url_blocklist, local_site_opt_to_slur_regex, @@ -278,7 +278,7 @@ impl Object for ApubPost { let timestamp = page.updated.or(page.published).unwrap_or_else(naive_now); let post = Post::insert_apub(&mut context.pool(), timestamp, &form).await?; - generate_post_link_metadata( + generate_post_link_metadata_background( post.clone(), None, page.image.map(|i| i.url),