diff --git a/README.md b/README.md index ffcc909..e1c5561 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@

A simple, but extensible Python implementation for the Telegram Bot API.

Both synchronous and asynchronous.

-##

Supported Bot API version: 6.5! +##

Supported Bot API version: 6.6!

Official documentation

Official ru documentation

diff --git a/telebot/__init__.py b/telebot/__init__.py index f8dd488..a79bbc2 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -1837,11 +1837,12 @@ class TeleBot: parse_mode: Optional[str]=None, disable_notification: Optional[bool]=None, timeout: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, caption_entities: Optional[List[types.MessageEntity]]=None, allow_sending_without_reply: Optional[bool]=None, protect_content: Optional[bool]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + thumb: Optional[Union[Any, str]]=None,) -> types.Message: """ Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .MP3 or .M4A format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size, @@ -1887,11 +1888,11 @@ class TeleBot: :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` - :param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. + :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under - :type thumb: :obj:`str` + :type thumbnail: :obj:`str` :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode :type caption_entities: :obj:`list` of :class:`telebot.types.MessageEntity` @@ -1913,10 +1914,14 @@ class TeleBot: protect_content = self.protect_content if (protect_content is None) else protect_content allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply + if thumb is not None and thumbnail is None: + thumbnail = thumb + logger.warning('thumb is deprecated, use thumbnail instead') + return types.Message.de_json( apihelper.send_audio( self.token, chat_id, audio, caption, duration, performer, title, reply_to_message_id, - reply_markup, parse_mode, disable_notification, timeout, thumb, + reply_markup, parse_mode, disable_notification, timeout, thumbnail, caption_entities, allow_sending_without_reply, protect_content, message_thread_id)) # TODO: Rewrite this method like in API. @@ -2003,13 +2008,14 @@ class TeleBot: parse_mode: Optional[str]=None, disable_notification: Optional[bool]=None, timeout: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, caption_entities: Optional[List[types.MessageEntity]]=None, allow_sending_without_reply: Optional[bool]=None, visible_file_name: Optional[str]=None, disable_content_type_detection: Optional[bool]=None, data: Optional[Union[Any, str]]=None, - protect_content: Optional[bool]=None, message_thread_id: Optional[int]=None) -> types.Message: + protect_content: Optional[bool]=None, message_thread_id: Optional[int]=None, + thumb: Optional[Union[Any, str]]=None,) -> types.Message: """ Use this method to send general files. @@ -2042,8 +2048,8 @@ class TeleBot: :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` - :param thumb: InputFile or String : Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under - :type thumb: :obj:`str` or :class:`telebot.types.InputFile` + :param thumbnail: InputFile or String : Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under + :type thumbnail: :obj:`str` or :class:`telebot.types.InputFile` :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode :type caption_entities: :obj:`list` of :class:`telebot.types.MessageEntity` @@ -2078,11 +2084,15 @@ class TeleBot: # function typo miss compatibility document = data + if thumb is not None and thumbnail is None: + thumbnail = thumb + logger.warning('thumb is deprecated, use thumbnail instead') + return types.Message.de_json( apihelper.send_data( self.token, chat_id, document, 'document', reply_to_message_id = reply_to_message_id, reply_markup = reply_markup, parse_mode = parse_mode, - disable_notification = disable_notification, timeout = timeout, caption = caption, thumb = thumb, + disable_notification = disable_notification, timeout = timeout, caption = caption, thumb = thumbnail, caption_entities = caption_entities, allow_sending_without_reply = allow_sending_without_reply, disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name, protect_content = protect_content, message_thread_id = message_thread_id)) @@ -2099,7 +2109,8 @@ class TeleBot: allow_sending_without_reply: Optional[bool]=None, protect_content:Optional[bool]=None, data: Union[Any, str]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + emoji: Optional[str]=None) -> types.Message: """ Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. On success, the sent Message is returned. @@ -2139,6 +2150,9 @@ class TeleBot: :param message_thread_id: The thread to which the message will be sent :type message_thread_id: :obj:`int` + :param emoji: Emoji associated with the sticker; only for just uploaded stickers + :type emoji: :obj:`str` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -2156,14 +2170,14 @@ class TeleBot: reply_to_message_id=reply_to_message_id, reply_markup=reply_markup, disable_notification=disable_notification, timeout=timeout, allow_sending_without_reply=allow_sending_without_reply, - protect_content=protect_content, message_thread_id=message_thread_id)) + protect_content=protect_content, message_thread_id=message_thread_id, emoji=emoji)) def send_video( self, chat_id: Union[int, str], video: Union[Any, str], duration: Optional[int]=None, width: Optional[int]=None, height: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, @@ -2176,7 +2190,8 @@ class TeleBot: timeout: Optional[int]=None, data: Optional[Union[Any, str]]=None, message_thread_id: Optional[int]=None, - has_spoiler: Optional[bool]=None) -> types.Message: + has_spoiler: Optional[bool]=None, + thumb: Optional[Union[Any, str]]=None,) -> types.Message: """ Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). @@ -2197,8 +2212,8 @@ class TeleBot: :param height: Video height :type height: :obj:`int` - :param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . - :type thumb: :obj:`str` or :class:`telebot.types.InputFile` + :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . + :type thumbnail: :obj:`str` or :class:`telebot.types.InputFile` :param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after entities parsing :type caption: :obj:`str` @@ -2253,10 +2268,14 @@ class TeleBot: # function typo miss compatibility video = data + if thumb is not None and thumbnail is None: + thumbnail = thumb + logger.warning('thumb is deprecated, use thumbnail instead') + return types.Message.de_json( apihelper.send_video( self.token, chat_id, video, duration, caption, reply_to_message_id, reply_markup, - parse_mode, supports_streaming, disable_notification, timeout, thumb, width, height, + parse_mode, supports_streaming, disable_notification, timeout, thumbnail, width, height, caption_entities, allow_sending_without_reply, protect_content, message_thread_id, has_spoiler)) def send_animation( @@ -2264,7 +2283,7 @@ class TeleBot: duration: Optional[int]=None, width: Optional[int]=None, height: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, @@ -2275,7 +2294,8 @@ class TeleBot: reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, message_thread_id: Optional[int]=None, - has_spoiler: Optional[bool]=None) -> types.Message: + has_spoiler: Optional[bool]=None, + thumb: Optional[Union[Any, str]]=None,) -> types.Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future. @@ -2298,11 +2318,11 @@ class TeleBot: :param height: Animation height :type height: :obj:`int` - :param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. + :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . - :type thumb: :obj:`str` or :class:`telebot.types.InputFile` + :type thumbnail: :obj:`str` or :class:`telebot.types.InputFile` :param caption: Animation caption (may also be used when resending animation by file_id), 0-1024 characters after entities parsing :type caption: :obj:`str` @@ -2347,10 +2367,13 @@ class TeleBot: protect_content = self.protect_content if (protect_content is None) else protect_content allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply + if thumbnail is None and thumb is not None: + thumbnail = thumb + logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.') return types.Message.de_json( apihelper.send_animation( self.token, chat_id, animation, duration, caption, reply_to_message_id, - reply_markup, parse_mode, disable_notification, timeout, thumb, + reply_markup, parse_mode, disable_notification, timeout, thumbnail, caption_entities, allow_sending_without_reply, protect_content, width, height, message_thread_id, has_spoiler)) # TODO: Rewrite this method like in API. @@ -2362,10 +2385,11 @@ class TeleBot: reply_markup: Optional[REPLY_MARKUP_TYPES]=None, disable_notification: Optional[bool]=None, timeout: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, allow_sending_without_reply: Optional[bool]=None, protect_content: Optional[bool]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + thumb: Optional[Union[Any, str]]=None) -> types.Message: """ As of v.4.0, Telegram clients support rounded square MPEG4 videos of up to 1 minute long. Use this method to send video messages. On success, the sent Message is returned. @@ -2399,11 +2423,11 @@ class TeleBot: :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` - :param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. + :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . - :type thumb: :obj:`str` or :class:`telebot.types.InputFile` + :type thumbnail: :obj:`str` or :class:`telebot.types.InputFile` :param allow_sending_without_reply: Pass True, if the message should be sent even if the specified replied-to message is not found :type allow_sending_without_reply: :obj:`bool` @@ -2421,10 +2445,14 @@ class TeleBot: protect_content = self.protect_content if (protect_content is None) else protect_content allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply + if thumbnail is None and thumb is not None: + thumbnail = thumb + logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.') + return types.Message.de_json( apihelper.send_video_note( self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup, - disable_notification, timeout, thumb, allow_sending_without_reply, protect_content, message_thread_id)) + disable_notification, timeout, thumbnail, allow_sending_without_reply, protect_content, message_thread_id)) def send_media_group( @@ -3400,6 +3428,68 @@ class TeleBot: """ result = apihelper.get_my_commands(self.token, scope, language_code) return [types.BotCommand.de_json(cmd) for cmd in result] + + def set_my_description(self, description: Optional[str]=None, language_code: Optional[str]=None): + """ + Use this method to change the bot's description, which is shown in + the chat with the bot if the chat is empty. + Returns True on success. + + :param description: New bot description; 0-512 characters. Pass an empty string to remove the dedicated description for the given language. + :type description: :obj:`str` + + :param language_code: A two-letter ISO 639-1 language code. If empty, the description will be applied to all users for + whose language there is no dedicated description. + :type language_code: :obj:`str` + + :return: True on success. + """ + + return apihelper.set_my_description(self.token, description, language_code) + + def get_my_description(self, language_code: Optional[str]=None): + """ + Use this method to get the current bot description for the given user language. + Returns BotDescription on success. + + :param language_code: A two-letter ISO 639-1 language code or an empty string + :type language_code: :obj:`str` + + :return: :class:`telebot.types.BotDescription` + """ + + return types.BotDescription.de_json(apihelper.get_my_description(self.token, language_code)) + + def set_my_short_description(self, short_description:Optional[str]=None, language_code:Optional[str]=None): + """ + Use this method to change the bot's short description, which is shown on the bot's profile page and + is sent together with the link when users share the bot. + Returns True on success. + + :param short_description: New short description for the bot; 0-120 characters. Pass an empty string to remove the dedicated short description for the given language. + :type short_description: :obj:`str` + + :param language_code: A two-letter ISO 639-1 language code. + If empty, the short description will be applied to all users for whose language there is no dedicated short description. + :type language_code: :obj:`str` + + :return: True on success. + """ + + return apihelper.set_my_short_description(self.token, short_description, language_code) + + def get_my_short_description(self, language_code: Optional[str]=None): + """ + Use this method to get the current bot short description for the given user language. + Returns BotShortDescription on success. + + :param language_code: A two-letter ISO 639-1 language code or an empty string + :type language_code: :obj:`str` + + :return: :class:`telebot.types.BotShortDescription` + """ + + return types.BotShortDescription.de_json(apihelper.get_my_short_description(self.token, language_code)) def set_chat_menu_button(self, chat_id: Union[int, str]=None, menu_button: types.MenuButton=None) -> bool: @@ -4447,7 +4537,7 @@ class TeleBot: """ return apihelper.answer_callback_query(self.token, callback_query_id, text, show_alert, url, cache_time) - def set_sticker_set_thumb( + def set_sticker_set_thumbnail( self, name: str, user_id: int, thumb: Union[Any, str]=None): """ Use this method to set the thumbnail of a sticker set. @@ -4468,6 +4558,8 @@ class TeleBot: :rtype: :obj:`bool` """ return apihelper.set_sticker_set_thumb(self.token, name, user_id, thumb) + + set_sticker_set_thumb = set_sticker_set_thumbnail def get_sticker_set(self, name: str) -> types.StickerSet: """ @@ -4497,8 +4589,107 @@ class TeleBot: """ result = apihelper.get_custom_emoji_stickers(self.token, custom_emoji_ids) return [types.Sticker.de_json(sticker) for sticker in result] + + def set_sticker_keywords(self, sticker: str, keywords: List[str]=None) -> bool: + """ + Use this method to change search keywords assigned to a regular or custom emoji sticker. + The sticker must belong to a sticker set created by the bot. + Returns True on success. - def upload_sticker_file(self, user_id: int, png_sticker: Union[Any, str]) -> types.File: + :param sticker: File identifier of the sticker. + :type sticker: :obj:`str` + + :param keywords: A JSON-serialized list of 0-20 search keywords for the sticker with total length of up to 64 characters + :type keywords: :obj:`list` of :obj:`str` + + :return: On success, True is returned. + :rtype: :obj:`bool` + """ + return apihelper.set_sticker_keywords(self.token, sticker, keywords) + + def set_sticker_mask_position(self, sticker: str, mask_position: types.MaskPosition=None) -> bool: + """ + Use this method to change the mask position of a mask sticker. + The sticker must belong to a sticker set that was created by the bot. + Returns True on success. + + :param sticker: File identifier of the sticker. + :type sticker: :obj:`str` + + :param mask_position: A JSON-serialized object for position where the mask should be placed on faces. + :type mask_position: :class:`telebot.types.MaskPosition` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + return apihelper.set_sticker_mask_position(self.token, sticker, mask_position) + + + def set_custom_emoji_sticker_set_thumbnail(self, name: str, custom_emoji_id: Optional[str]=None) -> bool: + """ + Use this method to set the thumbnail of a custom emoji sticker set. + Returns True on success. + + :param name: Sticker set name + :type name: :obj:`str` + + :param custom_emoji_id: Custom emoji identifier of a sticker from the sticker set; pass an empty string to drop the thumbnail and use the first sticker as the thumbnail. + :type custom_emoji_id: :obj:`str` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + return apihelper.set_custom_emoji_sticker_set_thumbnail(self.token, name, custom_emoji_id) + + def set_sticker_set_title(self, name: str, title: str) -> bool: + """ + Use this method to set the title of a created sticker set. + Returns True on success. + + :param name: Sticker set name + :type name: :obj:`str` + + :param title: New sticker set title + :type title: :obj:`str` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + + return apihelper.set_sticker_set_title(self.token, name, title) + + def delete_sticker_set(self, name:str) -> bool: + """ + Use this method to delete a sticker set. Returns True on success. + + :param name: Sticker set name + :type name: :obj:`str` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + + return apihelper.delete_sticker_set(self.token, name) + + def set_sticker_emoji_list(self, sticker: str, emoji_list: List[str]) -> bool: + """ + Use this method to set the emoji list of a custom emoji sticker set. + Returns True on success. + + :param sticker: Sticker identifier + :type sticker: :obj:`str` + + :param emoji_list: List of emoji + :type emoji_list: :obj:`list` of :obj:`str` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + + return apihelper.set_sticker_emoji_list(self.token, sticker, emoji_list) + + + def upload_sticker_file(self, user_id: int, png_sticker: Union[Any, str]=None, sticker: Optional[types.InputFile]=None, sticker_format: Optional[str]=None) -> types.File: """ Use this method to upload a .png file with a sticker for later use in createNewStickerSet and addStickerToSet methods (can be used multiple times). Returns the uploaded File on success. @@ -4508,25 +4699,40 @@ class TeleBot: :param user_id: User identifier of sticker set owner :type user_id: :obj:`int` - :param png_sticker: PNG image with the sticker, must be up to 512 kilobytes in size, dimensions must not exceed 512px, + :param png_sticker: DEPRECATED: PNG image with the sticker, must be up to 512 kilobytes in size, dimensions must not exceed 512px, and either width or height must be exactly 512px. :type png_sticker: :obj:`filelike object` + :param sticker: A file with the sticker in .WEBP, .PNG, .TGS, or .WEBM format. + See https://core.telegram.org/stickers for technical requirements. More information on Sending Files » + :type sticker: :class:`telebot.types.InputFile` + + :param sticker_format: One of "static", "animated", "video". + :type sticker_format: :obj:`str` + :return: On success, the sent file is returned. :rtype: :class:`telebot.types.File` """ - result = apihelper.upload_sticker_file(self.token, user_id, png_sticker) + if png_sticker: + logger.warning("png_sticker is deprecated, use sticker instead", DeprecationWarning) + sticker = png_sticker + sticker_format = "static" + + result = apihelper.upload_sticker_file(self.token, user_id, sticker, sticker_format) return types.File.de_json(result) def create_new_sticker_set( self, user_id: int, name: str, title: str, - emojis: str, + emojis: Optional[List[str]]=None, png_sticker: Union[Any, str]=None, tgs_sticker: Union[Any, str]=None, webm_sticker: Union[Any, str]=None, contains_masks: Optional[bool]=None, sticker_type: Optional[str]=None, - mask_position: Optional[types.MaskPosition]=None) -> bool: + mask_position: Optional[types.MaskPosition]=None, + needs_repainting: Optional[bool]=None, + stickers: List[types.InputSticker]=None, + sticker_format: Optional[str]=None) -> bool: """ Use this method to create new sticker set owned by a user. The bot will be able to edit the created sticker set. @@ -4534,6 +4740,9 @@ class TeleBot: Telegram documentation: https://core.telegram.org/bots/api#createnewstickerset + .. note:: + Fields *_sticker are deprecated, pass a list of stickers to stickers parameter instead. + :param user_id: User identifier of created sticker set owner :type user_id: :obj:`int` @@ -4563,38 +4772,69 @@ class TeleBot: use sticker_type instead. :type contains_masks: :obj:`bool` - :param sticker_type: Optional, Type of stickers in the set, pass “regular” or “mask”. Custom emoji sticker sets can't be created - via the Bot API at the moment. By default, a regular sticker set is created. + :param sticker_type: Type of stickers in the set, pass “regular”, “mask”, or “custom_emoji”. By default, a regular sticker set is created. :type sticker_type: :obj:`str` :param mask_position: A JSON-serialized object for position where the mask should be placed on faces :type mask_position: :class:`telebot.types.MaskPosition` + :param needs_repainting: Pass True if stickers in the sticker set must be repainted to the color of text when used in messages, + the accent color if used as emoji status, white on chat photos, or another appropriate color based on context; + for custom emoji sticker sets only + :type needs_repainting: :obj:`bool` + + :param stickers: List of stickers to be added to the set + :type stickers: :obj:`list` of :class:`telebot.types.InputSticker` + + :param sticker_format: Format of stickers in the set, must be one of “static”, “animated”, “video” + :type sticker_format: :obj:`str` + :return: On success, True is returned. :rtype: :obj:`bool` """ + if tgs_sticker: + sticker_format = 'animated' + elif webm_sticker: + sticker_format = 'video' + elif png_sticker: + sticker_format = 'static' + if contains_masks is not None: logger.warning('The parameter "contains_masks" is deprecated, use "sticker_type" instead') if sticker_type is None: sticker_type = 'mask' if contains_masks else 'regular' + if stickers is None: + stickers = png_sticker or tgs_sticker or webm_sticker + if stickers is None: + raise ValueError('You must pass at least one sticker') + stickers = [types.InputSticker(sticker=stickers, emoji_list=emojis, mask_position=mask_position)] + + + return apihelper.create_new_sticker_set( - self.token, user_id, name, title, emojis, png_sticker, tgs_sticker, - mask_position, webm_sticker, sticker_type) + self.token, user_id, name, title, stickers, sticker_format, sticker_type, needs_repainting) + def add_sticker_to_set( - self, user_id: int, name: str, emojis: str, + self, user_id: int, name: str, emojis: List[str]=None, png_sticker: Optional[Union[Any, str]]=None, tgs_sticker: Optional[Union[Any, str]]=None, webm_sticker: Optional[Union[Any, str]]=None, - mask_position: Optional[types.MaskPosition]=None) -> bool: + mask_position: Optional[types.MaskPosition]=None, + sticker: Optional[List[types.InputSticker]]=None) -> bool: """ - Use this method to add a new sticker to a set created by the bot. - It's required to pass `png_sticker` or `tgs_sticker`. + Use this method to add a new sticker to a set created by the bot. + The format of the added sticker must match the format of the other stickers in the set. + Emoji sticker sets can have up to 200 stickers. Animated and video sticker sets can have up to 50 stickers. + Static sticker sets can have up to 120 stickers. Returns True on success. Telegram documentation: https://core.telegram.org/bots/api#addstickertoset + .. note:: + **_sticker parameters are deprecated, use stickers instead + :param user_id: User identifier of created sticker set owner :type user_id: :obj:`int` @@ -4618,11 +4858,19 @@ class TeleBot: :param mask_position: A JSON-serialized object for position where the mask should be placed on faces :type mask_position: :class:`telebot.types.MaskPosition` + :param sticker: A JSON-serialized list of 1-50 initial stickers to be added to the sticker set + :type sticker: :class:`telebot.types.InputSticker` + :return: On success, True is returned. :rtype: :obj:`bool` """ + # Replaced the parameters png_sticker, tgs_sticker, webm_sticker, emojis and mask_position + if sticker is None: + sticker = png_sticker or tgs_sticker or webm_sticker + sticker = types.InputSticker(sticker, emojis, mask_position) + return apihelper.add_sticker_to_set( - self.token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker) + self.token, user_id, name, sticker) def set_sticker_position_in_set(self, sticker: str, position: int) -> bool: """ diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 17c3e41..1100ed7 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -356,7 +356,7 @@ def get_chat_member_count(token, chat_id): def set_sticker_set_thumb(token, name, user_id, thumb): - method_url = r'setStickerSetThumb' + method_url = r'setStickerSetThumbnail' payload = {'name': name, 'user_id': user_id} files = {} if thumb: @@ -697,11 +697,11 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if width: payload['width'] = width if height: @@ -748,11 +748,11 @@ def send_animation( if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if caption_entities: payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: @@ -832,11 +832,11 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_m if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply if protect_content is not None: @@ -877,11 +877,11 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if caption_entities: payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: @@ -896,7 +896,7 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, caption=None, thumb=None, caption_entities=None, allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None, - protect_content = None, message_thread_id=None): + protect_content = None, message_thread_id=None, emoji=None): method_url = get_method_by_type(data_type) payload = {'chat_id': chat_id} files = None @@ -922,11 +922,11 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if caption_entities: payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: @@ -937,6 +937,8 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m payload['disable_content_type_detection'] = disable_content_type_detection if message_thread_id: payload['message_thread_id'] = message_thread_id + if emoji: + payload['emoji'] = emoji return _make_request(token, method_url, params=payload, files=files, method='post') @@ -1152,6 +1154,39 @@ def set_chat_title(token, chat_id, title): return _make_request(token, method_url, params=payload, method='post') +def set_my_description(token, description=None, language_code=None): + method_url = r'setMyDescription' + payload = {} + if description is not None: + payload['description'] = description + if language_code is not None: + payload['language_code'] = language_code + return _make_request(token, method_url, params=payload, method='post') + + +def get_my_description(token, language_code=None): + method_url = r'getMyDescription' + payload = {} + if language_code: + payload['language_code'] = language_code + return _make_request(token, method_url, params=payload) + +def set_my_short_description(token, short_description=None, language_code=None): + method_url = r'setMyShortDescription' + payload = {} + if short_description: + payload['short_description'] = short_description + if language_code: + payload['language_code'] = language_code + return _make_request(token, method_url, params=payload, method='post') + +def get_my_short_description(token, language_code=None): + method_url = r'getMyShortDescription' + payload = {} + if language_code: + payload['language_code'] = language_code + return _make_request(token, method_url, params=payload) + def get_my_commands(token, scope=None, language_code=None): method_url = r'getMyCommands' payload = {} @@ -1584,56 +1619,88 @@ def get_sticker_set(token, name): def get_custom_emoji_stickers(token, custom_emoji_ids): method_url = r'getCustomEmojiStickers' - return _make_request(token, method_url, params={'custom_emoji_ids': custom_emoji_ids}) + return _make_request(token, method_url, params={'custom_emoji_ids': json.dumps(custom_emoji_ids)}) + +def set_sticker_keywords(token, sticker, keywords=None): + method_url = 'setStickerKeywords' + payload = {'sticker': sticker} + if keywords: + payload['keywords'] = json.dumps(keywords) + return _make_request(token, method_url, params=payload, method='post') + +def set_sticker_mask_position(token, sticker, mask_position=None): + method_url = 'setStickerMaskPosition' + payload = {'sticker': sticker} + if mask_position: + payload['mask_position'] = mask_position.to_json() + return _make_request(token, method_url, params=payload, method='post') + -def upload_sticker_file(token, user_id, png_sticker): +def upload_sticker_file(token, user_id, sticker, sticker_format): method_url = 'uploadStickerFile' - payload = {'user_id': user_id} - files = {'png_sticker': png_sticker} + payload = {'user_id': user_id, 'sticker_format': sticker_format} + files = {'sticker': sticker} return _make_request(token, method_url, params=payload, files=files, method='post') +def set_custom_emoji_sticker_set_thumbnail(token, name, custom_emoji_id=None): + method_url = 'setCustomEmojiStickerSetThumbnail' + payload = {'name': name} + if custom_emoji_id: + payload['custom_emoji_id'] = custom_emoji_id + return _make_request(token, method_url, params=payload, method='post') + + +def set_sticker_set_title(token, name, title): + method_url = 'setStickerSetTitle' + payload = {'name': name, 'title': title} + return _make_request(token, method_url, params=payload, method='post') + +def delete_sticker_set(token, name): + method_url = 'deleteStickerSet' + payload = {'name': name} + return _make_request(token, method_url, params=payload, method='post') + +def set_sticker_emoji_list(token, sticker, emoji_list): + method_url = 'setStickerEmojiList' + payload = {'sticker': sticker, 'emoji_list': json.dumps(emoji_list)} + return _make_request(token, method_url, params=payload, method='post') + def create_new_sticker_set( - token, user_id, name, title, emojis, png_sticker, tgs_sticker, - mask_position=None, webm_sticker=None, sticker_type=None): + token, user_id, name, title, stickers, sticker_format=None, sticker_type=None, needs_repainting=None): method_url = 'createNewStickerSet' - payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis} - if png_sticker: - stype = 'png_sticker' - elif webm_sticker: - stype = 'webm_sticker' - else: - stype = 'tgs_sticker' - sticker = png_sticker or tgs_sticker or webm_sticker - files = None - if not util.is_string(sticker): - files = {stype: sticker} - else: - payload[stype] = sticker - if mask_position: - payload['mask_position'] = mask_position.to_json() + payload = {'user_id': user_id, 'name': name, 'title': title} if sticker_type: payload['sticker_type'] = sticker_type + if needs_repainting: + payload['needs_repainting'] = needs_repainting + if sticker_format: + payload['sticker_format'] = sticker_format + + files = {} + lst = [] + + for sticker in stickers: + json_dict, file = sticker.convert_input_sticker() + json_dict = sticker.to_dict() + + if file: + list_keys = list(file.keys()) + files[list_keys[0]] = file[list_keys[0]] + lst.append(json_dict) + + payload['stickers'] = json.dumps(lst) + + + return _make_request(token, method_url, params=payload, files=files, method='post') -def add_sticker_to_set(token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker): +def add_sticker_to_set(token, user_id, name, sticker): method_url = 'addStickerToSet' - payload = {'user_id': user_id, 'name': name, 'emojis': emojis} - if png_sticker: - stype = 'png_sticker' - elif webm_sticker: - stype = 'webm_sticker' - else: - stype = 'tgs_sticker' - sticker = png_sticker or tgs_sticker or webm_sticker - files = None - if not util.is_string(sticker): - files = {stype: sticker} - else: - payload[stype] = sticker - if mask_position: - payload['mask_position'] = mask_position.to_json() + json_dict, files = sticker.convert_input_sticker() + payload = {'user_id': user_id, 'name': name, 'sticker': json_dict} + return _make_request(token, method_url, params=payload, files=files, method='post') diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index a75398c..63f2bdd 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -2700,11 +2700,12 @@ class AsyncTeleBot: parse_mode: Optional[str]=None, disable_notification: Optional[bool]=None, timeout: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, caption_entities: Optional[List[types.MessageEntity]]=None, allow_sending_without_reply: Optional[bool]=None, protect_content: Optional[bool]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + thumb: Optional[Union[Any, str]]=None) -> types.Message: """ Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .MP3 or .M4A format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size, @@ -2750,11 +2751,11 @@ class AsyncTeleBot: :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` - :param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. + :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under - :type thumb: :obj:`str` + :type thumbnail: :obj:`str` :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode :type caption_entities: :obj:`list` of :class:`telebot.types.MessageEntity` @@ -2776,10 +2777,14 @@ class AsyncTeleBot: protect_content = self.protect_content if (protect_content is None) else protect_content allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply + if thumb is not None and thumbnail is None: + thumbnail = thumb + logger.warning('The parameter "thumb" is deprecated, use "thumbnail" instead') + return types.Message.de_json( await asyncio_helper.send_audio( self.token, chat_id, audio, caption, duration, performer, title, reply_to_message_id, - reply_markup, parse_mode, disable_notification, timeout, thumb, + reply_markup, parse_mode, disable_notification, timeout, thumbnail, caption_entities, allow_sending_without_reply, protect_content, message_thread_id)) async def send_voice( @@ -2864,14 +2869,15 @@ class AsyncTeleBot: parse_mode: Optional[str]=None, disable_notification: Optional[bool]=None, timeout: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, caption_entities: Optional[List[types.MessageEntity]]=None, allow_sending_without_reply: Optional[bool]=None, visible_file_name: Optional[str]=None, disable_content_type_detection: Optional[bool]=None, data: Optional[Union[Any, str]]=None, protect_content: Optional[bool]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + thumb: Optional[Union[Any, str]]=None) -> types.Message: """ Use this method to send general files. @@ -2904,8 +2910,8 @@ class AsyncTeleBot: :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` - :param thumb: InputFile or String : Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under - :type thumb: :obj:`str` or :class:`telebot.types.InputFile` + :param thumbnail: InputFile or String : Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under + :type thumbnail: :obj:`str` or :class:`telebot.types.InputFile` :param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode :type caption_entities: :obj:`list` of :class:`telebot.types.MessageEntity` @@ -2940,11 +2946,15 @@ class AsyncTeleBot: # function typo miss compatibility document = data + if thumb is not None and thumbnail is None: + thumbnail = thumb + logger.warning('thumb is deprecated, use thumbnail instead') + return types.Message.de_json( await asyncio_helper.send_data( self.token, chat_id, document, 'document', reply_to_message_id = reply_to_message_id, reply_markup = reply_markup, parse_mode = parse_mode, - disable_notification = disable_notification, timeout = timeout, caption = caption, thumb = thumb, + disable_notification = disable_notification, timeout = timeout, caption = caption, thumb = thumbnail, caption_entities = caption_entities, allow_sending_without_reply = allow_sending_without_reply, disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name, protect_content = protect_content, message_thread_id = message_thread_id)) @@ -2958,7 +2968,8 @@ class AsyncTeleBot: allow_sending_without_reply: Optional[bool]=None, protect_content: Optional[bool]=None, data: Union[Any, str]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + emoji: Optional[str]=None) -> types.Message: """ Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. On success, the sent Message is returned. @@ -2998,6 +3009,9 @@ class AsyncTeleBot: :param message_thread_id: Identifier of a message thread, in which the message will be sent :type message_thread_id: :obj:`int` + :param emoji: Emoji associated with the sticker; only for just uploaded stickers + :type emoji: :obj:`str` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -3016,14 +3030,14 @@ class AsyncTeleBot: reply_to_message_id=reply_to_message_id, reply_markup=reply_markup, disable_notification=disable_notification, timeout=timeout, allow_sending_without_reply=allow_sending_without_reply, protect_content=protect_content, - message_thread_id=message_thread_id)) + message_thread_id=message_thread_id, emoji=emoji)) async def send_video( self, chat_id: Union[int, str], video: Union[Any, str], duration: Optional[int]=None, width: Optional[int]=None, height: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, @@ -3036,7 +3050,8 @@ class AsyncTeleBot: timeout: Optional[int]=None, data: Optional[Union[Any, str]]=None, message_thread_id: Optional[int]=None, - has_spoiler: Optional[bool]=None) -> types.Message: + has_spoiler: Optional[bool]=None, + thumb: Optional[Union[Any, str]]=None) -> types.Message: """ Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). @@ -3057,8 +3072,8 @@ class AsyncTeleBot: :param height: Video height :type height: :obj:`int` - :param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . - :type thumb: :obj:`str` or :class:`telebot.types.InputFile` + :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . + :type thumbnail: :obj:`str` or :class:`telebot.types.InputFile` :param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after entities parsing :type caption: :obj:`str` @@ -3114,10 +3129,14 @@ class AsyncTeleBot: logger.warning("send_sticker: data parameter is deprecated. Use video instead.") video = data + if thumb and not(thumbnail): + logger.warning("send_sticker: thumb parameter is deprecated. Use thumbnail instead.") + thumbnail = thumb + return types.Message.de_json( await asyncio_helper.send_video( self.token, chat_id, video, duration, caption, reply_to_message_id, reply_markup, - parse_mode, supports_streaming, disable_notification, timeout, thumb, width, height, + parse_mode, supports_streaming, disable_notification, timeout, thumbnail, width, height, caption_entities, allow_sending_without_reply, protect_content, message_thread_id, has_spoiler)) async def send_animation( @@ -3125,7 +3144,7 @@ class AsyncTeleBot: duration: Optional[int]=None, width: Optional[int]=None, height: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, @@ -3136,7 +3155,8 @@ class AsyncTeleBot: reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, message_thread_id: Optional[int]=None, - has_spoiler: Optional[bool]=None) -> types.Message: + has_spoiler: Optional[bool]=None, + thumb: Optional[Union[Any, str]]=None) -> types.Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future. @@ -3159,11 +3179,11 @@ class AsyncTeleBot: :param height: Animation height :type height: :obj:`int` - :param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. + :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . - :type thumb: :obj:`str` or :class:`telebot.types.InputFile` + :type thumbnail: :obj:`str` or :class:`telebot.types.InputFile` :param caption: Animation caption (may also be used when resending animation by file_id), 0-1024 characters after entities parsing :type caption: :obj:`str` @@ -3208,10 +3228,14 @@ class AsyncTeleBot: protect_content = self.protect_content if (protect_content is None) else protect_content allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply + if thumb is not None and thumbnail is None: + thumbnail = thumb + logger.warning('thumb is deprecated, use thumbnail instead') + return types.Message.de_json( await asyncio_helper.send_animation( self.token, chat_id, animation, duration, caption, reply_to_message_id, - reply_markup, parse_mode, disable_notification, timeout, thumb, + reply_markup, parse_mode, disable_notification, timeout, thumbnail, caption_entities, allow_sending_without_reply, width, height, protect_content, message_thread_id, has_spoiler)) async def send_video_note( @@ -3222,10 +3246,11 @@ class AsyncTeleBot: reply_markup: Optional[REPLY_MARKUP_TYPES]=None, disable_notification: Optional[bool]=None, timeout: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, + thumbnail: Optional[Union[Any, str]]=None, allow_sending_without_reply: Optional[bool]=None, protect_content: Optional[bool]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + thumb: Optional[Union[Any, str]]=None) -> types.Message: """ As of v.4.0, Telegram clients support rounded square MPEG4 videos of up to 1 minute long. Use this method to send video messages. On success, the sent Message is returned. @@ -3259,11 +3284,11 @@ class AsyncTeleBot: :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` - :param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. + :param thumbnail: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . - :type thumb: :obj:`str` or :class:`telebot.types.InputFile` + :type thumbnail: :obj:`str` or :class:`telebot.types.InputFile` :param allow_sending_without_reply: Pass True, if the message should be sent even if the specified replied-to message is not found :type allow_sending_without_reply: :obj:`bool` @@ -3281,10 +3306,14 @@ class AsyncTeleBot: protect_content = self.protect_content if (protect_content is None) else protect_content allow_sending_without_reply = self.allow_sending_without_reply if (allow_sending_without_reply is None) else allow_sending_without_reply + if thumb is not None and thumbnail is None: + thumbnail = thumb + logger.warning('thumb is deprecated, use thumbnail instead') + return types.Message.de_json( await asyncio_helper.send_video_note( self.token, chat_id, data, duration, length, reply_to_message_id, reply_markup, - disable_notification, timeout, thumb, allow_sending_without_reply, protect_content, message_thread_id)) + disable_notification, timeout, thumbnail, allow_sending_without_reply, protect_content, message_thread_id)) async def send_media_group( self, chat_id: Union[int, str], @@ -4238,6 +4267,68 @@ class AsyncTeleBot: """ return await asyncio_helper.delete_chat_photo(self.token, chat_id) + async def set_my_description(self, description: Optional[str]=None, language_code: Optional[str]=None): + """ + Use this method to change the bot's description, which is shown in + the chat with the bot if the chat is empty. + Returns True on success. + + :param description: New bot description; 0-512 characters. Pass an empty string to remove the dedicated description for the given language. + :type description: :obj:`str` + + :param language_code: A two-letter ISO 639-1 language code. If empty, the description will be applied to all users for + whose language there is no dedicated description. + :type language_code: :obj:`str` + + :return: True on success. + """ + + return await asyncio_helper.set_my_description(self.token, description, language_code) + + async def get_my_description(self, language_code: Optional[str]=None): + """ + Use this method to get the current bot description for the given user language. + Returns BotDescription on success. + + :param language_code: A two-letter ISO 639-1 language code or an empty string + :type language_code: :obj:`str` + + :return: :class:`telebot.types.BotDescription` + """ + result = await asyncio_helper.get_my_description(self.token, language_code) + return types.BotDescription.de_json(result) + + async def set_my_short_description(self, short_description:Optional[str]=None, language_code:Optional[str]=None): + """ + Use this method to change the bot's short description, which is shown on the bot's profile page and + is sent together with the link when users share the bot. + Returns True on success. + + :param short_description: New short description for the bot; 0-120 characters. Pass an empty string to remove the dedicated short description for the given language. + :type short_description: :obj:`str` + + :param language_code: A two-letter ISO 639-1 language code. + If empty, the short description will be applied to all users for whose language there is no dedicated short description. + :type language_code: :obj:`str` + + :return: True on success. + """ + + return await asyncio_helper.set_my_short_description(self.token, short_description, language_code) + + async def get_my_short_description(self, language_code: Optional[str]=None): + """ + Use this method to get the current bot short description for the given user language. + Returns BotShortDescription on success. + + :param language_code: A two-letter ISO 639-1 language code or an empty string + :type language_code: :obj:`str` + + :return: :class:`telebot.types.BotShortDescription` + """ + result = await asyncio_helper.get_my_short_description(self.token, language_code) + return types.BotShortDescription.de_json(result) + async def get_my_commands(self, scope: Optional[types.BotCommandScope], language_code: Optional[str]) -> List[types.BotCommand]: """ @@ -5310,7 +5401,7 @@ class AsyncTeleBot: """ return await asyncio_helper.answer_callback_query(self.token, callback_query_id, text, show_alert, url, cache_time) - async def set_sticker_set_thumb( + async def set_sticker_set_thumbnail( self, name: str, user_id: int, thumb: Union[Any, str]=None): """ Use this method to set the thumbnail of a sticker set. @@ -5331,6 +5422,8 @@ class AsyncTeleBot: :rtype: :obj:`bool` """ return await asyncio_helper.set_sticker_set_thumb(self.token, name, user_id, thumb) + + set_sticker_set_thumb = set_sticker_set_thumbnail async def get_sticker_set(self, name: str) -> types.StickerSet: """ @@ -5346,6 +5439,40 @@ class AsyncTeleBot: """ result = await asyncio_helper.get_sticker_set(self.token, name) return types.StickerSet.de_json(result) + + async def set_sticker_keywords(self, sticker: str, keywords: List[str]=None) -> bool: + """ + Use this method to change search keywords assigned to a regular or custom emoji sticker. + The sticker must belong to a sticker set created by the bot. + Returns True on success. + + :param sticker: File identifier of the sticker. + :type sticker: :obj:`str` + + :param keywords: A JSON-serialized list of 0-20 search keywords for the sticker with total length of up to 64 characters + :type keywords: :obj:`list` of :obj:`str` + + :return: On success, True is returned. + :rtype: :obj:`bool` + """ + return await asyncio_helper.set_sticker_keywords(self.token, sticker, keywords) + + async def set_sticker_mask_position(self, sticker: str, mask_position: types.MaskPosition=None) -> bool: + """ + Use this method to change the mask position of a mask sticker. + The sticker must belong to a sticker set that was created by the bot. + Returns True on success. + + :param sticker: File identifier of the sticker. + :type sticker: :obj:`str` + + :param mask_position: A JSON-serialized object for position where the mask should be placed on faces. + :type mask_position: :class:`telebot.types.MaskPosition` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + return await asyncio_helper.set_sticker_mask_position(self.token, sticker, mask_position) async def get_custom_emoji_stickers(self, custom_emoji_ids: List[str]) -> List[types.Sticker]: """ @@ -5361,7 +5488,7 @@ class AsyncTeleBot: result = await asyncio_helper.get_custom_emoji_stickers(self.token, custom_emoji_ids) return [types.Sticker.de_json(sticker) for sticker in result] - async def upload_sticker_file(self, user_id: int, png_sticker: Union[Any, str]) -> types.File: + async def upload_sticker_file(self, user_id: int, png_sticker: Union[Any, str]=None, sticker: Optional[types.InputFile]=None, sticker_format: Optional[str]=None) -> types.File: """ Use this method to upload a .png file with a sticker for later use in createNewStickerSet and addStickerToSet methods (can be used multiple times). Returns the uploaded File on success. @@ -5371,25 +5498,105 @@ class AsyncTeleBot: :param user_id: User identifier of sticker set owner :type user_id: :obj:`int` - :param png_sticker: PNG image with the sticker, must be up to 512 kilobytes in size, dimensions must not exceed 512px, + :param png_sticker: DEPRECATED: PNG image with the sticker, must be up to 512 kilobytes in size, dimensions must not exceed 512px, and either width or height must be exactly 512px. :type png_sticker: :obj:`filelike object` + :param sticker: A file with the sticker in .WEBP, .PNG, .TGS, or .WEBM format. + See https://core.telegram.org/stickers for technical requirements. More information on Sending Files » + :type sticker: :class:`telebot.types.InputFile` + + :param sticker_format: One of "static", "animated", "video". + :type sticker_format: :obj:`str` + :return: On success, the sent file is returned. :rtype: :class:`telebot.types.File` """ - result = await asyncio_helper.upload_sticker_file(self.token, user_id, png_sticker) + if png_sticker: + logger.warning("png_sticker is deprecated, use sticker instead", DeprecationWarning) + sticker = png_sticker + sticker_format = "static" + + result = await asyncio_helper.upload_sticker_file(self.token, user_id, sticker, sticker_format) return types.File.de_json(result) + + async def set_custom_emoji_sticker_set_thumbnail(self, name: str, custom_emoji_id: Optional[str]=None) -> bool: + """ + Use this method to set the thumbnail of a custom emoji sticker set. + Returns True on success. + + :param name: Sticker set name + :type name: :obj:`str` + + :param custom_emoji_id: Custom emoji identifier of a sticker from the sticker set; pass an empty string to drop the thumbnail and use the first sticker as the thumbnail. + :type custom_emoji_id: :obj:`str` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + return await asyncio_helper.set_custom_emoji_sticker_set_thumbnail(self.token, name, custom_emoji_id) + + async def set_sticker_set_title(self, name: str, title: str) -> bool: + """ + Use this method to set the title of a created sticker set. + Returns True on success. + + :param name: Sticker set name + :type name: :obj:`str` + + :param title: New sticker set title + :type title: :obj:`str` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + + return await asyncio_helper.set_sticker_set_title(self.token, name, title) + + async def delete_sticker_set(self, name:str) -> bool: + """ + Use this method to delete a sticker set. Returns True on success. + + :param name: Sticker set name + :type name: :obj:`str` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + + return await asyncio_helper.delete_sticker_set(self.token, name) + + + async def set_sticker_emoji_list(self, name: str, emoji_list: List[str]) -> bool: + """ + Use this method to set the emoji list of a sticker set. + Returns True on success. + + :param name: Sticker set name + :type name: :obj:`str` + + :param emoji_list: List of emojis + :type emoji_list: :obj:`list` of :obj:`str` + + :return: Returns True on success. + :rtype: :obj:`bool` + """ + + return await asyncio_helper.set_sticker_emoji_list(self.token, name, emoji_list) + async def create_new_sticker_set( self, user_id: int, name: str, title: str, - emojis: str, + emojis: Optional[str]=None, png_sticker: Union[Any, str]=None, tgs_sticker: Union[Any, str]=None, webm_sticker: Union[Any, str]=None, contains_masks: Optional[bool]=None, sticker_type: Optional[str]=None, - mask_position: Optional[types.MaskPosition]=None) -> bool: + mask_position: Optional[types.MaskPosition]=None, + needs_repainting: Optional[bool]=None, + stickers: List[types.InputSticker]=None, + sticker_format: Optional[str]=None) -> bool: """ Use this method to create new sticker set owned by a user. The bot will be able to edit the created sticker set. @@ -5397,6 +5604,9 @@ class AsyncTeleBot: Telegram documentation: https://core.telegram.org/bots/api#createnewstickerset + .. note:: + Fields *_sticker are deprecated, pass a list of stickers to stickers parameter instead. + :param user_id: User identifier of created sticker set owner :type user_id: :obj:`int` @@ -5426,35 +5636,62 @@ class AsyncTeleBot: use sticker_type instead. :type contains_masks: :obj:`bool` - :param sticker_type: Optional, Type of stickers in the set, pass “regular” or “mask”. Custom emoji sticker sets can't be created - via the Bot API at the moment. By default, a regular sticker set is created. + :param sticker_type: Type of stickers in the set, pass “regular”, “mask”, or “custom_emoji”. By default, a regular sticker set is created. :type sticker_type: :obj:`str` :param mask_position: A JSON-serialized object for position where the mask should be placed on faces :type mask_position: :class:`telebot.types.MaskPosition` + :param needs_repainting: Pass True if stickers in the sticker set must be repainted to the color of text when used in messages, + the accent color if used as emoji status, white on chat photos, or another appropriate color based on context; + for custom emoji sticker sets only + :type needs_repainting: :obj:`bool` + + :param stickers: List of stickers to be added to the set + :type stickers: :obj:`list` of :class:`telebot.types.InputSticker` + + :param sticker_format: Format of stickers in the set, must be one of “static”, “animated”, “video” + :type sticker_format: :obj:`str` + :return: On success, True is returned. :rtype: :obj:`bool` """ + if tgs_sticker: + sticker_format = 'animated' + elif webm_sticker: + sticker_format = 'video' + elif png_sticker: + sticker_format = 'static' + if contains_masks is not None: logger.warning('The parameter "contains_masks" is deprecated, use "sticker_type" instead') if sticker_type is None: sticker_type = 'mask' if contains_masks else 'regular' + + if stickers is None: + stickers = png_sticker or tgs_sticker or webm_sticker + if stickers is None: + raise ValueError('You must pass at least one sticker') + stickers = [types.InputSticker(sticker=stickers, emoji_list=emojis, mask_position=mask_position)] + + return await asyncio_helper.create_new_sticker_set( - self.token, user_id, name, title, emojis, png_sticker, tgs_sticker, - mask_position, webm_sticker, sticker_type) + self.token, user_id, name, title, stickers, sticker_format, sticker_type, needs_repainting) async def add_sticker_to_set( - self, user_id: int, name: str, emojis: str, + self, user_id: int, name: str, emojis: List[str]=None, png_sticker: Optional[Union[Any, str]]=None, tgs_sticker: Optional[Union[Any, str]]=None, webm_sticker: Optional[Union[Any, str]]=None, - mask_position: Optional[types.MaskPosition]=None) -> bool: + mask_position: Optional[types.MaskPosition]=None, + sticker: Optional[List[types.InputSticker]]=None) -> bool: """ - Use this method to add a new sticker to a set created by the bot. - It's required to pass `png_sticker` or `tgs_sticker`. + Use this method to add a new sticker to a set created by the bot. + The format of the added sticker must match the format of the other stickers in the set. + Emoji sticker sets can have up to 200 stickers. Animated and video sticker sets can have up to 50 stickers. + Static sticker sets can have up to 120 stickers. Returns True on success. Telegram documentation: https://core.telegram.org/bots/api#addstickertoset @@ -5482,11 +5719,21 @@ class AsyncTeleBot: :param mask_position: A JSON-serialized object for position where the mask should be placed on faces :type mask_position: :class:`telebot.types.MaskPosition` + :param sticker: A JSON-serialized list of 1-50 initial stickers to be added to the sticker set + :type sticker: :class:`telebot.types.InputSticker` + :return: On success, True is returned. :rtype: :obj:`bool` """ + # Replaced the parameters png_sticker, tgs_sticker, webm_sticker, emojis and mask_position + if sticker is None: + sticker = png_sticker or tgs_sticker or webm_sticker + if sticker is None: + raise ValueError('You must pass at least one sticker') + sticker = types.InputSticker(sticker, emojis, mask_position) + return await asyncio_helper.add_sticker_to_set( - self.token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker) + self.token, user_id, name, sticker) async def set_sticker_position_in_set(self, sticker: str, position: int) -> bool: diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 04b494f..6de7973 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -342,7 +342,7 @@ async def get_chat_member_count(token, chat_id): async def set_sticker_set_thumb(token, name, user_id, thumb): - method_url = r'setStickerSetThumb' + method_url = r'setStickerSetThumbnail' payload = {'name': name, 'user_id': user_id} files = {} if thumb: @@ -689,11 +689,11 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_to if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if width: payload['width'] = width if height: @@ -740,11 +740,11 @@ async def send_animation( if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if caption_entities: payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: @@ -824,11 +824,11 @@ async def send_video_note(token, chat_id, data, duration=None, length=None, repl if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply if protect_content is not None: @@ -869,11 +869,11 @@ async def send_audio(token, chat_id, audio, caption=None, duration=None, perform if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if caption_entities: payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: @@ -888,7 +888,7 @@ async def send_audio(token, chat_id, audio, caption=None, duration=None, perform async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, caption=None, thumb=None, caption_entities=None, allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None, protect_content=None, - message_thread_id=None): + message_thread_id=None, emoji=None): method_url = await get_method_by_type(data_type) payload = {'chat_id': chat_id} files = None @@ -914,11 +914,11 @@ async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, r if thumb: if not util.is_string(thumb): if files: - files['thumb'] = thumb + files['thumbnail'] = thumb else: - files = {'thumb': thumb} + files = {'thumbnail': thumb} else: - payload['thumb'] = thumb + payload['thumbnail'] = thumb if caption_entities: payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: @@ -929,6 +929,8 @@ async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, r payload['disable_content_type_detection'] = disable_content_type_detection if message_thread_id: payload['message_thread_id'] = message_thread_id + if emoji: + payload['emoji'] = emoji return await _process_request(token, method_url, params=payload, files=files, method='post') @@ -1138,6 +1140,37 @@ async def set_chat_title(token, chat_id, title): payload = {'chat_id': chat_id, 'title': title} return await _process_request(token, method_url, params=payload, method='post') +async def set_my_description(token, description=None, language_code=None): + method_url = r'setMyDescription' + payload = {} + if description: + payload['description'] = description + if language_code is not None: + payload['language_code'] = language_code + return await _process_request(token, method_url, params=payload, method='post') + +async def get_my_description(token, language_code=None): + method_url = r'getMyDescription' + payload = {} + if language_code: + payload['language_code'] = language_code + return await _process_request(token, method_url, params=payload) + +async def set_my_short_description(token, short_description=None, language_code=None): + method_url = r'setMyShortDescription' + payload = {} + if short_description: + payload['short_description'] = short_description + if language_code: + payload['language_code'] = language_code + return await _process_request(token, method_url, params=payload, method='post') + +async def get_my_short_description(token, language_code=None): + method_url = r'getMyShortDescription' + payload = {} + if language_code: + payload['language_code'] = language_code + return await _process_request(token, method_url, params=payload) async def get_my_commands(token, scope=None, language_code=None): method_url = r'getMyCommands' @@ -1573,60 +1606,87 @@ async def get_sticker_set(token, name): async def get_custom_emoji_stickers(token, custom_emoji_ids): method_url = r'getCustomEmojiStickers' - return await _process_request(token, method_url, params={'custom_emoji_ids': custom_emoji_ids}) + return await _process_request(token, method_url, params={'custom_emoji_ids': json.dumps(custom_emoji_ids)}) -async def upload_sticker_file(token, user_id, png_sticker): +async def set_sticker_keywords(token, sticker, keywords=None): + method_url = 'setStickerKeywords' + payload = {'sticker': sticker} + if keywords: + payload['keywords'] = json.dumps(keywords) + + return await _process_request(token, method_url, params=payload, method='post') + +async def set_sticker_mask_position(token, sticker, mask_position=None): + method_url = 'setStickerMaskPosition' + payload = {'sticker': sticker} + if mask_position: + payload['mask_position'] = mask_position.to_json() + return await _process_request(token, method_url, params=payload, method='post') + +async def upload_sticker_file(token, user_id, sticker, sticker_format): method_url = 'uploadStickerFile' - payload = {'user_id': user_id} - files = {'png_sticker': png_sticker} + payload = {'user_id': user_id, 'sticker_format': sticker_format} + files = {'sticker': sticker} return await _process_request(token, method_url, params=payload, files=files, method='post') +async def set_sticker_emoji_list(token, sticker, emoji_list): + method_url = 'setStickerEmojiList' + payload = {'sticker': sticker, 'emoji_list': json.dumps(emoji_list)} + return await _process_request(token, method_url, params=payload, method='post') + +async def delete_sticker_set(token, name): + method_url = 'deleteStickerSet' + payload = {'name': name} + return await _process_request(token, method_url, params=payload, method='post') + +async def set_custom_emoji_sticker_set_thumbnail(token, name, custom_emoji_id=None): + method_url = 'setCustomEmojiStickerSetThumbnail' + payload = {'name': name} + if custom_emoji_id: + payload['custom_emoji_id'] = custom_emoji_id + return await _process_request(token, method_url, params=payload, method='post') + + +async def set_sticker_set_title(token, name, title): + method_url = 'setStickerSetTitle' + payload = {'name': name, 'title': title} + return await _process_request(token, method_url, params=payload, method='post') async def create_new_sticker_set( - token, user_id, name, title, emojis, png_sticker, tgs_sticker, - mask_position=None, webm_sticker=None, sticker_type=None): + token, user_id, name, title, stickers, sticker_format=None, sticker_type=None, needs_repainting=None): method_url = 'createNewStickerSet' - payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis} - if png_sticker: - stype = 'png_sticker' - elif webm_sticker: - stype = 'webm_sticker' - else: - stype = 'tgs_sticker' - sticker = png_sticker or tgs_sticker or webm_sticker - files = None - if not util.is_string(sticker): - files = {stype: sticker} - else: - payload[stype] = sticker - if mask_position: - payload['mask_position'] = mask_position.to_json() + payload = {'user_id': user_id, 'name': name, 'title': title} if sticker_type: payload['sticker_type'] = sticker_type + if needs_repainting: + payload['needs_repainting'] = needs_repainting + if sticker_format: + payload['sticker_format'] = sticker_format + + files = {} + lst = [] + + for sticker in stickers: + json_dict, file = sticker.convert_input_sticker() + json_dict = sticker.to_dict() + + if file: + list_keys = list(file.keys()) + files[list_keys[0]] = file[list_keys[0]] + lst.append(json_dict) + + payload['stickers'] = json.dumps(lst) + + return await _process_request(token, method_url, params=payload, files=files, method='post') -async def add_sticker_to_set(token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker): +async def add_sticker_to_set(token, user_id, name, sticker): method_url = 'addStickerToSet' - payload = {'user_id': user_id, 'name': name, 'emojis': emojis} - if png_sticker: - stype = 'png_sticker' - elif webm_sticker: - stype = 'webm_sticker' - else: - stype = 'tgs_sticker' - files = None - sticker = png_sticker or tgs_sticker or webm_sticker + json_dict, files = sticker.convert_input_sticker() + payload = {'user_id': user_id, 'name': name, 'sticker': json_dict} + - if not util.is_string(sticker): - files = {stype: sticker} - else: - payload[stype] = sticker - if mask_position: - payload['mask_position'] = mask_position.to_json() - - if webm_sticker: - payload['webm_sticker'] = webm_sticker return await _process_request(token, method_url, params=payload, files=files, method='post') diff --git a/telebot/types.py b/telebot/types.py index cb4facb..cd7d00f 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -1552,8 +1552,8 @@ class Audio(JsonDeserializable): double-precision float type are safe for storing this value. :type file_size: :obj:`int` - :param thumb: Optional. Thumbnail of the album cover to which the music file belongs - :type thumb: :class:`telebot.types.PhotoSize` + :param thumbnail: Optional. Thumbnail of the album cover to which the music file belongs + :type thumbnail: :class:`telebot.types.PhotoSize` :return: Instance of the class :rtype: :class:`telebot.types.Audio` @@ -1562,14 +1562,14 @@ class Audio(JsonDeserializable): def de_json(cls, json_string): if json_string is None: return None obj = cls.check_json(json_string) - if 'thumb' in obj and 'file_id' in obj['thumb']: - obj['thumb'] = PhotoSize.de_json(obj['thumb']) + if 'thumbnail' in obj and 'file_id' in obj['thumbnail']: + obj['thumbnail'] = PhotoSize.de_json(obj['thumbnail']) else: - obj['thumb'] = None + obj['thumbnail'] = None return cls(**obj) def __init__(self, file_id, file_unique_id, duration, performer=None, title=None, file_name=None, mime_type=None, - file_size=None, thumb=None, **kwargs): + file_size=None, thumbnail=None, **kwargs): self.file_id: str = file_id self.file_unique_id: str = file_unique_id self.duration: int = duration @@ -1578,7 +1578,8 @@ class Audio(JsonDeserializable): self.file_name: str = file_name self.mime_type: str = mime_type self.file_size: int = file_size - self.thumb: PhotoSize = thumb + self.thumbnail: PhotoSize = thumbnail + self.thumb = thumbnail class Voice(JsonDeserializable): @@ -1635,8 +1636,8 @@ class Document(JsonDeserializable): bots. Can't be used to download or reuse the file. :type file_unique_id: :obj:`str` - :param thumb: Optional. Document thumbnail as defined by sender - :type thumb: :class:`telebot.types.PhotoSize` + :param thumbnail: Optional. Document thumbnail as defined by sender + :type thumbnail: :class:`telebot.types.PhotoSize` :param file_name: Optional. Original filename as defined by sender :type file_name: :obj:`str` @@ -1656,19 +1657,20 @@ class Document(JsonDeserializable): def de_json(cls, json_string): if json_string is None: return None obj = cls.check_json(json_string) - if 'thumb' in obj and 'file_id' in obj['thumb']: - obj['thumb'] = PhotoSize.de_json(obj['thumb']) + if 'thumbnail' in obj and 'file_id' in obj['thumbnail']: + obj['thumbnail'] = PhotoSize.de_json(obj['thumbnail']) else: - obj['thumb'] = None + obj['thumbnail'] = None return cls(**obj) - def __init__(self, file_id, file_unique_id, thumb=None, file_name=None, mime_type=None, file_size=None, **kwargs): + def __init__(self, file_id, file_unique_id, thumbnail=None, file_name=None, mime_type=None, file_size=None, **kwargs): self.file_id: str = file_id self.file_unique_id: str = file_unique_id - self.thumb: PhotoSize = thumb + self.thumbnail: PhotoSize = thumbnail self.file_name: str = file_name self.mime_type: str = mime_type self.file_size: int = file_size + self.thumb = thumbnail class Video(JsonDeserializable): @@ -1693,8 +1695,8 @@ class Video(JsonDeserializable): :param duration: Duration of the video in seconds as defined by sender :type duration: :obj:`int` - :param thumb: Optional. Video thumbnail - :type thumb: :class:`telebot.types.PhotoSize` + :param thumbnail: Optional. Video thumbnail + :type thumbnail: :class:`telebot.types.PhotoSize` :param file_name: Optional. Original filename as defined by sender :type file_name: :obj:`str` @@ -1714,20 +1716,21 @@ class Video(JsonDeserializable): def de_json(cls, json_string): if json_string is None: return None obj = cls.check_json(json_string) - if 'thumb' in obj and 'file_id' in obj['thumb']: - obj['thumb'] = PhotoSize.de_json(obj['thumb']) + if 'thumbnail' in obj and 'file_id' in obj['thumbnail']: + obj['thumbnail'] = PhotoSize.de_json(obj['thumbnail']) return cls(**obj) - def __init__(self, file_id, file_unique_id, width, height, duration, thumb=None, file_name=None, mime_type=None, file_size=None, **kwargs): + def __init__(self, file_id, file_unique_id, width, height, duration, thumbnail=None, file_name=None, mime_type=None, file_size=None, **kwargs): self.file_id: str = file_id self.file_unique_id: str = file_unique_id self.width: int = width self.height: int = height self.duration: int = duration - self.thumb: PhotoSize = thumb + self.thumbnail: PhotoSize = thumbnail self.file_name: str = file_name self.mime_type: str = mime_type self.file_size: int = file_size + self.thumb = thumbnail class VideoNote(JsonDeserializable): @@ -1749,8 +1752,8 @@ class VideoNote(JsonDeserializable): :param duration: Duration of the video in seconds as defined by sender :type duration: :obj:`int` - :param thumb: Optional. Video thumbnail - :type thumb: :class:`telebot.types.PhotoSize` + :param thumbnail: Optional. Video thumbnail + :type thumbnail: :class:`telebot.types.PhotoSize` :param file_size: Optional. File size in bytes :type file_size: :obj:`int` @@ -1762,17 +1765,18 @@ class VideoNote(JsonDeserializable): def de_json(cls, json_string): if json_string is None: return None obj = cls.check_json(json_string) - if 'thumb' in obj and 'file_id' in obj['thumb']: - obj['thumb'] = PhotoSize.de_json(obj['thumb']) + if 'thumbnail' in obj and 'file_id' in obj['thumbnail']: + obj['thumbnail'] = PhotoSize.de_json(obj['thumbnail']) return cls(**obj) - def __init__(self, file_id, file_unique_id, length, duration, thumb=None, file_size=None, **kwargs): + def __init__(self, file_id, file_unique_id, length, duration, thumbnail=None, file_size=None, **kwargs): self.file_id: str = file_id self.file_unique_id: str = file_unique_id self.length: int = length self.duration: int = duration - self.thumb: PhotoSize = thumb + self.thumbnail: PhotoSize = thumbnail self.file_size: int = file_size + self.thumb = thumbnail class Contact(JsonDeserializable): @@ -3990,27 +3994,32 @@ class InlineQueryResultArticle(InlineQueryResultBase): :param description: Optional. Short description of the result :type description: :obj:`str` - :param thumb_url: Optional. Url of the thumbnail for the result - :type thumb_url: :obj:`str` + :param thumbnail_url: Optional. Url of the thumbnail for the result + :type thumbnail_url: :obj:`str` - :param thumb_width: Optional. Thumbnail width - :type thumb_width: :obj:`int` + :param thumbnail_width: Optional. Thumbnail width + :type thumbnail_width: :obj:`int` - :param thumb_height: Optional. Thumbnail height - :type thumb_height: :obj:`int` + :param thumbnail_height: Optional. Thumbnail height + :type thumbnail_height: :obj:`int` :return: Instance of the class :rtype: :class:`telebot.types.InlineQueryResultArticle` """ def __init__(self, id, title, input_message_content, reply_markup=None, - url=None, hide_url=None, description=None, thumb_url=None, thumb_width=None, thumb_height=None): + url=None, hide_url=None, description=None, thumbnail_url=None, thumbnail_width=None, thumbnail_height=None): super().__init__('article', id, title = title, input_message_content = input_message_content, reply_markup = reply_markup) self.url = url self.hide_url = hide_url self.description = description - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height + self.thumbnail_url = thumbnail_url + self.thumbnail_width = thumbnail_width + self.thumbnail_height = thumbnail_height + + # deprecateds + self.thumb_url = thumbnail_url + self.thumb_width = thumbnail_width + self.thumb_height = thumbnail_height def to_dict(self): json_dict = super().to_dict() @@ -4020,12 +4029,12 @@ class InlineQueryResultArticle(InlineQueryResultBase): json_dict['hide_url'] = self.hide_url if self.description: json_dict['description'] = self.description - if self.thumb_url: - json_dict['thumb_url'] = self.thumb_url + if self.thumbnail_url: + json_dict['thumbnail_url'] = self.thumbnail_url if self.thumb_width: - json_dict['thumb_width'] = self.thumb_width + json_dict['thumbnail_width'] = self.thumbnail_width if self.thumb_height: - json_dict['thumb_height'] = self.thumb_height + json_dict['thumbnail_height'] = self.thumbnail_height return json_dict @@ -4044,8 +4053,8 @@ class InlineQueryResultPhoto(InlineQueryResultBase): :param photo_url: A valid URL of the photo. Photo must be in JPEG format. Photo size must not exceed 5MB :type photo_url: :obj:`str` - :param thumb_url: URL of the thumbnail for the photo - :type thumb_url: :obj:`str` + :param thumbnail_url: URL of the thumbnail for the photo + :type thumbnail_url: :obj:`str` :param photo_width: Optional. Width of the photo :type photo_width: :obj:`int` @@ -4079,21 +4088,24 @@ class InlineQueryResultPhoto(InlineQueryResultBase): :return: Instance of the class :rtype: :class:`telebot.types.InlineQueryResultPhoto` """ - def __init__(self, id, photo_url, thumb_url, photo_width=None, photo_height=None, title=None, + def __init__(self, id, photo_url, thumbnail_url, photo_width=None, photo_height=None, title=None, description=None, caption=None, caption_entities=None, parse_mode=None, reply_markup=None, input_message_content=None): super().__init__('photo', id, title = title, caption = caption, input_message_content = input_message_content, reply_markup = reply_markup, parse_mode = parse_mode, caption_entities = caption_entities) self.photo_url = photo_url - self.thumb_url = thumb_url + self.thumbnail_url = thumbnail_url self.photo_width = photo_width self.photo_height = photo_height self.description = description + # deprecateds + self.thumb_url = thumbnail_url + def to_dict(self): json_dict = super().to_dict() json_dict['photo_url'] = self.photo_url - json_dict['thumb_url'] = self.thumb_url + json_dict['thumbnail_url'] = self.thumbnail_url if self.photo_width: json_dict['photo_width'] = self.photo_width if self.photo_height: @@ -4127,12 +4139,12 @@ class InlineQueryResultGif(InlineQueryResultBase): :param gif_duration: Optional. Duration of the GIF in seconds :type gif_duration: :obj:`int` - :param thumb_url: URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result - :type thumb_url: :obj:`str` + :param thumbnail_url: URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result + :type thumbnail_url: :obj:`str` - :param thumb_mime_type: Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, or + :param thumbnail_mime_type: Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, or “video/mp4”. Defaults to “image/jpeg” - :type thumb_mime_type: :obj:`str` + :type thumbnail_mime_type: :obj:`str` :param title: Optional. Title for the result :type title: :obj:`str` @@ -4156,19 +4168,23 @@ class InlineQueryResultGif(InlineQueryResultBase): :return: Instance of the class :rtype: :class:`telebot.types.InlineQueryResultGif` """ - def __init__(self, id, gif_url, thumb_url, gif_width=None, gif_height=None, + def __init__(self, id, gif_url, thumbnail_url, gif_width=None, gif_height=None, title=None, caption=None, caption_entities=None, reply_markup=None, input_message_content=None, gif_duration=None, parse_mode=None, - thumb_mime_type=None): + thumbnail_mime_type=None): super().__init__('gif', id, title = title, caption = caption, input_message_content = input_message_content, reply_markup = reply_markup, parse_mode = parse_mode, caption_entities = caption_entities) self.gif_url = gif_url self.gif_width = gif_width self.gif_height = gif_height - self.thumb_url = thumb_url + self.thumbnail_url = thumbnail_url self.gif_duration = gif_duration - self.thumb_mime_type = thumb_mime_type + self.thumbnail_mime_type = thumbnail_mime_type + + # deprecateds + self.thumb_url = thumbnail_url + self.thumb_mime_type = thumbnail_mime_type def to_dict(self): json_dict = super().to_dict() @@ -4177,11 +4193,11 @@ class InlineQueryResultGif(InlineQueryResultBase): json_dict['gif_width'] = self.gif_width if self.gif_height: json_dict['gif_height'] = self.gif_height - json_dict['thumb_url'] = self.thumb_url + json_dict['thumbnail_url'] = self.thumbnail_url if self.gif_duration: json_dict['gif_duration'] = self.gif_duration - if self.thumb_mime_type: - json_dict['thumb_mime_type'] = self.thumb_mime_type + if self.thumbnail_mime_type: + json_dict['thumbnail_mime_type'] = self.thumbnail_mime_type return json_dict @@ -4209,12 +4225,12 @@ class InlineQueryResultMpeg4Gif(InlineQueryResultBase): :param mpeg4_duration: Optional. Video duration in seconds :type mpeg4_duration: :obj:`int` - :param thumb_url: URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result - :type thumb_url: :obj:`str` + :param thumbnail_url: URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result + :type thumbnail_url: :obj:`str` - :param thumb_mime_type: Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, or + :param thumbnail_mime_type: Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, or “video/mp4”. Defaults to “image/jpeg” - :type thumb_mime_type: :obj:`str` + :type thumbnail_mime_type: :obj:`str` :param title: Optional. Title for the result :type title: :obj:`str` @@ -4238,19 +4254,23 @@ class InlineQueryResultMpeg4Gif(InlineQueryResultBase): :return: Instance of the class :rtype: :class:`telebot.types.InlineQueryResultMpeg4Gif` """ - def __init__(self, id, mpeg4_url, thumb_url, mpeg4_width=None, mpeg4_height=None, + def __init__(self, id, mpeg4_url, thumbnail_url, mpeg4_width=None, mpeg4_height=None, title=None, caption=None, caption_entities=None, parse_mode=None, reply_markup=None, input_message_content=None, mpeg4_duration=None, - thumb_mime_type=None): + thumbnail_mime_type=None): super().__init__('mpeg4_gif', id, title = title, caption = caption, input_message_content = input_message_content, reply_markup = reply_markup, parse_mode = parse_mode, caption_entities = caption_entities) self.mpeg4_url = mpeg4_url self.mpeg4_width = mpeg4_width self.mpeg4_height = mpeg4_height - self.thumb_url = thumb_url + self.thumbnail_url = thumbnail_url self.mpeg4_duration = mpeg4_duration - self.thumb_mime_type = thumb_mime_type + self.thumbnail_mime_type = thumbnail_mime_type + + # deprecateds + self.thumb_url = thumbnail_url + self.thumb_mime_type = thumbnail_mime_type def to_dict(self): json_dict = super().to_dict() @@ -4259,11 +4279,11 @@ class InlineQueryResultMpeg4Gif(InlineQueryResultBase): json_dict['mpeg4_width'] = self.mpeg4_width if self.mpeg4_height: json_dict['mpeg4_height'] = self.mpeg4_height - json_dict['thumb_url'] = self.thumb_url + json_dict['thumbnail_url'] = self.thumbnail_url if self.mpeg4_duration: json_dict['mpeg4_duration '] = self.mpeg4_duration - if self.thumb_mime_type: - json_dict['thumb_mime_type'] = self.thumb_mime_type + if self.thumbnail_mime_type: + json_dict['thumbnail_mime_type'] = self.thumbnail_mime_type return json_dict @@ -4285,8 +4305,8 @@ class InlineQueryResultVideo(InlineQueryResultBase): :param mime_type: MIME type of the content of the video URL, “text/html” or “video/mp4” :type mime_type: :obj:`str` - :param thumb_url: URL of the thumbnail (JPEG only) for the video - :type thumb_url: :obj:`str` + :param thumbnail_url: URL of the thumbnail (JPEG only) for the video + :type thumbnail_url: :obj:`str` :param title: Title for the result :type title: :obj:`str` @@ -4324,7 +4344,7 @@ class InlineQueryResultVideo(InlineQueryResultBase): :return: Instance of the class :rtype: :class:`telebot.types.InlineQueryResultVideo` """ - def __init__(self, id, video_url, mime_type, thumb_url, + def __init__(self, id, video_url, mime_type, thumbnail_url, title, caption=None, caption_entities=None, parse_mode=None, video_width=None, video_height=None, video_duration=None, description=None, reply_markup=None, input_message_content=None): @@ -4333,17 +4353,20 @@ class InlineQueryResultVideo(InlineQueryResultBase): parse_mode = parse_mode, caption_entities = caption_entities) self.video_url = video_url self.mime_type = mime_type - self.thumb_url = thumb_url + self.thumbnail_url = thumbnail_url self.video_width = video_width self.video_height = video_height self.video_duration = video_duration self.description = description + # deprecated + self.thumb_url = thumbnail_url + def to_dict(self): json_dict = super().to_dict() json_dict['video_url'] = self.video_url json_dict['mime_type'] = self.mime_type - json_dict['thumb_url'] = self.thumb_url + json_dict['thumbnail_url'] = self.thumbnail_url if self.video_height: json_dict['video_height'] = self.video_height if self.video_duration: @@ -4515,30 +4538,36 @@ class InlineQueryResultDocument(InlineQueryResultBase): :param input_message_content: Optional. Content of the message to be sent instead of the file :type input_message_content: :class:`telebot.types.InputMessageContent` - :param thumb_url: Optional. URL of the thumbnail (JPEG only) for the file - :type thumb_url: :obj:`str` + :param thumbnail_url: Optional. URL of the thumbnail (JPEG only) for the file + :type thumbnail_url: :obj:`str` - :param thumb_width: Optional. Thumbnail width - :type thumb_width: :obj:`int` + :param thumbnail_width: Optional. Thumbnail width + :type thumbnail_width: :obj:`int` - :param thumb_height: Optional. Thumbnail height - :type thumb_height: :obj:`int` + :param thumbnail_height: Optional. Thumbnail height + :type thumbnail_height: :obj:`int` :return: Instance of the class :rtype: :class:`telebot.types.InlineQueryResultDocument` """ def __init__(self, id, title, document_url, mime_type, caption=None, caption_entities=None, parse_mode=None, description=None, reply_markup=None, input_message_content=None, - thumb_url=None, thumb_width=None, thumb_height=None): + thumbnail_url=None, thumbnail_width=None, thumbnail_height=None): super().__init__('document', id, title = title, caption = caption, input_message_content = input_message_content, reply_markup = reply_markup, parse_mode = parse_mode, caption_entities = caption_entities) self.document_url = document_url self.mime_type = mime_type self.description = description - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height + self.thumbnail_url = thumbnail_url + self.thumbnail_width = thumbnail_width + self.thumbnail_height = thumbnail_height + + # deprecated + self.thumb_url = thumbnail_url + self.thumb_width = thumbnail_width + self.thumb_height = thumbnail_height + def to_dict(self): json_dict = super().to_dict() @@ -4546,12 +4575,12 @@ class InlineQueryResultDocument(InlineQueryResultBase): json_dict['mime_type'] = self.mime_type if self.description: json_dict['description'] = self.description - if self.thumb_url: - json_dict['thumb_url'] = self.thumb_url - if self.thumb_width: - json_dict['thumb_width'] = self.thumb_width - if self.thumb_height: - json_dict['thumb_height'] = self.thumb_height + if self.thumbnail_url: + json_dict['thumbnail_url'] = self.thumbnail_url + if self.thumbnail_width: + json_dict['thumbnail_width'] = self.thumbnail_width + if self.thumbnail_height: + json_dict['thumbnail_height'] = self.thumbnail_height return json_dict @@ -4597,20 +4626,20 @@ class InlineQueryResultLocation(InlineQueryResultBase): :param input_message_content: Optional. Content of the message to be sent instead of the location :type input_message_content: :class:`telebot.types.InputMessageContent` - :param thumb_url: Optional. Url of the thumbnail for the result - :type thumb_url: :obj:`str` + :param thumbnail_url: Optional. Url of the thumbnail for the result + :type thumbnail_url: :obj:`str` - :param thumb_width: Optional. Thumbnail width - :type thumb_width: :obj:`int` + :param thumbnail_width: Optional. Thumbnail width + :type thumbnail_width: :obj:`int` - :param thumb_height: Optional. Thumbnail height - :type thumb_height: :obj:`int` + :param thumbnail_height: Optional. Thumbnail height + :type thumbnail_height: :obj:`int` :return: Instance of the class :rtype: :class:`telebot.types.InlineQueryResultLocation` """ def __init__(self, id, title, latitude, longitude, horizontal_accuracy, live_period=None, reply_markup=None, - input_message_content=None, thumb_url=None, thumb_width=None, thumb_height=None, heading=None, proximity_alert_radius = None): + input_message_content=None, thumbnail_url=None, thumbnail_width=None, thumbnail_height=None, heading=None, proximity_alert_radius = None): super().__init__('location', id, title = title, input_message_content = input_message_content, reply_markup = reply_markup) self.latitude = latitude @@ -4619,9 +4648,14 @@ class InlineQueryResultLocation(InlineQueryResultBase): self.live_period = live_period self.heading: int = heading self.proximity_alert_radius: int = proximity_alert_radius - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height + self.thumbnail_url = thumbnail_url + self.thumbnail_width = thumbnail_width + self.thumbnail_height = thumbnail_height + + # deprecated + self.thumb_url = thumbnail_url + self.thumb_width = thumbnail_width + self.thumb_height = thumbnail_height def to_dict(self): json_dict = super().to_dict() @@ -4635,12 +4669,12 @@ class InlineQueryResultLocation(InlineQueryResultBase): json_dict['heading'] = self.heading if self.proximity_alert_radius: json_dict['proximity_alert_radius'] = self.proximity_alert_radius - if self.thumb_url: - json_dict['thumb_url'] = self.thumb_url - if self.thumb_width: - json_dict['thumb_width'] = self.thumb_width - if self.thumb_height: - json_dict['thumb_height'] = self.thumb_height + if self.thumbnail_url: + json_dict['thumbnail_url'] = self.thumbnail_url + if self.thumbnail_width: + json_dict['thumbnail_width'] = self.thumbnail_width + if self.thumbnail_height: + json_dict['thumbnail_height'] = self.thumbnail_height return json_dict @@ -4687,21 +4721,21 @@ class InlineQueryResultVenue(InlineQueryResultBase): :param input_message_content: Optional. Content of the message to be sent instead of the venue :type input_message_content: :class:`telebot.types.InputMessageContent` - :param thumb_url: Optional. Url of the thumbnail for the result - :type thumb_url: :obj:`str` + :param thumbnail_url: Optional. Url of the thumbnail for the result + :type thumbnail_url: :obj:`str` - :param thumb_width: Optional. Thumbnail width - :type thumb_width: :obj:`int` + :param thumbnail_width: Optional. Thumbnail width + :type thumbnail_width: :obj:`int` - :param thumb_height: Optional. Thumbnail height - :type thumb_height: :obj:`int` + :param thumbnail_height: Optional. Thumbnail height + :type thumbnail_height: :obj:`int` :return: Instance of the class :rtype: :class:`telebot.types.InlineQueryResultVenue` """ def __init__(self, id, title, latitude, longitude, address, foursquare_id=None, foursquare_type=None, - reply_markup=None, input_message_content=None, thumb_url=None, - thumb_width=None, thumb_height=None, google_place_id=None, google_place_type=None): + reply_markup=None, input_message_content=None, thumbnail_url=None, + thumbnail_width=None, thumbnail_height=None, google_place_id=None, google_place_type=None): super().__init__('venue', id, title = title, input_message_content = input_message_content, reply_markup = reply_markup) self.latitude = latitude @@ -4711,9 +4745,15 @@ class InlineQueryResultVenue(InlineQueryResultBase): self.foursquare_type = foursquare_type self.google_place_id = google_place_id self.google_place_type = google_place_type - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height + self.thumbnail_url = thumbnail_url + self.thumbnail_width = thumbnail_width + self.thumbnail_height = thumbnail_height + + # deprecated + self.thumb_url = thumbnail_url + self.thumb_width = thumbnail_width + self.thumb_height = thumbnail_height + def to_dict(self): json_dict = super().to_dict() @@ -4728,12 +4768,12 @@ class InlineQueryResultVenue(InlineQueryResultBase): json_dict['google_place_id'] = self.google_place_id if self.google_place_type: json_dict['google_place_type'] = self.google_place_type - if self.thumb_url: - json_dict['thumb_url'] = self.thumb_url - if self.thumb_width: - json_dict['thumb_width'] = self.thumb_width - if self.thumb_height: - json_dict['thumb_height'] = self.thumb_height + if self.thumbnail_url: + json_dict['thumbnail_url'] = self.thumbnail_url + if self.thumbnail_width: + json_dict['thumbnail_width'] = self.thumbnail_width + if self.thumbnail_height: + json_dict['thumbnail_height'] = self.thumbnail_height return json_dict @@ -4767,30 +4807,37 @@ class InlineQueryResultContact(InlineQueryResultBase): :param input_message_content: Optional. Content of the message to be sent instead of the contact :type input_message_content: :class:`telebot.types.InputMessageContent` - :param thumb_url: Optional. Url of the thumbnail for the result - :type thumb_url: :obj:`str` + :param thumbnail_url: Optional. Url of the thumbnail for the result + :type thumbnail_url: :obj:`str` - :param thumb_width: Optional. Thumbnail width - :type thumb_width: :obj:`int` + :param thumbnail_width: Optional. Thumbnail width + :type thumbnail_width: :obj:`int` - :param thumb_height: Optional. Thumbnail height - :type thumb_height: :obj:`int` + :param thumbnail_height: Optional. Thumbnail height + :type thumbnail_height: :obj:`int` :return: Instance of the class :rtype: :class:`telebot.types.InlineQueryResultContact` """ def __init__(self, id, phone_number, first_name, last_name=None, vcard=None, reply_markup=None, input_message_content=None, - thumb_url=None, thumb_width=None, thumb_height=None): + thumbnail_url=None, thumbnail_width=None, thumbnail_height=None): super().__init__('contact', id, input_message_content = input_message_content, reply_markup = reply_markup) self.phone_number = phone_number self.first_name = first_name self.last_name = last_name self.vcard = vcard - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height + self.thumbnail_url = thumbnail_url + self.thumbnail_width = thumbnail_width + self.thumbnail_height = thumbnail_height + + # deprecated + self.thumb_url = thumbnail_url + self.thumb_width = thumbnail_width + self.thumb_height = thumbnail_height + + def to_dict(self): json_dict = super().to_dict() @@ -4800,12 +4847,12 @@ class InlineQueryResultContact(InlineQueryResultBase): json_dict['last_name'] = self.last_name if self.vcard: json_dict['vcard'] = self.vcard - if self.thumb_url: - json_dict['thumb_url'] = self.thumb_url - if self.thumb_width: - json_dict['thumb_width'] = self.thumb_width - if self.thumb_height: - json_dict['thumb_height'] = self.thumb_height + if self.thumbnail_url: + json_dict['thumbnail_url'] = self.thumbnail_url + if self.thumbnail_width: + json_dict['thumbnail_width'] = self.thumbnail_width + if self.thumbnail_height: + json_dict['thumbnail_height'] = self.thumbnail_height return json_dict @@ -5389,8 +5436,8 @@ class Animation(JsonDeserializable): :param duration: Duration of the video in seconds as defined by sender :type duration: :obj:`int` - :param thumb: Optional. Animation thumbnail as defined by sender - :type thumb: :class:`telebot.types.PhotoSize` + :param thumbnail: Optional. Animation thumbnail as defined by sender + :type thumbnail: :class:`telebot.types.PhotoSize` :param file_name: Optional. Original animation filename as defined by sender :type file_name: :obj:`str` @@ -5410,20 +5457,21 @@ class Animation(JsonDeserializable): def de_json(cls, json_string): if (json_string is None): return None obj = cls.check_json(json_string) - if 'thumb' in obj and 'file_id' in obj['thumb']: - obj["thumb"] = PhotoSize.de_json(obj['thumb']) + if 'thumbnail' in obj and 'file_id' in obj['thumbnail']: + obj["thumbnail"] = PhotoSize.de_json(obj['thumbnail']) else: - obj['thumb'] = None + obj['thumbnail'] = None return cls(**obj) def __init__(self, file_id, file_unique_id, width=None, height=None, duration=None, - thumb=None, file_name=None, mime_type=None, file_size=None, **kwargs): + thumbnail=None, file_name=None, mime_type=None, file_size=None, **kwargs): self.file_id: str = file_id self.file_unique_id: str = file_unique_id self.width: int = width self.height: int = height self.duration: int = duration - self.thumb: PhotoSize = thumb + self.thumbnail: PhotoSize = thumbnail + self.thumb: PhotoSize = thumbnail self.file_name: str = file_name self.mime_type: str = mime_type self.file_size: int = file_size @@ -5819,8 +5867,8 @@ class StickerSet(JsonDeserializable): :param stickers: List of all set stickers :type stickers: :obj:`list` of :class:`telebot.types.Sticker` - :param thumb: Optional. Sticker set thumbnail in the .WEBP, .TGS, or .WEBM format - :type thumb: :class:`telebot.types.PhotoSize` + :param thumbnail: Optional. Sticker set thumbnail in the .WEBP, .TGS, or .WEBM format + :type thumbnail: :class:`telebot.types.PhotoSize` :return: Instance of the class :rtype: :class:`telebot.types.StickerSet` @@ -5833,20 +5881,21 @@ class StickerSet(JsonDeserializable): for s in obj['stickers']: stickers.append(Sticker.de_json(s)) obj['stickers'] = stickers - if 'thumb' in obj and 'file_id' in obj['thumb']: - obj['thumb'] = PhotoSize.de_json(obj['thumb']) + if 'thumbnail' in obj and 'file_id' in obj['thumbnail']: + obj['thumbnail'] = PhotoSize.de_json(obj['thumbnail']) else: - obj['thumb'] = None + obj['thumbnail'] = None return cls(**obj) - def __init__(self, name, title, sticker_type, is_animated, is_video, stickers, thumb=None, **kwargs): + def __init__(self, name, title, sticker_type, is_animated, is_video, stickers, thumbnail=None, **kwargs): self.name: str = name self.title: str = title self.sticker_type: str = sticker_type self.is_animated: bool = is_animated self.is_video: bool = is_video self.stickers: List[Sticker] = stickers - self.thumb: PhotoSize = thumb + self.thumbnail: PhotoSize = thumbnail + self.thumb = thumbnail @property def contains_masks(self): @@ -5886,8 +5935,8 @@ class Sticker(JsonDeserializable): :param is_video: True, if the sticker is a video sticker :type is_video: :obj:`bool` - :param thumb: Optional. Sticker thumbnail in the .WEBP or .JPG format - :type thumb: :class:`telebot.types.PhotoSize` + :param thumbnail: Optional. Sticker thumbnail in the .WEBP or .JPG format + :type thumbnail: :class:`telebot.types.PhotoSize` :param emoji: Optional. Emoji associated with the sticker :type emoji: :obj:`str` @@ -5904,6 +5953,11 @@ class Sticker(JsonDeserializable): :param custom_emoji_id: Optional. For custom emoji stickers, unique identifier of the custom emoji :type custom_emoji_id: :obj:`str` + :param needs_repainting: Optional. True, if the sticker must be repainted to a text color in messages, + the color of the Telegram Premium badge in emoji status, white color on chat photos, or another + appropriate color in other places + :type needs_repainting: :obj:`bool` + :param file_size: Optional. File size in bytes :type file_size: :obj:`int` @@ -5915,10 +5969,10 @@ class Sticker(JsonDeserializable): def de_json(cls, json_string): if (json_string is None): return None obj = cls.check_json(json_string) - if 'thumb' in obj and 'file_id' in obj['thumb']: - obj['thumb'] = PhotoSize.de_json(obj['thumb']) + if 'thumbnail' in obj and 'file_id' in obj['thumbnail']: + obj['thumbnail'] = PhotoSize.de_json(obj['thumbnail']) else: - obj['thumb'] = None + obj['thumbnail'] = None if 'mask_position' in obj: obj['mask_position'] = MaskPosition.de_json(obj['mask_position']) if 'premium_animation' in obj: @@ -5926,8 +5980,8 @@ class Sticker(JsonDeserializable): return cls(**obj) def __init__(self, file_id, file_unique_id, type, width, height, is_animated, - is_video, thumb=None, emoji=None, set_name=None, mask_position=None, file_size=None, - premium_animation=None, custom_emoji_id=None, **kwargs): + is_video, thumbnail=None, emoji=None, set_name=None, mask_position=None, file_size=None, + premium_animation=None, custom_emoji_id=None, needs_repainting=None ,**kwargs): self.file_id: str = file_id self.file_unique_id: str = file_unique_id self.type: str = type @@ -5935,13 +5989,15 @@ class Sticker(JsonDeserializable): self.height: int = height self.is_animated: bool = is_animated self.is_video: bool = is_video - self.thumb: PhotoSize = thumb + self.thumbnail: PhotoSize = thumbnail self.emoji: str = emoji self.set_name: str = set_name self.mask_position: MaskPosition = mask_position self.file_size: int = file_size self.premium_animation: File = premium_animation self.custom_emoji_id: int = custom_emoji_id + self.needs_repainting: bool = needs_repainting + self.thumb = self.thumbnail @@ -6093,12 +6149,12 @@ class InputMediaVideo(InputMedia): multipart/form-data under name. More information on Sending Files » :type media: :obj:`str` - :param thumb: Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported + :param thumbnail: Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . More information on Sending Files » - :type thumb: InputFile or :obj:`str` + :type thumbnail: InputFile or :obj:`str` :param caption: Optional. Caption of the video to be sent, 0-1024 characters after entities parsing :type caption: :obj:`str` @@ -6129,21 +6185,22 @@ class InputMediaVideo(InputMedia): :return: Instance of the class :rtype: :class:`telebot.types.InputMediaVideo` """ - def __init__(self, media, thumb=None, caption=None, parse_mode=None, caption_entities=None, + def __init__(self, media, thumbnail=None, caption=None, parse_mode=None, caption_entities=None, width=None, height=None, duration=None, supports_streaming=None, has_spoiler=None): super(InputMediaVideo, self).__init__( type="video", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities) - self.thumb = thumb + self.thumbnail = thumbnail self.width = width self.height = height self.duration = duration self.supports_streaming = supports_streaming self.has_spoiler: Optional[bool] = has_spoiler + self.thumb = thumbnail def to_dict(self): ret = super(InputMediaVideo, self).to_dict() - if self.thumb: - ret['thumb'] = self.thumb + if self.thumbnail: + ret['thumbnail'] = self.thumbnail if self.width: ret['width'] = self.width if self.height: @@ -6201,20 +6258,21 @@ class InputMediaAnimation(InputMedia): :return: Instance of the class :rtype: :class:`telebot.types.InputMediaAnimation` """ - def __init__(self, media, thumb=None, caption=None, parse_mode=None, caption_entities=None, + def __init__(self, media, thumbnail=None, caption=None, parse_mode=None, caption_entities=None, width=None, height=None, duration=None, has_spoiler=None): super(InputMediaAnimation, self).__init__( type="animation", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities) - self.thumb = thumb + self.thumbnail = thumbnail self.width = width self.height = height self.duration = duration self.has_spoiler: Optional[bool] = has_spoiler + self.thumb = thumbnail def to_dict(self): ret = super(InputMediaAnimation, self).to_dict() - if self.thumb: - ret['thumb'] = self.thumb + if self.thumbnail: + ret['thumbnail'] = self.thumbnail if self.width: ret['width'] = self.width if self.height: @@ -6237,12 +6295,12 @@ class InputMediaAudio(InputMedia): multipart/form-data under name. More information on Sending Files » :type media: :obj:`str` - :param thumb: Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported + :param thumbnail: Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . More information on Sending Files » - :type thumb: InputFile or :obj:`str` + :type thumbnail: InputFile or :obj:`str` :param caption: Optional. Caption of the audio to be sent, 0-1024 characters after entities parsing :type caption: :obj:`str` @@ -6267,19 +6325,20 @@ class InputMediaAudio(InputMedia): :return: Instance of the class :rtype: :class:`telebot.types.InputMediaAudio` """ - def __init__(self, media, thumb=None, caption=None, parse_mode=None, caption_entities=None, + def __init__(self, media, thumbnail=None, caption=None, parse_mode=None, caption_entities=None, duration=None, performer=None, title=None): super(InputMediaAudio, self).__init__( type="audio", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities) - self.thumb = thumb + self.thumbnail = thumbnail self.duration = duration self.performer = performer self.title = title + self.thumb = thumbnail def to_dict(self): ret = super(InputMediaAudio, self).to_dict() - if self.thumb: - ret['thumb'] = self.thumb + if self.thumbnail: + ret['thumbnail'] = self.thumbnail if self.duration: ret['duration'] = self.duration if self.performer: @@ -6300,12 +6359,12 @@ class InputMediaDocument(InputMedia): multipart/form-data under name. More information on Sending Files » :type media: :obj:`str` - :param thumb: Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported + :param thumbnail: Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . More information on Sending Files » - :type thumb: InputFile or :obj:`str` + :type thumbnail: InputFile or :obj:`str` :param caption: Optional. Caption of the document to be sent, 0-1024 characters after entities parsing :type caption: :obj:`str` @@ -6325,17 +6384,18 @@ class InputMediaDocument(InputMedia): :return: Instance of the class :rtype: :class:`telebot.types.InputMediaDocument` """ - def __init__(self, media, thumb=None, caption=None, parse_mode=None, caption_entities=None, + def __init__(self, media, thumbnail=None, caption=None, parse_mode=None, caption_entities=None, disable_content_type_detection=None): super(InputMediaDocument, self).__init__( type="document", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities) - self.thumb = thumb + self.thumbnail = thumbnail self.disable_content_type_detection = disable_content_type_detection + self.thumb = thumbnail def to_dict(self): ret = super(InputMediaDocument, self).to_dict() - if self.thumb: - ret['thumb'] = self.thumb + if self.thumbnail: + ret['thumbnail'] = self.thumbnail if self.disable_content_type_detection is not None: ret['disable_content_type_detection'] = self.disable_content_type_detection return ret @@ -7296,3 +7356,110 @@ class ChatShared(JsonDeserializable): self.request_id: int = request_id self.chat_id: int = chat_id + +class BotDescription(JsonDeserializable): + """ + This object represents a bot description. + + Telegram documentation: https://core.telegram.org/bots/api#botdescription + + :param description: Bot description + :type description: :obj:`str` + + :return: Instance of the class + :rtype: :class:`telebot.types.BotDescription` + """ + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + return cls(**obj) + + def __init__(self, description: str) -> None: + self.description: str = description + + +class BotShortDescription(JsonDeserializable): + """ + This object represents a bot short description. + + Telegram documentation: https://core.telegram.org/bots/api#botshortdescription + + :param short_description: Bot short description + :type short_description: :obj:`str` + + :return: Instance of the class + :rtype: :class:`telebot.types.BotShortDescription` + """ + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + return cls(**obj) + + def __init__(self, short_description: str) -> None: + self.short_description: str = short_description + + +class InputSticker(Dictionaryable, JsonSerializable): + """ + This object describes a sticker to be added to a sticker set. + + :param sticker: The added sticker. Pass a file_id as a String to send a file that already exists on the Telegram servers, + pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. + Animated and video stickers can't be uploaded via HTTP URL. + :type sticker: :obj:`str` or :obj:`telebot.types.InputFile` + + :param emoji_list: One or more(up to 20) emoji(s) corresponding to the sticker + :type emoji_list: :obj:`list` of :obj:`str` + + :param mask_position: Optional. Position where the mask should be placed on faces. For “mask” stickers only. + :type mask_position: :class:`telebot.types.MaskPosition` + + :param keywords: Optional. List of 0-20 search keywords for the sticker with total length of up to 64 characters. + For “regular” and “custom_emoji” stickers only. + :type keywords: :obj:`list` of :obj:`str` + + :return: Instance of the class + :rtype: :class:`telebot.types.InputSticker` + """ + + def __init__(self, sticker: Union[str, InputFile], emoji_list: List[str], mask_position: Optional[MaskPosition]=None, keywords: Optional[List[str]]=None) -> None: + self.sticker: Union[str, InputFile] = sticker + self.emoji_list: List[str] = emoji_list + self.mask_position: Optional[MaskPosition] = mask_position + self.keywords: Optional[List[str]] = keywords + + if service_utils.is_string(self.sticker): + self._sticker_name = '' + self._sticker_dic = self.sticker + else: + self._sticker_name = service_utils.generate_random_token() + self._sticker_dic = 'attach://{0}'.format(self._sticker_name) + + def to_dict(self) -> dict: + json_dict = { + 'sticker': self._sticker_dic, + 'emoji_list': self.emoji_list + } + + if self.mask_position is not None: + json_dict['mask_position'] = self.mask_position.to_dict() + if self.keywords is not None: + json_dict['keywords'] = self.keywords + + return json_dict + + def to_json(self) -> str: + return json.dumps(self.to_dict()) + + def convert_input_sticker(self): + if service_utils.is_string(self.sticker): + return self.to_json(), None + + return self.to_json(), {self._sticker_name: self.sticker} + + + \ No newline at end of file diff --git a/tests/test_types.py b/tests/test_types.py index 4587a16..c696f16 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -67,9 +67,9 @@ def test_json_GroupChat(): def test_json_Document(): - json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}' + json_string = r'{"file_name":"Text File","thumbnail":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}' doc = types.Document.de_json(json_string) - assert doc.thumb is None + assert doc.thumbnail is None assert doc.file_name == 'Text File' @@ -83,23 +83,23 @@ def test_json_Message_Audio(): def test_json_Message_Sticker(): - json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "thumb": {"file_id": "AAMCBAADHQJOFL7mAAJUMF8Dj62hpmDhpRAYvkc8CtIqipolAAJ8AAPA-8cF9yxjgjkLS97A0D4iXQARtQAHbQADHy4AAhoE", "file_unique_id": "AQADwNA-Il0AAx8uAAI", "file_size": 7776, "width": 60, "height": 60}, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}' + json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "thumbnail": {"file_id": "AAMCBAADHQJOFL7mAAJUMF8Dj62hpmDhpRAYvkc8CtIqipolAAJ8AAPA-8cF9yxjgjkLS97A0D4iXQARtQAHbQADHy4AAhoE", "file_unique_id": "AQADwNA-Il0AAx8uAAI", "file_size": 7776, "width": 60, "height": 60}, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}' msg = types.Message.de_json(json_string) assert msg.sticker.height == 368 - assert msg.sticker.thumb.height == 60 + assert msg.sticker.thumbnail.height == 60 assert msg.content_type == 'sticker' -def test_json_Message_Sticker_without_thumb(): +def test_json_Message_Sticker_without_thumbnail(): json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}' msg = types.Message.de_json(json_string) assert msg.sticker.height == 368 - assert msg.sticker.thumb is None + assert msg.sticker.thumbnail is None assert msg.content_type == 'sticker' def test_json_Message_Document(): - json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":446}}' + json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumbnail":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":446}}' msg = types.Message.de_json(json_string) assert msg.document.file_name == 'Text File' assert msg.content_type == 'document' @@ -113,11 +113,11 @@ def test_json_Message_Photo(): def test_json_Message_Video(): - json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_unique_id": "AQADTeisa3QAAz1nAAI","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_unique_id": "AgADbgEAAn8VSFY","file_size":260699}}' + json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumbnail":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_unique_id": "AQADTeisa3QAAz1nAAI","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_unique_id": "AgADbgEAAn8VSFY","file_size":260699}}' msg = types.Message.de_json(json_string) assert msg.video assert msg.video.duration == 3 - assert msg.video.thumb.width == 50 + assert msg.video.thumbnail.width == 50 assert msg.content_type == 'video'