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