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