diff --git a/crates/xmedia-bot/src/media_sender/test_support.rs b/crates/xmedia-bot/src/media_sender/test_support.rs index 19883b7..28a6156 100644 --- a/crates/xmedia-bot/src/media_sender/test_support.rs +++ b/crates/xmedia-bot/src/media_sender/test_support.rs @@ -227,6 +227,8 @@ pub(crate) struct MockSender { cursor: Mutex, calls: Mutex>, messages: Mutex>, + /// The reply target of every `send_message`, in order. + message_replies: Mutex>>, captions: Mutex>, answers: Mutex>>, /// `(chat, message, text)` of every text rewrite, in order. @@ -281,6 +283,7 @@ impl MockSender { cursor: Mutex::new(0), calls: Mutex::new(Vec::new()), messages: Mutex::new(Vec::new()), + message_replies: Mutex::new(Vec::new()), captions: Mutex::new(Vec::new()), answers: Mutex::new(Vec::new()), edited_texts: Mutex::new(Vec::new()), @@ -301,6 +304,12 @@ impl MockSender { self.messages.lock().clone() } + /// The reply target of every plain message sent, in order (`None` = no + /// reply). + pub(crate) fn message_replies(&self) -> Vec> { + self.message_replies.lock().clone() + } + /// Captions passed to `edit_message_caption`, in order. pub(crate) fn captions(&self) -> Vec { self.captions.lock().clone() @@ -415,11 +424,14 @@ impl MediaSender for MockSender { &self, _chat_id: ChatId, text: String, - _reply_to: Option, + reply_to: Option, _reply_markup: Option, ) -> BoxFuture<'_, Result> { Box::pin(async move { self.messages.lock().push(text); + self.message_replies + .lock() + .push(reply_to.map(|id| id.0 as i64)); match self.next("send_message") { Outcome::MessageOk => Ok(MockSender::SENT_ID), Outcome::MessageErr => Err(self.error()), diff --git a/crates/xmedia-bot/src/send/mod.rs b/crates/xmedia-bot/src/send/mod.rs index ad87703..38c2b18 100644 --- a/crates/xmedia-bot/src/send/mod.rs +++ b/crates/xmedia-bot/src/send/mod.rs @@ -1646,6 +1646,9 @@ mod tests { .expect("the prompt record must be stored"); assert_eq!(record.url, "https://x.com/u/status/1"); assert_eq!(record.forward_message_ids, vec![10, 11]); + // The prompt replies to the post's first media message, so several + // links in one user message still get distinguishable prompts. + assert_eq!(sender.message_replies(), vec![Some(10)]); } #[tokio::test] diff --git a/crates/xmedia-bot/src/send/post_send.rs b/crates/xmedia-bot/src/send/post_send.rs index f506644..e991f79 100644 --- a/crates/xmedia-bot/src/send/post_send.rs +++ b/crates/xmedia-bot/src/send/post_send.rs @@ -301,12 +301,18 @@ pub(crate) async fn post_send_actions(ctx: &AppContext<'_>, task: &Task, message "\n({hidden} more templates not shown — /remove_template to prune.)" )); } + // Reply to this post's own first media message rather than the user's + // link message: one message carrying several links opens several + // prompts, and replying them all to that one message made each + // indistinguishable from the others. The media message is the thing + // the prompt actually edits and forwards. + let prompt_reply_to = message_ids.first().copied().unwrap_or(reply_to); let prompt = ctx .sender .send_message( ChatId(chat_id), text, - Some(MessageId(reply_to as i32)), + Some(MessageId(prompt_reply_to as i32)), Some(keyboard), ) .await;