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