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