tgbot/types/file/animation/mod.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 ParseMode,
13 PhotoSize,
14 ReplyMarkup,
15 ReplyMarkupError,
16 ReplyParameters,
17 ReplyParametersError,
18 TextEntities,
19 TextEntity,
20 TextEntityError,
21 },
22};
23
24#[cfg(test)]
25mod tests;
26
27/// Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound).
28#[serde_with::skip_serializing_none]
29#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
30pub struct Animation {
31 /// Duration in seconds as defined by sender.
32 pub duration: Integer,
33 /// Identifier of the file.
34 ///
35 /// Can be used to download or reuse the file.
36 pub file_id: String,
37 /// Unique identifier of the file.
38 ///
39 /// It is supposed to be the same over time and for different bots.
40 /// Can't be used to download or reuse the file.
41 pub file_unique_id: String,
42 /// Height as defined by sender.
43 pub height: Integer,
44 /// Width as defined by sender.
45 pub width: Integer,
46 /// Original filename as defined by sender.
47 pub file_name: Option<String>,
48 /// File size in bytes.
49 pub file_size: Option<Integer>,
50 /// MIME type as defined by sender.
51 pub mime_type: Option<String>,
52 /// Thumbnail as defined by sender.
53 pub thumbnail: Option<PhotoSize>,
54}
55
56impl Animation {
57 /// Creates a new `Animation`.
58 ///
59 /// # Arguments
60 ///
61 /// * `duration` - Duration in seconds.
62 /// * `file_id` - Identifier of the file.
63 /// * `file_unique_id` - Unique identifier of the file.
64 /// * `height` - Height.
65 /// * `width` - Width.
66 pub fn new<A, B>(duration: Integer, file_id: A, file_unique_id: B, height: Integer, width: Integer) -> Self
67 where
68 A: Into<String>,
69 B: Into<String>,
70 {
71 Self {
72 duration,
73 file_id: file_id.into(),
74 file_unique_id: file_unique_id.into(),
75 height,
76 width,
77 file_name: None,
78 file_size: None,
79 mime_type: None,
80 thumbnail: None,
81 }
82 }
83
84 /// Sets a new file name.
85 ///
86 /// # Arguments
87 ///
88 /// * `value` - File name.
89 pub fn with_file_name<T>(mut self, value: T) -> Self
90 where
91 T: Into<String>,
92 {
93 self.file_name = Some(value.into());
94 self
95 }
96
97 /// Sets a new file size.
98 ///
99 /// # Arguments
100 ///
101 /// * `value` - The size of the file in bytes.
102 pub fn with_file_size(mut self, value: Integer) -> Self {
103 self.file_size = Some(value);
104 self
105 }
106
107 /// Sets a new MIME type.
108 ///
109 /// # Arguments
110 ///
111 /// * `value` - MIME type.
112 pub fn with_mime_type<T>(mut self, value: T) -> Self
113 where
114 T: Into<String>,
115 {
116 self.mime_type = Some(value.into());
117 self
118 }
119
120 /// Sets a new thumbnail.
121 ///
122 /// # Arguments
123 ///
124 /// * `value` - Thumbnail.
125 pub fn with_thumbnail(mut self, value: PhotoSize) -> Self {
126 self.thumbnail = Some(value);
127 self
128 }
129}
130
131/// Sends an animation file (GIF or H.264/MPEG-4 AVC video without sound).
132///
133/// Bots can currently send animation files of up to 50 MB in size,
134/// this limit may be changed in the future.
135#[derive(Debug)]
136pub struct SendAnimation {
137 form: Form,
138}
139
140impl SendAnimation {
141 /// Creates a new `SendAnimation`.
142 ///
143 /// # Arguments
144 ///
145 /// * `chat_id` - Unique identifier of the target chat.
146 /// * `animation` - Animation to send.
147 pub fn new<A, B>(animation: A, chat_id: B) -> Self
148 where
149 A: Into<InputFile>,
150 B: Into<ChatId>,
151 {
152 Self {
153 form: Form::from([
154 ("animation", animation.into().into()),
155 ("chat_id", chat_id.into().into()),
156 ]),
157 }
158 }
159
160 /// Sets a new value for the `allow_paid_broadcast` flag.
161 ///
162 /// # Arguments
163 ///
164 /// * `value` - Whether to allow up to 1000 messages per second, ignoring broadcasting limits
165 /// for a fee of 0.1 Telegram Stars per message.
166 /// The relevant Stars will be withdrawn from the bot's balance.
167 pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
168 self.form.insert_field("allow_paid_broadcast", value);
169 self
170 }
171
172 /// Sets a new business connection ID.
173 ///
174 /// # Arguments
175 ///
176 /// * `value` - Unique identifier of the business connection.
177 pub fn with_business_connection_id<T>(mut self, value: T) -> Self
178 where
179 T: Into<String>,
180 {
181 self.form.insert_field("business_connection_id", value.into());
182 self
183 }
184
185 /// Sets a new caption.
186 ///
187 /// # Arguments
188 ///
189 /// * `value` - Caption; 0-1024 characters.
190 ///
191 /// May also be used when resending animation by `file_id`.
192 pub fn with_caption<T>(mut self, value: T) -> Self
193 where
194 T: Into<String>,
195 {
196 self.form.insert_field("caption", value.into());
197 self
198 }
199
200 /// Sets a new list of caption entities.
201 ///
202 /// # Arguments
203 ///
204 /// * `value` - The list of special entities that appear in the caption.
205 ///
206 /// Caption parse mode will be set to [`None`] when this method is called.
207 pub fn with_caption_entities<T>(mut self, value: T) -> Result<Self, TextEntityError>
208 where
209 T: IntoIterator<Item = TextEntity>,
210 {
211 let value: TextEntities = value.into_iter().collect();
212 self.form.insert_field("caption_entities", value.serialize()?);
213 self.form.remove_field("parse_mode");
214 Ok(self)
215 }
216
217 /// Sets a new caption parse mode.
218 ///
219 /// # Arguments
220 ///
221 /// * `value` - Parse mode.
222 ///
223 /// Caption entities will be set to [`None`] when this method is called.
224 pub fn with_caption_parse_mode(mut self, value: ParseMode) -> Self {
225 self.form.insert_field("parse_mode", value);
226 self.form.remove_field("caption_entities");
227 self
228 }
229
230 /// Sets a new value for the `disable_notification` flag.
231 ///
232 /// # Arguments
233 ///
234 /// * `value` - Indicates whether to send the message silently or not;
235 /// a user will receive a notification without sound.
236 pub fn with_disable_notification(mut self, value: bool) -> Self {
237 self.form.insert_field("disable_notification", value);
238 self
239 }
240
241 /// Sets a new duration.
242 ///
243 /// # Arguments
244 ///
245 /// * `value` - Duration in seconds.
246 pub fn with_duration(mut self, value: Integer) -> Self {
247 self.form.insert_field("duration", value);
248 self
249 }
250
251 /// Sets a new value for the `has_spoiler` flag.
252 ///
253 /// # Arguments
254 ///
255 /// * `value` - Indicates whether to cover with a spoiler animation.
256 pub fn with_has_spoiler(mut self, value: bool) -> Self {
257 self.form.insert_field("has_spoiler", value);
258 self
259 }
260
261 /// Sets a new height.
262 ///
263 /// # Arguments
264 ///
265 /// * `value` - Height.
266 pub fn with_height(mut self, value: Integer) -> Self {
267 self.form.insert_field("height", value);
268 self
269 }
270
271 /// Sets a new message effect ID.
272 ///
273 /// # Arguments
274 ///
275 /// * `value` - Unique identifier of the message effect to be added to the message; for private chats only.
276 pub fn with_message_effect_id<T>(mut self, value: T) -> Self
277 where
278 T: Into<String>,
279 {
280 self.form.insert_field("message_effect_id", value.into());
281 self
282 }
283
284 /// Sets a new message thread ID.
285 ///
286 /// # Arguments
287 ///
288 /// * `value` - Unique identifier of the target message thread;
289 /// supergroups only.
290 pub fn with_message_thread_id(mut self, value: Integer) -> Self {
291 self.form.insert_field("message_thread_id", value);
292 self
293 }
294
295 /// Sets a new value for the `protect_content` flag.
296 ///
297 /// # Arguments
298 ///
299 /// * `value` - Indicates whether to protect the contents
300 /// of the sent message from forwarding and saving.
301 pub fn with_protect_content(mut self, value: bool) -> Self {
302 self.form.insert_field("protect_content", value);
303 self
304 }
305
306 /// Sets a new reply markup.
307 ///
308 /// # Arguments
309 ///
310 /// * `value` - Reply markup.
311 pub fn with_reply_markup<T>(mut self, value: T) -> Result<Self, ReplyMarkupError>
312 where
313 T: Into<ReplyMarkup>,
314 {
315 let value = value.into();
316 self.form.insert_field("reply_markup", value.serialize()?);
317 Ok(self)
318 }
319
320 /// Sets new reply parameters.
321 ///
322 /// # Arguments
323 ///
324 /// * `value` - Description of the message to reply to.
325 pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Result<Self, ReplyParametersError> {
326 self.form.insert_field("reply_parameters", value.serialize()?);
327 Ok(self)
328 }
329
330 /// Sets a new value for the `show_caption_above_media` flag.
331 ///
332 /// # Arguments
333 ///
334 /// `value` - Whether the caption must be shown above the message media.
335 pub fn with_show_caption_above_media(mut self, value: bool) -> Self {
336 self.form.insert_field("show_caption_above_media", value);
337 self
338 }
339
340 /// Sets a new thumbnail.
341 ///
342 /// # Arguments
343 ///
344 /// * `value` - Thumbnail.
345 ///
346 /// The thumbnail should be in JPEG format and less than 200 kB in size.
347 /// A thumbnail‘s width and height should not exceed 320.
348 /// Ignored if the file is not uploaded using `multipart/form-data`.
349 /// Thumbnails can’t be reused and can be only uploaded as a new file.
350 pub fn with_thumbnail<T>(mut self, value: T) -> Result<Self, SendAnimationError>
351 where
352 T: Into<InputFile>,
353 {
354 let value = value.into();
355 if matches!(value, InputFile::Id(_)) {
356 return Err(SendAnimationError::InvalidThumbnail);
357 }
358 self.form.insert_field("thumbnail", value);
359 Ok(self)
360 }
361
362 /// Sets a new width.
363 ///
364 /// # Arguments
365 ///
366 /// * `value` - Width.
367 pub fn with_width(mut self, value: Integer) -> Self {
368 self.form.insert_field("width", value);
369 self
370 }
371}
372
373impl Method for SendAnimation {
374 type Response = Message;
375
376 fn into_payload(self) -> Payload {
377 Payload::form("sendAnimation", self.form)
378 }
379}
380
381/// Represents an error when sending an animation.
382#[derive(Debug)]
383pub enum SendAnimationError {
384 /// Thumbnails can not be reused.
385 InvalidThumbnail,
386}
387
388impl fmt::Display for SendAnimationError {
389 fn fmt(&self, out: &mut fmt::Formatter<'_>) -> fmt::Result {
390 match self {
391 Self::InvalidThumbnail => write!(out, "thumbnails can’t be reused and can be only uploaded as a new file"),
392 }
393 }
394}
395
396impl Error for SendAnimationError {}