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 {}