tgbot/types/definitions/file/
video_note.rs

1use std::{error::Error, fmt};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    api::{Form, Method, Payload},
7    types::{
8        ChatId,
9        InputFile,
10        Integer,
11        Message,
12        PhotoSize,
13        ReplyMarkup,
14        ReplyMarkupError,
15        ReplyParameters,
16        ReplyParametersError,
17        SuggestedPostParameters,
18        SuggestedPostParametersError,
19    },
20};
21
22/// Represents a video message.
23#[serde_with::skip_serializing_none]
24#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
25pub struct VideoNote {
26    /// Duration in seconds.
27    pub duration: Integer,
28    /// Identifier of the file.
29    ///
30    /// Can be used to download or reuse the file.
31    pub file_id: String,
32    /// Unique identifier of the file.
33    ///
34    /// It is supposed to be the same over time and for different bots.
35    /// Can't be used to download or reuse the file.
36    pub file_unique_id: String,
37    /// Width and height (diameter).
38    pub length: Integer,
39    /// File size in bytes.
40    pub file_size: Option<Integer>,
41    /// Thumbnail.
42    pub thumbnail: Option<PhotoSize>,
43}
44
45impl VideoNote {
46    /// Creates a new `VideoNote`.
47    ///
48    /// # Arguments
49    ///
50    /// * `duration` - Duration in seconds.
51    /// * `file_id` - Identifier of the file.
52    /// * `file_unique_id` - Unique identifier of the file.
53    /// * `length` - Width and height (diameter).
54    pub fn new<A, B>(duration: Integer, file_id: A, file_unique_id: B, length: Integer) -> Self
55    where
56        A: Into<String>,
57        B: Into<String>,
58    {
59        Self {
60            duration,
61            file_id: file_id.into(),
62            file_unique_id: file_unique_id.into(),
63            length,
64            file_size: None,
65            thumbnail: None,
66        }
67    }
68
69    /// Sets a new size of the file.
70    ///
71    /// # Arguments
72    ///
73    /// * `value` - The size of the file in bytes.
74    pub fn with_file_size(mut self, value: Integer) -> Self {
75        self.file_size = Some(value);
76        self
77    }
78
79    /// Sets a new thumbnail.
80    ///
81    /// # Arguments
82    ///
83    /// * `value` - Thumbnail.
84    pub fn with_thumbnail(mut self, value: PhotoSize) -> Self {
85        self.thumbnail = Some(value);
86        self
87    }
88}
89
90/// Sends a video message.
91///
92/// As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long.
93#[derive(Debug)]
94pub struct SendVideoNote {
95    form: Form,
96}
97
98impl SendVideoNote {
99    /// Creates a new `SendVideoNote`.
100    ///
101    /// # Arguments
102    ///
103    /// * `chat_id` - Unique identifier of the target chat.
104    /// * `video_note` - Video note to send.
105    pub fn new<A, B>(chat_id: A, video_note: B) -> Self
106    where
107        A: Into<ChatId>,
108        B: Into<InputFile>,
109    {
110        Self {
111            form: Form::from([
112                ("chat_id", chat_id.into().into()),
113                ("video_note", video_note.into().into()),
114            ]),
115        }
116    }
117
118    /// Sets a new value for the `allow_paid_broadcast` flag.
119    ///
120    /// # Arguments
121    ///
122    /// * `value` - Whether to allow up to 1000 messages per second, ignoring broadcasting limits
123    ///   for a fee of 0.1 Telegram Stars per message.
124    ///   The relevant Stars will be withdrawn from the bot's balance.
125    pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
126        self.form.insert_field("allow_paid_broadcast", value);
127        self
128    }
129
130    /// Sets a new business connection ID.
131    ///
132    /// # Arguments
133    ///
134    /// * `value` - Unique identifier of the business connection.
135    pub fn with_business_connection_id<T>(mut self, value: T) -> Self
136    where
137        T: Into<String>,
138    {
139        self.form.insert_field("business_connection_id", value.into());
140        self
141    }
142
143    /// Sets a new direct messages topic ID
144    ///
145    /// * `value` - Identifier of the direct messages topic to which the message will be sent.
146    ///
147    /// Required if the message is sent to a direct messages chat.
148    pub fn with_direct_messages_topic_id(mut self, value: Integer) -> Self {
149        self.form.insert_field("direct_messages_topic_id", value);
150        self
151    }
152
153    /// Sets a new value for the `disable_notification` flag.
154    ///
155    /// # Arguments
156    ///
157    /// * `value` - Indicates whether to send the message silently or not;
158    ///   a user will receive a notification without sound.
159    pub fn with_disable_notification(mut self, value: bool) -> Self {
160        self.form.insert_field("disable_notification", value);
161        self
162    }
163
164    /// Sets a new duration.
165    ///
166    /// # Arguments
167    ///
168    /// * `value` - Duration in seconds.
169    pub fn with_duration(mut self, value: Integer) -> Self {
170        self.form.insert_field("duration", value);
171        self
172    }
173
174    /// Sets a new length.
175    ///
176    /// # Arguments
177    ///
178    /// * `value` - Video width and height, i.e. diameter of the video message.
179    pub fn with_length(mut self, value: Integer) -> Self {
180        self.form.insert_field("length", value);
181        self
182    }
183
184    /// Sets a new message effect ID.
185    ///
186    /// # Arguments
187    ///
188    /// * `value` - Unique identifier of the message effect to be added to the message; for private chats only.
189    pub fn with_message_effect_id<T>(mut self, value: T) -> Self
190    where
191        T: Into<String>,
192    {
193        self.form.insert_field("message_effect_id", value.into());
194        self
195    }
196
197    /// Sets a new message thread ID.
198    ///
199    /// # Arguments
200    ///
201    /// * `value` - Unique identifier of the target message thread;
202    ///   supergroups only.
203    pub fn with_message_thread_id(mut self, value: Integer) -> Self {
204        self.form.insert_field("message_thread_id", value);
205        self
206    }
207
208    /// Sets a new value for the `protect_content` flag.
209    ///
210    /// # Arguments
211    ///
212    /// * `value` - Indicates whether to protect the contents
213    ///   of the sent message from forwarding and saving.
214    pub fn with_protect_content(mut self, value: bool) -> Self {
215        self.form.insert_field("protect_content", value.to_string());
216        self
217    }
218
219    /// Sets a new reply markup.
220    ///
221    /// # Arguments
222    ///
223    /// * `value` - Reply markup.
224    pub fn with_reply_markup<T>(mut self, value: T) -> Result<Self, ReplyMarkupError>
225    where
226        T: Into<ReplyMarkup>,
227    {
228        let value = value.into();
229        self.form.insert_field("reply_markup", value.serialize()?);
230        Ok(self)
231    }
232
233    /// Sets new reply parameters.
234    ///
235    /// # Arguments
236    ///
237    /// * `value` - Description of the message to reply to.
238    pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Result<Self, ReplyParametersError> {
239        self.form.insert_field("reply_parameters", value.serialize()?);
240        Ok(self)
241    }
242
243    /// Sets a new suggested post parameters.
244    ///
245    /// # Arguments
246    ///
247    /// * `value` - An object containing the parameters of the suggested post to send.
248    ///
249    /// For direct messages chats only.
250    ///
251    /// If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
252    pub fn with_suggested_post_parameters(
253        mut self,
254        value: &SuggestedPostParameters,
255    ) -> Result<Self, SuggestedPostParametersError> {
256        let value = serde_json::to_string(value).map_err(SuggestedPostParametersError::Serialize)?;
257        self.form.insert_field("suggested_post_parameters", value);
258        Ok(self)
259    }
260
261    /// Sets a new thumbnail.
262    ///
263    /// # Arguments
264    ///
265    /// * `value` - Thumbnail.
266    ///
267    /// The thumbnail should be in JPEG format and less than 200 kB in size.
268    /// A thumbnail‘s width and height should not exceed 320.
269    /// Ignored if the file is not uploaded using `multipart/form-data`.
270    /// Thumbnails can’t be reused and can be only uploaded as a new file.
271    pub fn with_thumbnail<T>(mut self, value: T) -> Result<Self, SendVideoNoteError>
272    where
273        T: Into<InputFile>,
274    {
275        let value = value.into();
276        if matches!(value, InputFile::Id(_)) {
277            return Err(SendVideoNoteError::InvalidThumbnail);
278        }
279        self.form.insert_field("thumbnail", value);
280        Ok(self)
281    }
282}
283
284impl Method for SendVideoNote {
285    type Response = Message;
286
287    fn into_payload(self) -> Payload {
288        Payload::form("sendVideoNote", self.form)
289    }
290}
291
292/// Represents an error when sending a video note.
293#[derive(Debug)]
294pub enum SendVideoNoteError {
295    /// Thumbnails can not be reused.
296    InvalidThumbnail,
297}
298
299impl fmt::Display for SendVideoNoteError {
300    fn fmt(&self, out: &mut fmt::Formatter<'_>) -> fmt::Result {
301        match self {
302            Self::InvalidThumbnail => write!(out, "thumbnails can’t be reused and can be only uploaded as a new file"),
303        }
304    }
305}
306
307impl Error for SendVideoNoteError {}