Skip to main content

tgbot/types/definitions/media/
paid.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{
4    api::{Form, Method, Payload},
5    types::{
6        ChatId,
7        InputPaidMediaGroup,
8        Integer,
9        LivePhoto,
10        Message,
11        ParseMode,
12        PhotoSize,
13        ReplyMarkup,
14        ReplyMarkupError,
15        ReplyParameters,
16        ReplyParametersError,
17        SuggestedPostParameters,
18        SuggestedPostParametersError,
19        TextEntities,
20        TextEntity,
21        TextEntityError,
22        User,
23        Video,
24    },
25};
26
27/// Contains information about a paid media purchase.
28#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
29pub struct PaidMediaPurchased {
30    /// User who purchased the media.
31    pub from: User,
32    /// Bot-specified paid media payload.
33    #[serde(rename = "paid_media_payload")]
34    pub payload: String,
35}
36
37impl PaidMediaPurchased {
38    /// Creates a new `PaidMediaPurchased`.
39    ///
40    /// # Arguments
41    ///
42    /// * `from` - User who purchased the media.
43    /// * `payload` - Bot-specified paid media payload.
44    pub fn new<T>(from: User, payload: T) -> Self
45    where
46        T: Into<String>,
47    {
48        Self {
49            from,
50            payload: payload.into(),
51        }
52    }
53}
54
55/// Describes the paid media added to a message.
56#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
57pub struct PaidMediaInfo {
58    /// The number of Telegram Stars that must be paid to buy access to the media.
59    pub star_count: Integer,
60    /// Information about the paid media.
61    pub paid_media: Vec<PaidMedia>,
62}
63
64impl PaidMediaInfo {
65    /// Creates a new `PaidMediaInfo`.
66    ///
67    /// # Arguments
68    ///
69    /// * `star_count` - The number of Telegram Stars that must be paid to buy access to the media.
70    /// * `paid_media` - Information about the paid media.
71    pub fn new<A, B>(star_count: Integer, paid_media: A) -> Self
72    where
73        A: IntoIterator<Item = B>,
74        B: Into<PaidMedia>,
75    {
76        Self {
77            star_count,
78            paid_media: paid_media.into_iter().map(Into::into).collect(),
79        }
80    }
81}
82
83/// Describes paid media.
84#[derive(Clone, Debug, derive_more::From, Deserialize, PartialEq, PartialOrd, Serialize)]
85#[serde(from = "RawPaidMedia", into = "RawPaidMedia")]
86pub enum PaidMedia {
87    /// The paid media is a live photo.
88    LivePhoto(LivePhoto),
89    /// The paid media is a photo.
90    Photo(Vec<PhotoSize>),
91    /// The paid media isn't available before the payment.
92    Preview(PaidMediaPreview),
93    /// The paid media is a video.
94    #[from(Video)]
95    Video(Box<Video>),
96}
97
98/// The paid media isn't available before the payment.
99#[serde_with::skip_serializing_none]
100#[derive(Clone, Debug, Default, Deserialize, PartialEq, PartialOrd, Serialize)]
101pub struct PaidMediaPreview {
102    /// Duration of the media in seconds as defined by the sender.
103    pub duration: Option<Integer>,
104    /// Media height as defined by the sender.
105    pub height: Option<Integer>,
106    /// Media width as defined by the sender.
107    pub width: Option<Integer>,
108}
109
110impl PaidMediaPreview {
111    /// Sets a new duration.
112    ///
113    /// # Arguments
114    ///
115    /// * `value` - Duration of the media in seconds as defined by the sender.
116    pub fn with_duration(mut self, value: Integer) -> Self {
117        self.duration = Some(value);
118        self
119    }
120
121    /// Sets a new height.
122    ///
123    /// # Arguments
124    ///
125    /// * `value` - Height of the media in seconds as defined by the sender.
126    pub fn with_height(mut self, value: Integer) -> Self {
127        self.height = Some(value);
128        self
129    }
130
131    /// Sets a new width.
132    ///
133    /// # Arguments
134    ///
135    /// * `value` - Width of the media in seconds as defined by the sender.
136    pub fn with_width(mut self, value: Integer) -> Self {
137        self.width = Some(value);
138        self
139    }
140}
141
142#[serde_with::skip_serializing_none]
143#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
144#[serde(rename_all = "snake_case", tag = "type")]
145enum RawPaidMedia {
146    LivePhoto {
147        live_photo: LivePhoto,
148    },
149    Photo {
150        photo: Vec<PhotoSize>,
151    },
152    Preview {
153        duration: Option<Integer>,
154        height: Option<Integer>,
155        width: Option<Integer>,
156    },
157    Video {
158        video: Box<Video>,
159    },
160}
161
162impl From<RawPaidMedia> for PaidMedia {
163    fn from(value: RawPaidMedia) -> Self {
164        match value {
165            RawPaidMedia::LivePhoto { live_photo } => Self::LivePhoto(live_photo),
166            RawPaidMedia::Photo { photo } => Self::Photo(photo),
167            RawPaidMedia::Preview {
168                duration,
169                height,
170                width,
171            } => Self::Preview(PaidMediaPreview {
172                duration,
173                height,
174                width,
175            }),
176            RawPaidMedia::Video { video } => Self::Video(video),
177        }
178    }
179}
180
181impl From<PaidMedia> for RawPaidMedia {
182    fn from(value: PaidMedia) -> Self {
183        match value {
184            PaidMedia::LivePhoto(live_photo) => Self::LivePhoto { live_photo },
185            PaidMedia::Photo(photo) => Self::Photo { photo },
186            PaidMedia::Preview(PaidMediaPreview {
187                duration,
188                height,
189                width,
190            }) => Self::Preview {
191                duration,
192                height,
193                width,
194            },
195            PaidMedia::Video(video) => Self::Video { video },
196        }
197    }
198}
199
200/// Send paid media to channel chats.
201#[derive(Debug)]
202pub struct SendPaidMedia {
203    form: Form,
204}
205
206impl SendPaidMedia {
207    /// Creates a new `SendPaidMedia`.
208    ///
209    /// # Arguments
210    ///
211    /// * `chat_id` - Unique identifier for the target chat.
212    /// * `media` - An array describing the media to be sent
213    /// * `star_count` - The number of Telegram Stars that must be paid to buy access to the media; 1-25000.
214    pub fn new<T>(chat_id: T, media: InputPaidMediaGroup, star_count: Integer) -> Self
215    where
216        T: Into<ChatId>,
217    {
218        let mut form: Form = media.into();
219        form.insert_field("chat_id", chat_id.into());
220        form.insert_field("star_count", star_count);
221        Self { form }
222    }
223
224    /// Sets a new value for the `allow_paid_broadcast` flag.
225    ///
226    /// # Arguments
227    ///
228    /// * `value` - Whether to allow up to 1000 messages per second, ignoring broadcasting limits
229    ///   for a fee of 0.1 Telegram Stars per message.
230    ///   The relevant Stars will be withdrawn from the bot's balance.
231    pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
232        self.form.insert_field("allow_paid_broadcast", value);
233        self
234    }
235
236    /// Sets a new business connection ID.
237    ///
238    /// # Arguments
239    ///
240    /// * `value` - Unique identifier of the business connection
241    ///   on behalf of which the message will be sent.
242    pub fn with_business_connection_id<T>(mut self, value: T) -> Self
243    where
244        T: Into<String>,
245    {
246        self.form.insert_field("business_connection_id", value.into());
247        self
248    }
249
250    /// Sets a new caption.
251    ///
252    /// # Arguments
253    ///
254    /// `value` - Media caption, 0-1024 characters after entities parsing.
255    pub fn with_caption<T>(mut self, value: T) -> Self
256    where
257        T: Into<String>,
258    {
259        self.form.insert_field("caption", value.into());
260        self
261    }
262
263    /// Sets a new list of caption entities.
264    ///
265    /// # Arguments
266    ///
267    /// `value` - A list of special entities that appear in the caption, which can be specified instead of parse_mode.
268    pub fn with_caption_entities<T>(mut self, value: T) -> Result<Self, TextEntityError>
269    where
270        T: IntoIterator<Item = TextEntity>,
271    {
272        let value = value.into_iter().collect::<TextEntities>().serialize()?;
273        self.form.insert_field("caption_entities", value);
274        self.form.remove_field("parse_mode");
275        Ok(self)
276    }
277
278    /// Sets a new direct messages topic ID
279    ///
280    /// * `value` - Identifier of the direct messages topic to which the message will be sent.
281    ///
282    /// Required if the message is sent to a direct messages chat.
283    pub fn with_direct_messages_topic_id(mut self, value: Integer) -> Self {
284        self.form.insert_field("direct_messages_topic_id", value);
285        self
286    }
287
288    /// Sets a new value for the `disable_notification` flag.
289    ///
290    /// # Arguments
291    ///
292    /// `value` - Whether to send the message silently.
293    ///
294    /// Users will receive a notification with no sound.
295    pub fn with_disable_notification(mut self, value: bool) -> Self {
296        self.form.insert_field("disable_notification", value);
297        self
298    }
299
300    /// Sets a new message thread ID.
301    ///
302    /// # Arguments
303    ///
304    /// * `value` - Unique identifier of the target message thread;
305    ///   for forum supergroups and private chats of bots with forum topic mode enabled only.
306    pub fn with_message_thread_id(mut self, value: Integer) -> Self {
307        self.form.insert_field("message_thread_id", value);
308        self
309    }
310
311    /// Sets a new parse mode.
312    ///
313    /// # Arguments
314    ///
315    /// `value` - Mode for parsing entities in the media caption.
316    pub fn with_parse_mode(mut self, value: ParseMode) -> Self {
317        self.form.insert_field("parse_mode", value);
318        self.form.remove_field("caption_entities");
319        self
320    }
321
322    /// Sets a new payload.
323    ///
324    /// # Arguments
325    ///
326    /// * `value` - Bot-defined paid media payload;
327    ///   0-128 bytes;
328    ///   This will not be displayed to the user, use it for your internal processes.
329    pub fn with_payload<T>(mut self, value: T) -> Self
330    where
331        T: Into<String>,
332    {
333        self.form.insert_field("payload", value.into());
334        self
335    }
336
337    /// Sets a new value for the `protect_content` flag.
338    ///
339    /// # Arguments
340    ///
341    /// `value` - Whether to protect the contents 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);
344        self
345    }
346
347    /// Sets new reply parameters.
348    ///
349    /// # Arguments
350    ///
351    /// `value` - Description of the message to reply to.
352    pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Result<Self, ReplyParametersError> {
353        let value = value.serialize()?;
354        self.form.insert_field("reply_parameters", value);
355        Ok(self)
356    }
357
358    /// Sets a new reply markup.
359    ///
360    /// # Arguments
361    ///
362    /// `value` - Additional interface options.
363    pub fn with_reply_markup<T>(mut self, value: T) -> Result<Self, ReplyMarkupError>
364    where
365        T: Into<ReplyMarkup>,
366    {
367        let value = value.into().serialize()?;
368        self.form.insert_field("reply_markup", value);
369        Ok(self)
370    }
371
372    /// Sets a new value for the `show_caption_above_media` flag.
373    ///
374    /// # Arguments
375    ///
376    /// `value` - Whether the caption must be shown above the message media.
377    pub fn with_show_caption_above_media(mut self, value: bool) -> Self {
378        self.form.insert_field("show_caption_above_media", value);
379        self
380    }
381
382    /// Sets a new suggested post parameters.
383    ///
384    /// # Arguments
385    ///
386    /// * `value` - An object containing the parameters of the suggested post to send.
387    ///
388    /// For direct messages chats only.
389    ///
390    /// If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
391    pub fn with_suggested_post_parameters(
392        mut self,
393        value: &SuggestedPostParameters,
394    ) -> Result<Self, SuggestedPostParametersError> {
395        self.form.insert_field("suggested_post_parameters", value.serialize()?);
396        Ok(self)
397    }
398}
399
400impl Method for SendPaidMedia {
401    type Response = Message;
402
403    fn into_payload(self) -> Payload {
404        Payload::form("sendPaidMedia", self.form)
405    }
406}