From 6a2ba6a50a3a54caaa38d6eb0f0f130da2b756da Mon Sep 17 00:00:00 2001 From: YoursFunny Date: Thu, 24 Sep 2026 19:51:50 +0800 Subject: [PATCH] fix: handle empty media and prompt persistence --- crates/xmedia-bot/src/handlers/repair.rs | 3 +++ crates/xmedia-bot/src/handlers/urls.rs | 19 +++++++++++++------ crates/xmedia-bot/src/send/post_send.rs | 20 +++++++++++++++++++- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/crates/xmedia-bot/src/handlers/repair.rs b/crates/xmedia-bot/src/handlers/repair.rs index 4897172..19ff75e 100644 --- a/crates/xmedia-bot/src/handlers/repair.rs +++ b/crates/xmedia-bot/src/handlers/repair.rs @@ -114,6 +114,9 @@ async fn refetch( .iter() .filter_map(|media| media_to_payload(media, fetched.sensitive)) .collect(); + if items.is_empty() { + return Ok(None); + } // The re-fetch may produce a fresh local file (ugoira / bsky remux): hand it // to the same keep-alive registry the first fetch uses. if let Some(dir) = fetched.keep_alive() { diff --git a/crates/xmedia-bot/src/handlers/urls.rs b/crates/xmedia-bot/src/handlers/urls.rs index 8739081..ae7333c 100644 --- a/crates/xmedia-bot/src/handlers/urls.rs +++ b/crates/xmedia-bot/src/handlers/urls.rs @@ -637,10 +637,7 @@ async fn url_media_inner( let format = chat_data.format_for(fetched.site_id); if fetched.media.is_empty() { // A post with no media is still a post: its text goes out as a - // message (through the same caption the media path would - // attach, plus the long-post quoting the senders apply to - // their own), instead of answering "No media found" to text - // the fetch already parsed. + // message through the same caption the media path would attach. let text = fetched .render_fields() .map(|(_, _, title, content, _)| x_media::site::compose_text(title, content)) @@ -652,14 +649,24 @@ async fn url_media_inner( return; } let caption = fetched.caption_with(&format); - // Raw render data for the link cache; the send fills in the - // Telegram file ids and persists the entry. let cache_data = cached_snapshot(fetched); let items: Vec = fetched .media .iter() .filter_map(|media| media_to_payload(media, fetched.sensitive)) .collect(); + if items.is_empty() { + let text = fetched + .render_fields() + .map(|(_, _, title, content, _)| x_media::site::compose_text(title, content)) + .unwrap_or_default(); + let caption = fetched.caption_with(&format); + let caption = + send::quote_long_caption(&caption, &text, ctx.config.caption_quote_text_chars); + send::send_text_post(ctx, chat_id, reply_to.0 as i64, caption.into_owned()).await; + return; + } + *hint.lock() = ActionHint::for_items(&items); let task = build_send_task( &chat_data, chat_id, diff --git a/crates/xmedia-bot/src/send/post_send.rs b/crates/xmedia-bot/src/send/post_send.rs index 5c36a02..238372e 100644 --- a/crates/xmedia-bot/src/send/post_send.rs +++ b/crates/xmedia-bot/src/send/post_send.rs @@ -301,7 +301,7 @@ pub(crate) async fn post_send_actions(ctx: &AppContext<'_>, task: &Task, message log_key(&source_url) ); let source_url = source_url.clone(); - let _ = ctx + let saved = match ctx .chat_store .update(chat_id, move |data| { data.edit_message.insert( @@ -315,7 +315,25 @@ pub(crate) async fn post_send_actions(ctx: &AppContext<'_>, task: &Task, message }, ); }) + .await + { + Ok((_, true)) => true, + Ok((_, false)) | Err(()) => false, + }; + if !saved { + log::error!("edit prompt {prompt_id} could not be persisted; removing it"); + let _ = ctx + .sender + .delete_message(ChatId(chat_id), MessageId(prompt_id as i32)) + .await; + notify_failure( + ctx.sender, + notify_chat_id, + notify_message_id, + "Could not save the edit-before-forward prompt — nothing was forwarded.", + ) .await; + } } Err(e) => { log::error!("failed to send edit prompt: {e}");