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}