From 10bb32f145347c8f656cd968394a94da754b77a1 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Fri, 20 Sep 2024 07:28:51 +0000 Subject: [PATCH] Add send_media_group --- src/push/telegram/botapi_client.rs | 65 +++++++++++- src/push/telegram/tg_type.rs | 163 +++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+), 1 deletion(-) diff --git a/src/push/telegram/botapi_client.rs b/src/push/telegram/botapi_client.rs index 4720697..eaa9bf9 100644 --- a/src/push/telegram/botapi_client.rs +++ b/src/push/telegram/botapi_client.rs @@ -1,7 +1,7 @@ use super::tg_type::*; -use crate::formdata::FormData; #[cfg(test)] use crate::formdata::FormDataPartBuilder; +use crate::formdata::{FormData, FormDataPart}; use crate::webclient::WebClient; use derive_builder::Builder; use serde::{Deserialize, Serialize}; @@ -367,6 +367,69 @@ impl BotapiClient { } } + pub async fn send_media_group( + &self, + chat_id: &ChatId, + message_thread_id: Option, + media: Vec, + files: Vec<(String, FormDataPart)>, + disable_notification: Option, + protect_content: Option, + message_effect_id: Option<&str>, + reply_parameters: Option<&ReplyParameters>, + ) -> Result, BotapiClientError> { + let mut form = FormData::new(); + form.data("chat_id", &chat_id.to_string()); + match message_thread_id { + Some(m) => { + form.data("message_thread_id", &m.to_string()); + } + None => {} + } + form.data("media", serde_json::to_string(&media)?.as_bytes()); + for (key, part) in files { + form.part(&key, part); + } + match disable_notification { + Some(d) => { + form.data("disable_notification", &d.to_string()); + } + None => {} + } + match protect_content { + Some(p) => { + form.data("protect_content", &p.to_string()); + } + None => {} + } + match message_effect_id { + Some(m) => { + form.data("message_effect_id", m); + } + None => {} + } + match reply_parameters { + Some(r) => { + form.data("reply_parameters", serde_json::to_string(r)?.as_str()); + } + None => {} + } + let re = self + .client + .post_multipart( + format!("{}/bot{}/sendMediaGroup", self.cfg.base, self.cfg.token), + None, + form, + ) + .await + .ok_or("Failed to send media group.")?; + let status = re.status(); + match re.text().await { + Ok(t) => Ok(serde_json::from_str(t.as_str())?), + Err(e) => Err(format!("HTTP ERROR {}: {}", status, e))?, + } + } + pub async fn send_message + ?Sized>( &self, chat_id: &ChatId, diff --git a/src/push/telegram/tg_type.rs b/src/push/telegram/tg_type.rs index 73afd0d..486c0bd 100644 --- a/src/push/telegram/tg_type.rs +++ b/src/push/telegram/tg_type.rs @@ -176,6 +176,169 @@ pub enum InputFile { Content(FormDataPart), } +#[derive(Builder, Clone, Debug, Deserialize, Serialize)] +#[builder(setter(into))] +/// Represents an audio file to be treated as music to be sent. +pub struct InputMediaAudio { + /// File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), + /// pass an HTTP URL for Telegram to get a file from the Internet, + /// or pass “attach://” to upload a new one using + /// multipart/form-data under name. + media: String, + /// Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file + /// is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. + /// A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded + /// using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, + /// so you can pass “attach://” if the thumbnail was uploaded using + /// multipart/form-data under . + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + thumbnail: Option, + /// Optional. Caption of the audio to be sent, 0-1024 characters after entities parsing + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + caption: Option, + /// Optional. Mode for parsing entities in the audio caption. See formatting options for more details. + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + parse_mode: Option, + /// Optional. Duration of the audio in seconds + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + duration: Option, + /// Optional. Performer of the audio + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + performer: Option, + /// Optional. Title of the audio + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + title: Option, +} + +#[derive(Builder, Clone, Debug, Deserialize, Serialize)] +#[builder(setter(into))] +/// Represents a general file to be sent. +pub struct InputMediaDocument { + /// File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), + /// pass an HTTP URL for Telegram to get a file from the Internet, + /// or pass “attach://” to upload a new one using + /// multipart/form-data under name. + media: String, + /// Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file + /// is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. + /// A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded + /// using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, + /// so you can pass “attach://” if the thumbnail was uploaded using + /// multipart/form-data under . + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + thumbnail: Option, + /// Optional. Caption of the document to be sent, 0-1024 characters after entities parsing + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + caption: Option, + /// Optional. Mode for parsing entities in the document caption. + /// See formatting options for more details. + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + parse_mode: Option, + /// Optional. Disables automatic server-side content type detection for files uploaded + /// using multipart/form-data. Always True, if the document is sent as part of an album. + #[builder(default, setter(strip_option))] + #[serde(skip_serializing_if = "Option::is_none")] + disable_content_type_detection: Option, +} + +#[derive(Builder, Clone, Debug, Deserialize, Serialize)] +#[builder(setter(into))] +/// Represents a photo to be sent. +pub struct InputMediaPhoto { + /// File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), + /// pass an HTTP URL for Telegram to get a file from the Internet, or pass + /// “attach://” to upload a new one using multipart/form-data + /// under name. + media: String, + /// Optional. Caption of the photo to be sent, 0-1024 characters after entities parsing + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + caption: Option, + /// Optional. Mode for parsing entities in the photo caption. See formatting options for more details. + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + parse_mode: Option, + /// Optional. Pass True, if the caption must be shown above the message media + #[builder(default, setter(strip_option))] + #[serde(skip_serializing_if = "Option::is_none")] + show_caption_above_media: Option, + /// Optional. Pass True if the photo needs to be covered with a spoiler animations + #[builder(default, setter(strip_option))] + #[serde(skip_serializing_if = "Option::is_none")] + has_spoiler: Option, +} + +#[derive(Builder, Clone, Debug, Deserialize, Serialize)] +#[builder(setter(into))] +/// Represents a video to be sent. +pub struct InputMediaVideo { + /// File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), + /// pass an HTTP URL for Telegram to get a file from the Internet, or pass + /// “attach://” to upload a new one using multipart/form-data under + /// name. + media: String, + /// Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file + /// is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. + /// A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded + /// using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, + /// so you can pass “attach://” if the thumbnail was uploaded using + /// multipart/form-data under . + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + thumbnail: Option, + /// Optional. Caption of the video to be sent, 0-1024 characters after entities parsing + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + caption: Option, + /// Optional. Mode for parsing entities in the video caption. See formatting options for more details. + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + parse_mode: Option, + /// Optional. Pass True, if the caption must be shown above the message media + #[builder(default, setter(strip_option))] + #[serde(skip_serializing_if = "Option::is_none")] + show_caption_above_media: Option, + /// Optional. Video width + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + width: Option, + /// Optional. Video height + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + height: Option, + /// Optional. Video duration in seconds + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + duration: Option, + /// Optional. Pass True if the uploaded video is suitable for streaming + #[builder(default, setter(strip_option))] + #[serde(skip_serializing_if = "Option::is_none")] + supports_streaming: Option, + /// Optional. Pass True if the video needs to be covered with a spoiler animation + #[builder(default, setter(strip_option))] + #[serde(skip_serializing_if = "Option::is_none")] + has_spoiler: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, derive_more::From)] +#[serde(rename_all = "camelCase", tag = "type")] +/// This object represents the content of a media message to be sent. +pub enum InputMedia { + Audio(InputMediaAudio), + Document(InputMediaDocument), + Photo(InputMediaPhoto), + Video(InputMediaVideo), +} + #[test] fn test_chat_id() { assert_eq!(