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