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