Skip to main content

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    ///   for forum supergroups and private chats of bots with forum topic mode enabled 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        self.form.insert_field("suggested_post_parameters", value.serialize()?);
446        Ok(self)
447    }
448}
449
450impl Method for SendSticker {
451    type Response = Message;
452
453    fn into_payload(self) -> Payload {
454        Payload::form("sendSticker", self.form)
455    }
456}
457
458/// Changes the list of emoji assigned to a regular or custom emoji sticker.
459///
460/// The sticker must belong to a sticker set created by the bot.
461#[derive(Clone, Debug, Serialize)]
462pub struct SetStickerEmojiList {
463    sticker: String,
464    emoji_list: Vec<String>,
465}
466
467impl SetStickerEmojiList {
468    /// Creates a new `SetStickerEmojiList`.
469    ///
470    /// * `sticker` - File identifier of the sticker.
471    /// * `emoji_list` - A list of 1-20 emoji associated with the sticker.
472    pub fn new<A, B, C>(sticker: A, emoji_list: B) -> Self
473    where
474        A: Into<String>,
475        B: IntoIterator<Item = C>,
476        C: Into<String>,
477    {
478        Self {
479            sticker: sticker.into(),
480            emoji_list: emoji_list.into_iter().map(Into::into).collect(),
481        }
482    }
483}
484
485impl Method for SetStickerEmojiList {
486    type Response = bool;
487
488    fn into_payload(self) -> Payload {
489        Payload::json("setStickerEmojiList", self)
490    }
491}
492
493/// Changes search keywords assigned to a regular or custom emoji sticker.
494///
495/// The sticker must belong to a sticker set created by the bot.
496#[derive(Clone, Debug, Serialize)]
497pub struct SetStickerKeywords {
498    sticker: String,
499    keywords: Vec<String>,
500}
501
502impl SetStickerKeywords {
503    /// Creates a new `SetStickerKeywords`.
504    ///
505    /// * `sticker` - File identifier of the sticker.
506    /// * `keywords` - A list of 0-20 search keywords for the sticker
507    ///   with total length of up to 64 characters.
508    pub fn new<A, B, C>(sticker: A, keywords: B) -> Self
509    where
510        A: Into<String>,
511        B: IntoIterator<Item = C>,
512        C: Into<String>,
513    {
514        Self {
515            sticker: sticker.into(),
516            keywords: keywords.into_iter().map(Into::into).collect(),
517        }
518    }
519}
520
521impl Method for SetStickerKeywords {
522    type Response = bool;
523
524    fn into_payload(self) -> Payload {
525        Payload::json("setStickerKeywords", self)
526    }
527}
528
529/// Changes the mask position of a mask sticker.
530///
531/// The sticker must belong to a sticker set created by the bot.
532#[serde_with::skip_serializing_none]
533#[derive(Clone, Debug, Serialize)]
534pub struct SetStickerMaskPosition {
535    sticker: String,
536    mask_position: Option<MaskPosition>,
537}
538
539impl SetStickerMaskPosition {
540    /// Creates a new `SetStickerMaskPosition`.
541    ///
542    /// * `sticker` - File identifier of the sticker.
543    pub fn new<T>(sticker: T) -> Self
544    where
545        T: Into<String>,
546    {
547        Self {
548            sticker: sticker.into(),
549            mask_position: None,
550        }
551    }
552
553    /// Sets a new mask position.
554    ///
555    /// # Arguments
556    ///
557    /// * `value` - Position where the mask should be placed on faces.
558    ///
559    /// Omit the parameter to remove the mask position.
560    pub fn with_mask_position(mut self, value: MaskPosition) -> Self {
561        self.mask_position = Some(value);
562        self
563    }
564}
565
566impl Method for SetStickerMaskPosition {
567    type Response = bool;
568
569    fn into_payload(self) -> Payload {
570        Payload::json("setStickerMaskPosition", self)
571    }
572}
573
574/// Uploads a file with a sticker for later use in
575/// the [`CreateNewStickerSet`] and [`AddStickerToSet`] methods.
576///
577/// The file can be used multiple times.
578#[derive(Debug)]
579pub struct UploadStickerFile {
580    form: Form,
581}
582
583impl UploadStickerFile {
584    /// Creates a new `UploadStickerFile`.
585    ///
586    /// # Arguments
587    ///
588    /// * `user_id` - User identifier of sticker file owner.
589    /// * `sticker` - A file with the sticker in WEBP, PNG, TGS, or WEBM format.
590    /// * `sticker_format` - Format of the sticker.
591    pub fn new<T>(user_id: Integer, sticker: T, sticker_format: StickerFormat) -> Self
592    where
593        T: Into<InputFile>,
594    {
595        Self {
596            form: Form::from([
597                ("user_id", user_id.into()),
598                ("sticker", sticker.into().into()),
599                ("sticker_format", sticker_format.as_ref().into()),
600            ]),
601        }
602    }
603}
604
605impl Method for UploadStickerFile {
606    type Response = File;
607
608    fn into_payload(self) -> Payload {
609        Payload::form("uploadStickerFile", self.form)
610    }
611}