tgbot/types/definitions/sticker/
mod.rs

1use serde::{Deserialize, Serialize};
2
3pub use self::{input::*, mask::*, set::*};
4use crate::{
5    api::{Form, Method, Payload},
6    types::{
7        ChatId,
8        File,
9        InputFile,
10        Integer,
11        Message,
12        PhotoSize,
13        ReplyMarkup,
14        ReplyMarkupError,
15        ReplyParameters,
16        ReplyParametersError,
17        SuggestedPostParameters,
18        SuggestedPostParametersError,
19    },
20};
21
22mod input;
23mod mask;
24mod set;
25
26/// Represents a sticker.
27#[serde_with::skip_serializing_none]
28#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
29pub struct Sticker {
30    /// Identifier of the file.
31    ///
32    /// Can be used to download or reuse the file.
33    pub file_id: String,
34    /// Unique identifier of the file.
35    ///
36    /// It is supposed to be the same over time and for different bots.
37    /// Can't be used to download or reuse the file.
38    pub file_unique_id: String,
39    /// Sticker height.
40    pub height: Integer,
41    /// Indicates whether the sticker is animated.
42    pub is_animated: bool,
43    /// Indicates whether the sticker is a video sticker.
44    pub is_video: bool,
45    /// Type of the sticker.
46    ///
47    /// The type of the sticker is independent from its format,
48    /// which is determined by the fields `is_animated` and `is_video`.
49    #[serde(rename = "type")]
50    pub sticker_type: StickerType,
51    /// Sticker width.
52    pub width: Integer,
53    /// For custom emoji stickers, unique identifier of the custom emoji.
54    pub custom_emoji_id: Option<String>,
55    /// Emoji associated with the sticker.
56    pub emoji: Option<String>,
57    /// File size in bytes.
58    pub file_size: Option<Integer>,
59    /// For mask stickers, the position where the mask should be placed.
60    pub mask_position: Option<MaskPosition>,
61    /// Indicates whether the sticker must be repainted to a text color in messages,
62    /// the color of the Telegram Premium badge in emoji status,
63    /// white color on chat photos, or another appropriate color in other places.
64    pub needs_repainting: Option<bool>,
65    /// For premium regular stickers, premium animation for the sticker.
66    pub premium_animation: Option<File>,
67    /// Name of the sticker set to which the sticker belongs.
68    pub set_name: Option<String>,
69    /// Sticker thumbnail in the WEBP or JPEG format.
70    pub thumbnail: Option<PhotoSize>,
71}
72
73impl Sticker {
74    /// Creates a new `Sticker`.
75    ///
76    /// # Arguments
77    ///
78    /// * `file_id` - Identifier for the file.
79    /// * `file_unique_id` - Unique identifier for the file.
80    /// * `sticker_type` - Type of the sticker.
81    /// * `height` - Sticker height.
82    /// * `width` - Sticker width.
83    pub fn new<A, B>(file_id: A, file_unique_id: B, sticker_type: StickerType, height: Integer, width: Integer) -> Self
84    where
85        A: Into<String>,
86        B: Into<String>,
87    {
88        Self {
89            file_id: file_id.into(),
90            file_unique_id: file_unique_id.into(),
91            height,
92            is_animated: false,
93            is_video: false,
94            sticker_type,
95            width,
96            custom_emoji_id: None,
97            emoji: None,
98            file_size: None,
99            mask_position: None,
100            needs_repainting: None,
101            premium_animation: None,
102            set_name: None,
103            thumbnail: None,
104        }
105    }
106
107    /// Sets a new value for the `is_animated` flag.
108    ///
109    /// # Arguments
110    ///
111    /// * `value` - Indicates whether the sticker is animated.
112    pub fn with_is_animated(mut self, value: bool) -> Self {
113        self.is_animated = value;
114        self
115    }
116
117    /// Sets a new value for the `is_video` flag.
118    ///
119    /// # Arguments
120    ///
121    /// * `value` - Indicates whether the sticker is a video sticker.
122    pub fn with_is_video(mut self, value: bool) -> Self {
123        self.is_video = value;
124        self
125    }
126
127    /// Sets a new custom emoji ID.
128    ///
129    /// # Arguments
130    ///
131    /// * `value` - Custom emoji ID.
132    pub fn with_custom_emoji_id<T>(mut self, value: T) -> Self
133    where
134        T: Into<String>,
135    {
136        self.custom_emoji_id = Some(value.into());
137        self
138    }
139
140    /// Sets a new emoji.
141    ///
142    /// # Arguments
143    ///
144    /// * `value` - Emoji.
145    pub fn with_emoji<T>(mut self, value: T) -> Self
146    where
147        T: Into<String>,
148    {
149        self.emoji = Some(value.into());
150        self
151    }
152
153    /// Sets a new file size.
154    ///
155    /// # Arguments
156    ///
157    /// * `value` - File size in bytes.
158    pub fn with_file_size(mut self, value: Integer) -> Self {
159        self.file_size = Some(value);
160        self
161    }
162
163    /// Sets a new mask position.
164    ///
165    /// # Arguments
166    ///
167    /// * `value` - Mask position.
168    pub fn with_mask_position(mut self, value: MaskPosition) -> Self {
169        self.mask_position = Some(value);
170        self
171    }
172    /// Sets a new value for the `needs_repainting` flag.
173    ///
174    /// # Arguments
175    ///
176    /// * `value` - Value of the flag.
177    pub fn with_needs_repainting(mut self, value: bool) -> Self {
178        self.needs_repainting = Some(value);
179        self
180    }
181
182    /// Sets a new premium animation.
183    ///
184    /// # Arguments
185    ///
186    /// * `value` - Premium animation.
187    pub fn with_premium_animation(mut self, value: File) -> Self {
188        self.premium_animation = Some(value);
189        self
190    }
191
192    /// Sets a new sticker set name.
193    ///
194    /// # Arguments
195    ///
196    /// * `value` - Name of a sticker set.
197    pub fn with_set_name<T>(mut self, value: T) -> Self
198    where
199        T: Into<String>,
200    {
201        self.set_name = Some(value.into());
202        self
203    }
204
205    /// Sets a new thumbnail.
206    ///
207    /// # Arguments
208    ///
209    /// * `value` - Thumbnail.
210    pub fn with_thumbnail(mut self, value: PhotoSize) -> Self {
211        self.thumbnail = Some(value);
212        self
213    }
214}
215
216/// Represents a format of stickers in the set.
217#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
218#[serde(rename_all = "snake_case")]
219pub enum StickerFormat {
220    /// PNG or WEBP.
221    Static,
222    /// TGS.
223    Animated,
224    /// WEBM.
225    Video,
226}
227
228impl AsRef<str> for StickerFormat {
229    fn as_ref(&self) -> &str {
230        match self {
231            Self::Static => "static",
232            Self::Animated => "animated",
233            Self::Video => "video",
234        }
235    }
236}
237
238/// Represents a type of stickers in the set.
239#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize)]
240#[serde(rename_all = "snake_case")]
241pub enum StickerType {
242    /// Sticker contains a custom emoji.
243    CustomEmoji,
244    /// Sticker contains a mask.
245    Mask,
246    /// Regular sticker.
247    Regular,
248}
249
250impl AsRef<str> for StickerType {
251    fn as_ref(&self) -> &str {
252        match self {
253            Self::CustomEmoji => "custom_emoji",
254            Self::Mask => "mask",
255            Self::Regular => "regular",
256        }
257    }
258}
259
260/// Returns information about custom emoji stickers by their identifiers.
261#[derive(Clone, Debug, Serialize)]
262pub struct GetCustomEmojiStickers {
263    custom_emoji_ids: Vec<String>,
264}
265
266impl GetCustomEmojiStickers {
267    /// Creates a new `GetCustomEmojiStickers`.
268    ///
269    /// # Arguments
270    ///
271    /// * `custom_emoji_ids` - List of custom emoji identifiers; at most 200 custom emoji identifiers can be specified.
272    pub fn new<A, B>(custom_emoji_ids: A) -> Self
273    where
274        A: IntoIterator<Item = B>,
275        B: Into<String>,
276    {
277        Self {
278            custom_emoji_ids: custom_emoji_ids.into_iter().map(Into::into).collect(),
279        }
280    }
281}
282
283impl Method for GetCustomEmojiStickers {
284    type Response = Vec<Sticker>;
285
286    fn into_payload(self) -> Payload {
287        Payload::json("getCustomEmojiStickers", self)
288    }
289}
290
291/// Sends a static WEBP, animated TGS, or video WEBM sticker.
292#[derive(Debug)]
293pub struct SendSticker {
294    form: Form,
295}
296
297impl SendSticker {
298    /// Creates a new `SendSticker`.
299    ///
300    /// # Arguments
301    ///
302    /// * `chat_id` - Unique identifier of the target chat.
303    /// * `sticker` - Sticker to send.
304    pub fn new<A, B>(chat_id: A, sticker: B) -> Self
305    where
306        A: Into<ChatId>,
307        B: Into<InputFile>,
308    {
309        Self {
310            form: Form::from([("chat_id", chat_id.into().into()), ("sticker", sticker.into().into())]),
311        }
312    }
313
314    /// Sets a new value for the `allow_paid_broadcast` flag.
315    ///
316    /// # Arguments
317    ///
318    /// * `value` - Whether to allow up to 1000 messages per second, ignoring broadcasting limits
319    ///   for a fee of 0.1 Telegram Stars per message.
320    ///   The relevant Stars will be withdrawn from the bot's balance.
321    pub fn with_allow_paid_broadcast(mut self, value: bool) -> Self {
322        self.form.insert_field("allow_paid_broadcast", value);
323        self
324    }
325
326    /// Sets a new business connection ID.
327    ///
328    /// # Arguments
329    ///
330    /// * `value` - Unique identifier of the business connection.
331    pub fn with_business_connection_id<T>(mut self, value: T) -> Self
332    where
333        T: Into<String>,
334    {
335        self.form.insert_field("business_connection_id", value.into());
336        self
337    }
338
339    /// Sets a new direct messages topic ID
340    ///
341    /// * `value` - Identifier of the direct messages topic to which the message will be sent.
342    ///
343    /// Required if the message is sent to a direct messages chat.
344    pub fn with_direct_messages_topic_id(mut self, value: Integer) -> Self {
345        self.form.insert_field("direct_messages_topic_id", value);
346        self
347    }
348
349    /// Sets a new value for the `disable_notification` flag.
350    ///
351    /// # Arguments
352    ///
353    /// * `value` - Indicates whether to send the message silently or not;
354    ///   a user will receive a notification without sound.
355    pub fn with_disable_notification(mut self, value: bool) -> Self {
356        self.form.insert_field("disable_notification", value);
357        self
358    }
359
360    /// Sets a new emoji.
361    ///
362    /// # Arguments
363    ///
364    /// * `value` - Emoji associated with the sticker; only for just uploaded stickers.
365    pub fn with_emoji<T>(mut self, value: T) -> Self
366    where
367        T: Into<String>,
368    {
369        self.form.insert_field("emoji", value.into());
370        self
371    }
372
373    /// Sets a new message effect ID.
374    ///
375    /// # Arguments
376    ///
377    /// * `value` - Unique identifier of the message effect to be added to the message; for private chats only.
378    pub fn with_message_effect_id<T>(mut self, value: T) -> Self
379    where
380        T: Into<String>,
381    {
382        self.form.insert_field("message_effect_id", value.into());
383        self
384    }
385
386    /// Sets a new message thread ID.
387    ///
388    /// # Arguments
389    ///
390    /// * `value` - Unique identifier of the target message thread;
391    ///   supergroups only.
392    pub fn with_message_thread_id(mut self, value: Integer) -> Self {
393        self.form.insert_field("message_thread_id", value);
394        self
395    }
396
397    /// Sets a new value for the `protect_content` flag.
398    ///
399    /// # Arguments
400    ///
401    /// * `value` - Indicates whether to protect the contents
402    ///   of the sent message from forwarding and saving.
403    pub fn with_protect_content(mut self, value: bool) -> Self {
404        self.form.insert_field("protect_content", value.to_string());
405        self
406    }
407
408    /// Sets a new reply markup.
409    ///
410    /// # Arguments
411    ///
412    /// * `value` - Reply markup.
413    pub fn with_reply_markup<T>(mut self, value: T) -> Result<Self, ReplyMarkupError>
414    where
415        T: Into<ReplyMarkup>,
416    {
417        let value = value.into();
418        self.form.insert_field("reply_markup", value.serialize()?);
419        Ok(self)
420    }
421
422    /// Sets new reply parameters.
423    ///
424    /// # Arguments
425    ///
426    /// * `value` - Description of the message to reply to.
427    pub fn with_reply_parameters(mut self, value: ReplyParameters) -> Result<Self, ReplyParametersError> {
428        self.form.insert_field("reply_parameters", value.serialize()?);
429        Ok(self)
430    }
431
432    /// Sets a new suggested post parameters.
433    ///
434    /// # Arguments
435    ///
436    /// * `value` - An object containing the parameters of the suggested post to send.
437    ///
438    /// For direct messages chats only.
439    ///
440    /// If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
441    pub fn with_suggested_post_parameters(
442        mut self,
443        value: &SuggestedPostParameters,
444    ) -> Result<Self, SuggestedPostParametersError> {
445        let value = serde_json::to_string(value).map_err(SuggestedPostParametersError::Serialize)?;
446        self.form.insert_field("suggested_post_parameters", value);
447        Ok(self)
448    }
449}
450
451impl Method for SendSticker {
452    type Response = Message;
453
454    fn into_payload(self) -> Payload {
455        Payload::form("sendSticker", self.form)
456    }
457}
458
459/// Changes the list of emoji assigned to a regular or custom emoji sticker.
460///
461/// The sticker must belong to a sticker set created by the bot.
462#[derive(Clone, Debug, Serialize)]
463pub struct SetStickerEmojiList {
464    sticker: String,
465    emoji_list: Vec<String>,
466}
467
468impl SetStickerEmojiList {
469    /// Creates a new `SetStickerEmojiList`.
470    ///
471    /// * `sticker` - File identifier of the sticker.
472    /// * `emoji_list` - A list of 1-20 emoji associated with the sticker.
473    pub fn new<A, B, C>(sticker: A, emoji_list: B) -> Self
474    where
475        A: Into<String>,
476        B: IntoIterator<Item = C>,
477        C: Into<String>,
478    {
479        Self {
480            sticker: sticker.into(),
481            emoji_list: emoji_list.into_iter().map(Into::into).collect(),
482        }
483    }
484}
485
486impl Method for SetStickerEmojiList {
487    type Response = bool;
488
489    fn into_payload(self) -> Payload {
490        Payload::json("setStickerEmojiList", self)
491    }
492}
493
494/// Changes search keywords assigned to a regular or custom emoji sticker.
495///
496/// The sticker must belong to a sticker set created by the bot.
497#[derive(Clone, Debug, Serialize)]
498pub struct SetStickerKeywords {
499    sticker: String,
500    keywords: Vec<String>,
501}
502
503impl SetStickerKeywords {
504    /// Creates a new `SetStickerKeywords`.
505    ///
506    /// * `sticker` - File identifier of the sticker.
507    /// * `keywords` - A list of 0-20 search keywords for the sticker
508    ///   with total length of up to 64 characters.
509    pub fn new<A, B, C>(sticker: A, keywords: B) -> Self
510    where
511        A: Into<String>,
512        B: IntoIterator<Item = C>,
513        C: Into<String>,
514    {
515        Self {
516            sticker: sticker.into(),
517            keywords: keywords.into_iter().map(Into::into).collect(),
518        }
519    }
520}
521
522impl Method for SetStickerKeywords {
523    type Response = bool;
524
525    fn into_payload(self) -> Payload {
526        Payload::json("setStickerKeywords", self)
527    }
528}
529
530/// Changes the mask position of a mask sticker.
531///
532/// The sticker must belong to a sticker set created by the bot.
533#[serde_with::skip_serializing_none]
534#[derive(Clone, Debug, Serialize)]
535pub struct SetStickerMaskPosition {
536    sticker: String,
537    mask_position: Option<MaskPosition>,
538}
539
540impl SetStickerMaskPosition {
541    /// Creates a new `SetStickerMaskPosition`.
542    ///
543    /// * `sticker` - File identifier of the sticker.
544    pub fn new<T>(sticker: T) -> Self
545    where
546        T: Into<String>,
547    {
548        Self {
549            sticker: sticker.into(),
550            mask_position: None,
551        }
552    }
553
554    /// Sets a new mask position.
555    ///
556    /// # Arguments
557    ///
558    /// * `value` - Position where the mask should be placed on faces.
559    ///
560    /// Omit the parameter to remove the mask position.
561    pub fn with_mask_position(mut self, value: MaskPosition) -> Self {
562        self.mask_position = Some(value);
563        self
564    }
565}
566
567impl Method for SetStickerMaskPosition {
568    type Response = bool;
569
570    fn into_payload(self) -> Payload {
571        Payload::json("setStickerMaskPosition", self)
572    }
573}
574
575/// Uploads a file with a sticker for later use in
576/// the [`CreateNewStickerSet`] and [`AddStickerToSet`] methods.
577///
578/// The file can be used multiple times.
579#[derive(Debug)]
580pub struct UploadStickerFile {
581    form: Form,
582}
583
584impl UploadStickerFile {
585    /// Creates a new `UploadStickerFile`.
586    ///
587    /// # Arguments
588    ///
589    /// * `user_id` - User identifier of sticker file owner.
590    /// * `sticker` - A file with the sticker in WEBP, PNG, TGS, or WEBM format.
591    /// * `sticker_format` - Format of the sticker.
592    pub fn new<T>(user_id: Integer, sticker: T, sticker_format: StickerFormat) -> Self
593    where
594        T: Into<InputFile>,
595    {
596        Self {
597            form: Form::from([
598                ("user_id", user_id.into()),
599                ("sticker", sticker.into().into()),
600                ("sticker_format", sticker_format.as_ref().into()),
601            ]),
602        }
603    }
604}
605
606impl Method for UploadStickerFile {
607    type Response = File;
608
609    fn into_payload(self) -> Payload {
610        Payload::form("uploadStickerFile", self.form)
611    }
612}