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}