diff --git a/README.md b/README.md index 82a4beb..3c6b2d5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@

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

Supports both sync and async ways.

-##

Supporting Bot API version: 5.5! +##

Supporting Bot API version: 5.6! ## Contents @@ -686,6 +686,7 @@ Result will be: ## API conformance +* ✔ [Bot API 5.6](https://core.telegram.org/bots/api#december-30-2021) * ✔ [Bot API 5.5](https://core.telegram.org/bots/api#december-7-2021) * ✔ [Bot API 5.4](https://core.telegram.org/bots/api#november-5-2021) * ➕ [Bot API 5.3](https://core.telegram.org/bots/api#june-25-2021) - ChatMember* classes are full copies of ChatMember diff --git a/telebot/__init__.py b/telebot/__init__.py index 840b047..ca93487 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -936,32 +936,35 @@ class TeleBot: def send_message( self, chat_id: Union[int, str], text: str, - disable_web_page_preview: Optional[bool]=None, - reply_to_message_id: Optional[int]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None, parse_mode: Optional[str]=None, - disable_notification: Optional[bool]=None, - timeout: Optional[int]=None, entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + disable_web_page_preview: Optional[bool]=None, + disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, + reply_to_message_id: Optional[int]=None, + allow_sending_without_reply: Optional[bool]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + timeout: Optional[int]=None) -> types.Message: """ Use this method to send text messages. + Warning: Do not send more than about 4000 characters each message, otherwise you'll risk an HTTP 414 error. If you must send more than 4000 characters, use the `split_string` or `smart_split` function in util.py. - :param chat_id: - :param text: - :param disable_web_page_preview: - :param reply_to_message_id: - :param reply_markup: - :param parse_mode: - :param disable_notification: Boolean, Optional. Sends the message silently. + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :param text: Text of the message to be sent + :param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your bot's message. + :param entities: List of special entities that appear in message text, which can be specified instead of parse_mode + :param disable_web_page_preview: Disables link previews for links in this message + :param disable_notification: Sends the message silently. Users will receive a notification with no sound. + :param protect_content: If True, the message content will be hidden for all users except for the target user + :param reply_to_message_id: If the message is a reply, ID of the original message + :param allow_sending_without_reply: Pass True, if the message should be sent even if the specified replied-to message is not found + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. :param timeout: - :param entities: - :param allow_sending_without_reply: - :return: API reply. + :return: """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -969,11 +972,12 @@ class TeleBot: apihelper.send_message( self.token, chat_id, text, disable_web_page_preview, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, - entities, allow_sending_without_reply)) + entities, allow_sending_without_reply, protect_content=protect_content)) def forward_message( self, chat_id: Union[int, str], from_chat_id: Union[int, str], - message_id: int, disable_notification: Optional[bool]=None, + message_id: int, disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, timeout: Optional[int]=None) -> types.Message: """ Use this method to forward messages of any kind. @@ -981,11 +985,12 @@ class TeleBot: :param chat_id: which chat to forward :param from_chat_id: which chat message from :param message_id: message id + :param protect_content: Protects the contents of the forwarded message from forwarding and saving :param timeout: :return: API reply. """ return types.Message.de_json( - apihelper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout)) + apihelper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content)) def copy_message( self, chat_id: Union[int, str], @@ -995,6 +1000,7 @@ class TeleBot: parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, reply_to_message_id: Optional[int]=None, allow_sending_without_reply: Optional[bool]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, @@ -1008,6 +1014,7 @@ class TeleBot: :param parse_mode: :param caption_entities: :param disable_notification: + :param protect_content: :param reply_to_message_id: :param allow_sending_without_reply: :param reply_markup: @@ -1017,7 +1024,7 @@ class TeleBot: return types.MessageID.de_json( apihelper.copy_message(self.token, chat_id, from_chat_id, message_id, caption, parse_mode, caption_entities, disable_notification, reply_to_message_id, allow_sending_without_reply, reply_markup, - timeout)) + timeout, protect_content)) def delete_message(self, chat_id: Union[int, str], message_id: int, timeout: Optional[int]=None) -> bool: @@ -1036,7 +1043,8 @@ class TeleBot: reply_to_message_id: Optional[int]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Use this method to send dices. :param chat_id: @@ -1046,35 +1054,39 @@ class TeleBot: :param reply_markup: :param timeout: :param allow_sending_without_reply: + :param protect_content: :return: Message """ return types.Message.de_json( apihelper.send_dice( self.token, chat_id, emoji, disable_notification, reply_to_message_id, - reply_markup, timeout, allow_sending_without_reply) + reply_markup, timeout, allow_sending_without_reply, protect_content) ) def send_photo( self, chat_id: Union[int, str], photo: Union[Any, str], - caption: Optional[str]=None, reply_to_message_id: Optional[int]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None, - parse_mode: Optional[str]=None, disable_notification: Optional[bool]=None, - timeout: Optional[int]=None, + caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, + reply_to_message_id: Optional[int]=None, + allow_sending_without_reply: Optional[bool]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + timeout: Optional[int]=None,) -> types.Message: """ - Use this method to send photos. + Use this method to send photos. On success, the sent Message is returned. :param chat_id: :param photo: :param caption: :param parse_mode: + :param caption_entities: :param disable_notification: + :param protect_content: :param reply_to_message_id: + :param allow_sending_without_reply: :param reply_markup: :param timeout: - :param caption_entities: - :param allow_sending_without_reply: - :return: API reply. + :return: Message """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1082,8 +1094,9 @@ class TeleBot: apihelper.send_photo( self.token, chat_id, photo, caption, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, caption_entities, - allow_sending_without_reply)) + allow_sending_without_reply, protect_content)) + # TODO: Rewrite this method like in API. def send_audio( self, chat_id: Union[int, str], audio: Union[Any, str], caption: Optional[str]=None, duration: Optional[int]=None, @@ -1095,7 +1108,8 @@ class TeleBot: timeout: Optional[int]=None, thumb: Optional[Union[Any, str]]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=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 format. @@ -1113,6 +1127,7 @@ class TeleBot: :param thumb: :param caption_entities: :param allow_sending_without_reply: + :param protect_content: :return: Message """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1121,8 +1136,9 @@ class TeleBot: apihelper.send_audio( self.token, chat_id, audio, caption, duration, performer, title, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, thumb, - caption_entities, allow_sending_without_reply)) + caption_entities, allow_sending_without_reply, protect_content)) + # TODO: Rewrite this method like in API. def send_voice( self, chat_id: Union[int, str], voice: Union[Any, str], caption: Optional[str]=None, duration: Optional[int]=None, @@ -1132,7 +1148,8 @@ class TeleBot: disable_notification: Optional[bool]=None, timeout: Optional[int]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. @@ -1147,6 +1164,7 @@ class TeleBot: :param timeout: :param caption_entities: :param allow_sending_without_reply: + :param protect_content: :return: Message """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1155,8 +1173,9 @@ class TeleBot: apihelper.send_voice( self.token, chat_id, voice, caption, duration, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, caption_entities, - allow_sending_without_reply)) + allow_sending_without_reply, protect_content)) + # TODO: Rewrite this method like in API. def send_document( self, chat_id: Union[int, str], document: Union[Any, str], reply_to_message_id: Optional[int]=None, @@ -1170,7 +1189,8 @@ class TeleBot: 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) -> types.Message: + data: Optional[Union[Any, str]]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Use this method to send general files. :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) @@ -1187,6 +1207,7 @@ class TeleBot: :param visible_file_name: allows to define file name that will be visible in the Telegram instead of original file name :param disable_content_type_detection: Disables automatic server-side content type detection for files uploaded using multipart/form-data :param data: function typo miss compatibility: do not use it + :param protect_content: :return: API reply. """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1200,15 +1221,18 @@ class TeleBot: 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, 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)) + disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name, protect_content = protect_content)) + # TODO: Rewrite this method like in API. def send_sticker( - self, chat_id: Union[int, str], data: Union[Any, str], + self, chat_id: Union[int, str], sticker: Union[Any, str], reply_to_message_id: Optional[int]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, disable_notification: Optional[bool]=None, timeout: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content:Optional[bool]=None, + data: Union[Any, str]=None) -> types.Message: """ Use this method to send .webp stickers. :param chat_id: @@ -1218,83 +1242,98 @@ class TeleBot: :param disable_notification: to disable the notification :param timeout: timeout :param allow_sending_without_reply: + :param protect_content: + :param data: function typo miss compatibility: do not use it :return: API reply. """ + if data and not(sticker): + # function typo miss compatibility + sticker = data return types.Message.de_json( apihelper.send_data( - self.token, chat_id, data, 'sticker', + self.token, chat_id, sticker, 'sticker', 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)) + allow_sending_without_reply=allow_sending_without_reply, protect_content=protect_content)) def send_video( - self, chat_id: Union[int, str], data: Union[Any, str], - duration: Optional[int]=None, - caption: Optional[str]=None, - reply_to_message_id: Optional[int]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None, - parse_mode: Optional[str]=None, - supports_streaming: Optional[bool]=None, - disable_notification: Optional[bool]=None, - timeout: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, - width: Optional[int]=None, + 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, + caption: Optional[str]=None, + parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + supports_streaming: Optional[bool]=None, + disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, + reply_to_message_id: Optional[int]=None, + allow_sending_without_reply: Optional[bool]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + timeout: Optional[int]=None, + data: Optional[Union[Any, str]]=None) -> types.Message: """ - Use this method to send video files, Telegram clients support mp4 videos. - :param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id - :param data: InputFile or String : Video to send. You can either pass a file_id as String to resend - a video that is already on the Telegram server - :param duration: Integer : Duration of sent video in seconds - :param caption: String : Video caption (may also be used when resending videos by file_id). - :param parse_mode: - :param supports_streaming: - :param reply_to_message_id: - :param reply_markup: - :param disable_notification: - :param timeout: - :param thumb: InputFile or String : Thumbnail of the file sent - :param width: - :param height: + Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :param video: Video to send. You can either pass a file_id as String to resend a video that is already on the Telegram servers, or upload a new video file using multipart/form-data. + :param duration: Duration of sent video in seconds + :param width: Video width + :param height: Video height + :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 . + :param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after entities parsing + :param parse_mode: Mode for parsing entities in the video caption :param caption_entities: + :param supports_streaming: Pass True, if the uploaded video is suitable for streaming + :param disable_notification: Sends the message silently. Users will receive a notification with no sound. + :param protect_content: + :param reply_to_message_id: If the message is a reply, ID of the original message :param allow_sending_without_reply: - :return: + :param reply_markup: + :param timeout: + :param data: function typo miss compatibility: do not use it """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode + if data and not(video): + # function typo miss compatibility + video = data return types.Message.de_json( apihelper.send_video( - self.token, chat_id, data, duration, caption, reply_to_message_id, reply_markup, + self.token, chat_id, video, duration, caption, reply_to_message_id, reply_markup, parse_mode, supports_streaming, disable_notification, timeout, thumb, width, height, - caption_entities, allow_sending_without_reply)) + caption_entities, allow_sending_without_reply, protect_content)) def send_animation( self, chat_id: Union[int, str], animation: Union[Any, str], duration: Optional[int]=None, - caption: Optional[str]=None, - reply_to_message_id: Optional[int]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None, - parse_mode: Optional[str]=None, - disable_notification: Optional[bool]=None, - timeout: Optional[int]=None, + width: Optional[int]=None, + height: Optional[int]=None, thumb: Optional[Union[Any, str]]=None, + caption: Optional[str]=None, + parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, + reply_to_message_id: Optional[int]=None, + allow_sending_without_reply: Optional[bool]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + timeout: Optional[int]=None, ) -> types.Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). :param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id :param animation: InputFile or String : Animation to send. You can either pass a file_id as String to resend an animation that is already on the Telegram server :param duration: Integer : Duration of sent video in seconds + :param width: Integer : Video width + :param height: Integer : Video height + :param thumb: InputFile or String : Thumbnail of the file sent :param caption: String : Animation caption (may also be used when resending animation by file_id). :param parse_mode: :param reply_to_message_id: :param reply_markup: :param disable_notification: :param timeout: - :param thumb: InputFile or String : Thumbnail of the file sent :param caption_entities: :param allow_sending_without_reply: :return: @@ -1305,8 +1344,9 @@ class TeleBot: apihelper.send_animation( self.token, chat_id, animation, duration, caption, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, thumb, - caption_entities, allow_sending_without_reply)) + caption_entities, allow_sending_without_reply, protect_content, width, height)) + # TODO: Rewrite this method like in API. def send_video_note( self, chat_id: Union[int, str], data: Union[Any, str], duration: Optional[int]=None, @@ -1316,7 +1356,8 @@ class TeleBot: disable_notification: Optional[bool]=None, timeout: Optional[int]=None, thumb: Optional[Union[Any, str]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. Use this method to send video messages. @@ -1331,12 +1372,13 @@ class TeleBot: :param timeout: :param thumb: InputFile or String : Thumbnail of the file sent :param allow_sending_without_reply: + :param protect_content: :return: """ 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)) + disable_notification, timeout, thumb, allow_sending_without_reply, protect_content)) def send_media_group( self, chat_id: Union[int, str], @@ -1344,6 +1386,7 @@ class TeleBot: types.InputMediaAudio, types.InputMediaDocument, types.InputMediaPhoto, types.InputMediaVideo]], disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, reply_to_message_id: Optional[int]=None, timeout: Optional[int]=None, allow_sending_without_reply: Optional[bool]=None) -> List[types.Message]: @@ -1352,6 +1395,7 @@ class TeleBot: :param chat_id: :param media: :param disable_notification: + :param protect_content: :param reply_to_message_id: :param timeout: :param allow_sending_without_reply: @@ -1359,9 +1403,11 @@ class TeleBot: """ result = apihelper.send_media_group( self.token, chat_id, media, disable_notification, reply_to_message_id, timeout, - allow_sending_without_reply) + allow_sending_without_reply, protect_content) return [types.Message.de_json(msg) for msg in result] + + # TODO: Rewrite this method like in API. def send_location( self, chat_id: Union[int, str], latitude: float, longitude: float, @@ -1373,7 +1419,8 @@ class TeleBot: horizontal_accuracy: Optional[float]=None, heading: Optional[int]=None, proximity_alert_radius: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ @@ -1390,6 +1437,7 @@ class TeleBot: :param heading: :param proximity_alert_radius: :param allow_sending_without_reply: + :param protect_content: :return: API reply. """ return types.Message.de_json( @@ -1397,7 +1445,7 @@ class TeleBot: self.token, chat_id, latitude, longitude, live_period, reply_to_message_id, reply_markup, disable_notification, timeout, horizontal_accuracy, heading, proximity_alert_radius, - allow_sending_without_reply)) + allow_sending_without_reply, protect_content)) def edit_message_live_location( self, latitude: float, longitude: float, @@ -1449,6 +1497,7 @@ class TeleBot: apihelper.stop_message_live_location( self.token, chat_id, message_id, inline_message_id, reply_markup, timeout)) + # TODO: Rewrite this method like in API. def send_venue( self, chat_id: Union[int, str], latitude: float, longitude: float, @@ -1461,7 +1510,8 @@ class TeleBot: timeout: Optional[int]=None, allow_sending_without_reply: Optional[bool]=None, google_place_id: Optional[str]=None, - google_place_type: Optional[str]=None) -> types.Message: + google_place_type: Optional[str]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Use this method to send information about a venue. :param chat_id: Integer or String : Unique identifier for the target chat or username of the target channel @@ -1479,15 +1529,16 @@ class TeleBot: :param allow_sending_without_reply: :param google_place_id: :param google_place_type: + :param protect_content: :return: """ return types.Message.de_json( apihelper.send_venue( self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type, disable_notification, reply_to_message_id, reply_markup, timeout, - allow_sending_without_reply, google_place_id, google_place_type) - ) + allow_sending_without_reply, google_place_id, google_place_type, protect_content)) + # TODO: Rewrite this method like in API. def send_contact( self, chat_id: Union[int, str], phone_number: str, first_name: str, last_name: Optional[str]=None, @@ -1496,13 +1547,13 @@ class TeleBot: reply_to_message_id: Optional[int]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: return types.Message.de_json( apihelper.send_contact( self.token, chat_id, phone_number, first_name, last_name, vcard, disable_notification, reply_to_message_id, reply_markup, timeout, - allow_sending_without_reply) - ) + allow_sending_without_reply, protect_content)) def send_chat_action( self, chat_id: Union[int, str], action: str, timeout: Optional[int]=None) -> bool: @@ -2026,7 +2077,8 @@ class TeleBot: reply_to_message_id: Optional[int]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Used to send the game :param chat_id: @@ -2036,12 +2088,13 @@ class TeleBot: :param reply_markup: :param timeout: :param allow_sending_without_reply: + :param protect_content: :return: """ result = apihelper.send_game( self.token, chat_id, game_short_name, disable_notification, reply_to_message_id, reply_markup, timeout, - allow_sending_without_reply) + allow_sending_without_reply, protect_content) return types.Message.de_json(result) def set_game_score( @@ -2083,6 +2136,7 @@ class TeleBot: result = apihelper.get_game_high_scores(self.token, user_id, chat_id, message_id, inline_message_id) return [types.GameHighScore.de_json(r) for r in result] + # TODO: rewrite this method like in API def send_invoice( self, chat_id: Union[int, str], title: str, description: str, invoice_payload: str, provider_token: str, currency: str, @@ -2101,7 +2155,8 @@ class TeleBot: timeout: Optional[int]=None, allow_sending_without_reply: Optional[bool]=None, max_tip_amount: Optional[int] = None, - suggested_tip_amounts: Optional[List[int]]=None) -> types.Message: + suggested_tip_amounts: Optional[List[int]]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Sends invoice :param chat_id: Unique identifier for the target private chat @@ -2140,6 +2195,7 @@ class TeleBot: :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency. At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount. + :param protect_content: :return: """ result = apihelper.send_invoice( @@ -2148,10 +2204,11 @@ class TeleBot: photo_height, need_name, need_phone_number, need_email, need_shipping_address, send_phone_number_to_provider, send_email_to_provider, is_flexible, disable_notification, reply_to_message_id, reply_markup, provider_data, timeout, allow_sending_without_reply, - max_tip_amount, suggested_tip_amounts) + max_tip_amount, suggested_tip_amounts, protect_content) return types.Message.de_json(result) # noinspection PyShadowingBuiltins + # TODO: rewrite this method like in API def send_poll( self, chat_id: Union[int, str], question: str, options: List[str], is_anonymous: Optional[bool]=None, type: Optional[str]=None, @@ -2167,7 +2224,8 @@ class TeleBot: reply_markup: Optional[REPLY_MARKUP_TYPES]=None, allow_sending_without_reply: Optional[bool]=None, timeout: Optional[int]=None, - explanation_entities: Optional[List[types.MessageEntity]]=None) -> types.Message: + explanation_entities: Optional[List[types.MessageEntity]]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Send polls :param chat_id: @@ -2188,6 +2246,7 @@ class TeleBot: :param reply_markup: :param timeout: :param explanation_entities: + :param protect_content: :return: """ @@ -2201,7 +2260,7 @@ class TeleBot: is_anonymous, type, allows_multiple_answers, correct_option_id, explanation, explanation_parse_mode, open_period, close_date, is_closed, disable_notification, reply_to_message_id, allow_sending_without_reply, - reply_markup, timeout, explanation_entities)) + reply_markup, timeout, explanation_entities, protect_content)) def stop_poll( self, chat_id: Union[int, str], message_id: int, diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 229fa78..3f9562d 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -232,7 +232,7 @@ def send_message( token, chat_id, text, disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, - entities=None, allow_sending_without_reply=None): + entities=None, allow_sending_without_reply=None, protect_content=None): """ Use this method to send text messages. On success, the sent Message is returned. :param token: @@ -266,6 +266,8 @@ def send_message( payload['entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload, method='post') @@ -390,19 +392,21 @@ def get_chat_member(token, chat_id, user_id): def forward_message( token, chat_id, from_chat_id, message_id, - disable_notification=None, timeout=None): + disable_notification=None, timeout=None, protect_content=None): method_url = r'forwardMessage' payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id} if disable_notification is not None: payload['disable_notification'] = disable_notification if timeout: payload['timeout'] = timeout + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload) def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None, disable_notification=None, reply_to_message_id=None, allow_sending_without_reply=None, - reply_markup=None, timeout=None): + reply_markup=None, timeout=None, protect_content=None): method_url = r'copyMessage' payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id} if caption is not None: @@ -421,13 +425,15 @@ def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_m payload['allow_sending_without_reply'] = allow_sending_without_reply if timeout: payload['timeout'] = timeout + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload) def send_dice( token, chat_id, emoji=None, disable_notification=None, reply_to_message_id=None, - reply_markup=None, timeout=None, allow_sending_without_reply=None): + reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendDice' payload = {'chat_id': chat_id} if emoji: @@ -442,6 +448,8 @@ def send_dice( payload['timeout'] = timeout if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload) @@ -449,7 +457,7 @@ def send_photo( token, chat_id, photo, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, - caption_entities=None, allow_sending_without_reply=None): + caption_entities=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendPhoto' payload = {'chat_id': chat_id} files = None @@ -475,13 +483,15 @@ def send_photo( payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload, files=files, method='post') def send_media_group( token, chat_id, media, disable_notification=None, reply_to_message_id=None, - timeout=None, allow_sending_without_reply=None): + timeout=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendMediaGroup' media_json, files = convert_input_media_array(media) payload = {'chat_id': chat_id, 'media': media_json} @@ -493,6 +503,8 @@ def send_media_group( payload['timeout'] = timeout if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request( token, method_url, params=payload, method='post' if files else 'get', @@ -504,7 +516,7 @@ def send_location( live_period=None, reply_to_message_id=None, reply_markup=None, disable_notification=None, timeout=None, horizontal_accuracy=None, heading=None, - proximity_alert_radius=None, allow_sending_without_reply=None): + proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendLocation' payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude} if live_period: @@ -525,6 +537,8 @@ def send_location( payload['disable_notification'] = disable_notification if timeout: payload['timeout'] = timeout + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload) @@ -576,7 +590,7 @@ def send_venue( foursquare_id=None, foursquare_type=None, disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None, allow_sending_without_reply=None, google_place_id=None, - google_place_type=None): + google_place_type=None, protect_content=None): method_url = r'sendVenue' payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address} if foursquare_id: @@ -597,13 +611,15 @@ def send_venue( payload['google_place_id'] = google_place_id if google_place_type: payload['google_place_type'] = google_place_type + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload) def send_contact( token, chat_id, phone_number, first_name, last_name=None, vcard=None, disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None, - allow_sending_without_reply=None): + allow_sending_without_reply=None, protect_content=None): method_url = r'sendContact' payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name} if last_name: @@ -620,6 +636,9 @@ def send_contact( payload['timeout'] = timeout if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content + return _make_request(token, method_url, params=payload) @@ -633,7 +652,7 @@ def send_chat_action(token, chat_id, action, timeout=None): def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None, - thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None): + thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendVideo' payload = {'chat_id': chat_id} files = None @@ -673,13 +692,15 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload, files=files, method='post') def send_animation( token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None, - allow_sending_without_reply=None): + allow_sending_without_reply=None, protect_content=None, width=None, height=None): method_url = r'sendAnimation' payload = {'chat_id': chat_id} files = None @@ -713,12 +734,18 @@ def send_animation( payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content + if width: + payload['width'] = width + if height: + payload['height'] = height return _make_request(token, method_url, params=payload, files=files, method='post') def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, caption_entities=None, - allow_sending_without_reply=None): + allow_sending_without_reply=None, protect_content=None): method_url = r'sendVoice' payload = {'chat_id': chat_id} files = None @@ -744,11 +771,13 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_mess payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload, files=files, method='post') def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None, - disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None): + disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendVideoNote' payload = {'chat_id': chat_id} files = None @@ -780,12 +809,14 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_m payload['thumb'] = thumb if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload, files=files, method='post') def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None, - caption_entities=None, allow_sending_without_reply=None): + caption_entities=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendAudio' payload = {'chat_id': chat_id} files = None @@ -823,6 +854,8 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload, files=files, method='post') @@ -1236,7 +1269,7 @@ def delete_message(token, chat_id, message_id, timeout=None): def send_game( token, chat_id, game_short_name, disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None, - allow_sending_without_reply=None): + allow_sending_without_reply=None, protect_content=None): method_url = r'sendGame' payload = {'chat_id': chat_id, 'game_short_name': game_short_name} if disable_notification is not None: @@ -1249,6 +1282,9 @@ def send_game( payload['timeout'] = timeout if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content + return _make_request(token, method_url, params=payload) @@ -1313,7 +1349,8 @@ def send_invoice( need_name=None, need_phone_number=None, need_email=None, need_shipping_address=None, send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None, disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None, - timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None): + timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None, + protect_content=None): """ Use this method to send invoices. On success, the sent Message is returned. :param token: Bot's token (you don't need to fill this) @@ -1391,6 +1428,8 @@ def send_invoice( payload['max_tip_amount'] = max_tip_amount if suggested_tip_amounts is not None: payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts) + if protect_content is not None: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload) @@ -1539,7 +1578,7 @@ def send_poll( is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None, explanation = None, explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None, disable_notification=False, reply_to_message_id=None, allow_sending_without_reply=None, - reply_markup=None, timeout=None, explanation_entities=None): + reply_markup=None, timeout=None, explanation_entities=None, protect_content=None): method_url = r'sendPoll' payload = { 'chat_id': str(chat_id), @@ -1581,6 +1620,8 @@ def send_poll( if explanation_entities: payload['explanation_entities'] = json.dumps( types.MessageEntity.to_list_of_dicts(explanation_entities)) + if protect_content: + payload['protect_content'] = protect_content return _make_request(token, method_url, params=payload) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 6f1fca5..011ff46 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -1484,16 +1484,19 @@ class AsyncTeleBot: result = await asyncio_helper.get_chat_member(self.token, chat_id, user_id) return types.ChatMember.de_json(result) + + async def send_message( self, chat_id: Union[int, str], text: str, - disable_web_page_preview: Optional[bool]=None, - reply_to_message_id: Optional[int]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None, parse_mode: Optional[str]=None, - disable_notification: Optional[bool]=None, - timeout: Optional[int]=None, entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + disable_web_page_preview: Optional[bool]=None, + disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, + reply_to_message_id: Optional[int]=None, + allow_sending_without_reply: Optional[bool]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + timeout: Optional[int]=None) -> types.Message: """ Use this method to send text messages. @@ -1511,6 +1514,7 @@ class AsyncTeleBot: :param timeout: :param entities: :param allow_sending_without_reply: + :param protect_content: :return: API reply. """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1519,11 +1523,12 @@ class AsyncTeleBot: await asyncio_helper.send_message( self.token, chat_id, text, disable_web_page_preview, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, - entities, allow_sending_without_reply)) + entities, allow_sending_without_reply, protect_content)) async def forward_message( self, chat_id: Union[int, str], from_chat_id: Union[int, str], - message_id: int, disable_notification: Optional[bool]=None, + message_id: int, disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, timeout: Optional[int]=None) -> types.Message: """ Use this method to forward messages of any kind. @@ -1531,11 +1536,12 @@ class AsyncTeleBot: :param chat_id: which chat to forward :param from_chat_id: which chat message from :param message_id: message id + :param protect_content: :param timeout: :return: API reply. """ return types.Message.de_json( - await asyncio_helper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout)) + await asyncio_helper.forward_message(self.token, chat_id, from_chat_id, message_id, disable_notification, timeout, protect_content)) async def copy_message( self, chat_id: Union[int, str], @@ -1545,6 +1551,7 @@ class AsyncTeleBot: parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, reply_to_message_id: Optional[int]=None, allow_sending_without_reply: Optional[bool]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, @@ -1562,12 +1569,13 @@ class AsyncTeleBot: :param allow_sending_without_reply: :param reply_markup: :param timeout: + :param protect_content: :return: API reply. """ return types.MessageID.de_json( await asyncio_helper.copy_message(self.token, chat_id, from_chat_id, message_id, caption, parse_mode, caption_entities, disable_notification, reply_to_message_id, allow_sending_without_reply, reply_markup, - timeout)) + timeout, protect_content)) async def delete_message(self, chat_id: Union[int, str], message_id: int, timeout: Optional[int]=None) -> bool: @@ -1586,7 +1594,8 @@ class AsyncTeleBot: reply_to_message_id: Optional[int]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Use this method to send dices. :param chat_id: @@ -1596,22 +1605,25 @@ class AsyncTeleBot: :param reply_markup: :param timeout: :param allow_sending_without_reply: + :param protect_content: :return: Message """ return types.Message.de_json( await asyncio_helper.send_dice( self.token, chat_id, emoji, disable_notification, reply_to_message_id, - reply_markup, timeout, allow_sending_without_reply) + reply_markup, timeout, allow_sending_without_reply, protect_content) ) async def send_photo( self, chat_id: Union[int, str], photo: Union[Any, str], - caption: Optional[str]=None, reply_to_message_id: Optional[int]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None, - parse_mode: Optional[str]=None, disable_notification: Optional[bool]=None, - timeout: Optional[int]=None, + caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, + reply_to_message_id: Optional[int]=None, + allow_sending_without_reply: Optional[bool]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + timeout: Optional[int]=None,) -> types.Message: """ Use this method to send photos. :param chat_id: @@ -1624,6 +1636,7 @@ class AsyncTeleBot: :param timeout: :param caption_entities: :param allow_sending_without_reply: + :param protect_content: :return: API reply. """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1632,7 +1645,7 @@ class AsyncTeleBot: await asyncio_helper.send_photo( self.token, chat_id, photo, caption, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, caption_entities, - allow_sending_without_reply)) + allow_sending_without_reply, protect_content)) async def send_audio( self, chat_id: Union[int, str], audio: Union[Any, str], @@ -1645,7 +1658,8 @@ class AsyncTeleBot: timeout: Optional[int]=None, thumb: Optional[Union[Any, str]]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=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 format. @@ -1663,6 +1677,7 @@ class AsyncTeleBot: :param thumb: :param caption_entities: :param allow_sending_without_reply: + :param protect_content: :return: Message """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1671,7 +1686,7 @@ class AsyncTeleBot: 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, - caption_entities, allow_sending_without_reply)) + caption_entities, allow_sending_without_reply, protect_content)) async def send_voice( self, chat_id: Union[int, str], voice: Union[Any, str], @@ -1682,7 +1697,8 @@ class AsyncTeleBot: disable_notification: Optional[bool]=None, timeout: Optional[int]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. @@ -1697,6 +1713,7 @@ class AsyncTeleBot: :param timeout: :param caption_entities: :param allow_sending_without_reply: + :param protect_content: :return: Message """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1705,7 +1722,7 @@ class AsyncTeleBot: await asyncio_helper.send_voice( self.token, chat_id, voice, caption, duration, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, caption_entities, - allow_sending_without_reply)) + allow_sending_without_reply, protect_content)) async def send_document( self, chat_id: Union[int, str], document: Union[Any, str], @@ -1720,7 +1737,8 @@ class AsyncTeleBot: 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) -> types.Message: + data: Optional[Union[Any, str]]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Use this method to send general files. :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) @@ -1737,6 +1755,7 @@ class AsyncTeleBot: :param visible_file_name: allows to async define file name that will be visible in the Telegram instead of original file name :param disable_content_type_detection: Disables automatic server-side content type detection for files uploaded using multipart/form-data :param data: function typo compatibility: do not use it + :param protect_content: :return: API reply. """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1750,67 +1769,75 @@ class AsyncTeleBot: 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, 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)) + disable_content_type_detection = disable_content_type_detection, visible_file_name = visible_file_name, protect_content = protect_content)) async def send_sticker( - self, chat_id: Union[int, str], data: Union[Any, str], + self, chat_id: Union[int, str], sticker: Union[Any, str], reply_to_message_id: Optional[int]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, disable_notification: Optional[bool]=None, timeout: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None, + data: Union[Any, str]=None) -> types.Message: """ Use this method to send .webp stickers. :param chat_id: - :param data: + :param sticker: :param reply_to_message_id: :param reply_markup: :param disable_notification: to disable the notification :param timeout: timeout :param allow_sending_without_reply: + :param protect_content: :return: API reply. """ + if data and not(sticker): + # function typo miss compatibility + sticker = data return types.Message.de_json( await asyncio_helper.send_data( - self.token, chat_id, data, 'sticker', + self.token, chat_id, sticker, 'sticker', 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)) + allow_sending_without_reply=allow_sending_without_reply, protect_content=protect_content)) async def send_video( - self, chat_id: Union[int, str], data: Union[Any, str], - duration: Optional[int]=None, - caption: Optional[str]=None, - reply_to_message_id: Optional[int]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None, - parse_mode: Optional[str]=None, - supports_streaming: Optional[bool]=None, - disable_notification: Optional[bool]=None, - timeout: Optional[int]=None, - thumb: Optional[Union[Any, str]]=None, - width: Optional[int]=None, + 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, + caption: Optional[str]=None, + parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + supports_streaming: Optional[bool]=None, + disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, + reply_to_message_id: Optional[int]=None, + allow_sending_without_reply: Optional[bool]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + timeout: Optional[int]=None, + data: Optional[Union[Any, str]]=None) -> types.Message: """ - Use this method to send video files, Telegram clients support mp4 videos. - :param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id - :param data: InputFile or String : Video to send. You can either pass a file_id as String to resend - a video that is already on the Telegram server - :param duration: Integer : Duration of sent video in seconds - :param caption: String : Video caption (may also be used when resending videos by file_id). - :param parse_mode: - :param supports_streaming: - :param reply_to_message_id: - :param reply_markup: - :param disable_notification: - :param timeout: - :param thumb: InputFile or String : Thumbnail of the file sent - :param width: - :param height: + Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :param video: Video to send. You can either pass a file_id as String to resend a video that is already on the Telegram servers, or upload a new video file using multipart/form-data. + :param duration: Duration of sent video in seconds + :param width: Video width + :param height: Video height + :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 . + :param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after entities parsing + :param parse_mode: Mode for parsing entities in the video caption :param caption_entities: + :param supports_streaming: Pass True, if the uploaded video is suitable for streaming + :param disable_notification: Sends the message silently. Users will receive a notification with no sound. + :param protect_content: + :param reply_to_message_id: If the message is a reply, ID of the original message :param allow_sending_without_reply: - :return: + :param reply_markup: + :param timeout: + :param data: function typo miss compatibility: do not use it """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode @@ -1818,33 +1845,38 @@ class AsyncTeleBot: await asyncio_helper.send_video( self.token, chat_id, data, duration, caption, reply_to_message_id, reply_markup, parse_mode, supports_streaming, disable_notification, timeout, thumb, width, height, - caption_entities, allow_sending_without_reply)) + caption_entities, allow_sending_without_reply, protect_content)) async def send_animation( self, chat_id: Union[int, str], animation: Union[Any, str], duration: Optional[int]=None, - caption: Optional[str]=None, - reply_to_message_id: Optional[int]=None, - reply_markup: Optional[REPLY_MARKUP_TYPES]=None, - parse_mode: Optional[str]=None, - disable_notification: Optional[bool]=None, - timeout: Optional[int]=None, + width: Optional[int]=None, + height: Optional[int]=None, thumb: Optional[Union[Any, str]]=None, + caption: Optional[str]=None, + parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, + reply_to_message_id: Optional[int]=None, + allow_sending_without_reply: Optional[bool]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None, + timeout: Optional[int]=None, ) -> types.Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). :param chat_id: Integer : Unique identifier for the message recipient — User or GroupChat id :param animation: InputFile or String : Animation to send. You can either pass a file_id as String to resend an animation that is already on the Telegram server :param duration: Integer : Duration of sent video in seconds + :param width: Integer : Video width + :param height: Integer : Video height + :param thumb: InputFile or String : Thumbnail of the file sent :param caption: String : Animation caption (may also be used when resending animation by file_id). :param parse_mode: :param reply_to_message_id: :param reply_markup: :param disable_notification: :param timeout: - :param thumb: InputFile or String : Thumbnail of the file sent :param caption_entities: :param allow_sending_without_reply: :return: @@ -1855,7 +1887,7 @@ class AsyncTeleBot: await asyncio_helper.send_animation( self.token, chat_id, animation, duration, caption, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, thumb, - caption_entities, allow_sending_without_reply)) + caption_entities, allow_sending_without_reply, width, height, protect_content)) async def send_video_note( self, chat_id: Union[int, str], data: Union[Any, str], @@ -1866,7 +1898,8 @@ class AsyncTeleBot: disable_notification: Optional[bool]=None, timeout: Optional[int]=None, thumb: Optional[Union[Any, str]]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. Use this method to send video messages. @@ -1881,12 +1914,13 @@ class AsyncTeleBot: :param timeout: :param thumb: InputFile or String : Thumbnail of the file sent :param allow_sending_without_reply: + :param protect_content: :return: """ 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)) + disable_notification, timeout, thumb, allow_sending_without_reply, protect_content)) async def send_media_group( self, chat_id: Union[int, str], @@ -1894,6 +1928,7 @@ class AsyncTeleBot: types.InputMediaAudio, types.InputMediaDocument, types.InputMediaPhoto, types.InputMediaVideo]], disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, reply_to_message_id: Optional[int]=None, timeout: Optional[int]=None, allow_sending_without_reply: Optional[bool]=None) -> List[types.Message]: @@ -1905,11 +1940,12 @@ class AsyncTeleBot: :param reply_to_message_id: :param timeout: :param allow_sending_without_reply: + :param protect_content: :return: """ result = await asyncio_helper.send_media_group( self.token, chat_id, media, disable_notification, reply_to_message_id, timeout, - allow_sending_without_reply) + allow_sending_without_reply, protect_content) return [types.Message.de_json(msg) for msg in result] async def send_location( @@ -1923,7 +1959,8 @@ class AsyncTeleBot: horizontal_accuracy: Optional[float]=None, heading: Optional[int]=None, proximity_alert_radius: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ @@ -1940,6 +1977,7 @@ class AsyncTeleBot: :param heading: :param proximity_alert_radius: :param allow_sending_without_reply: + :param protect_content: :return: API reply. """ return types.Message.de_json( @@ -1947,7 +1985,7 @@ class AsyncTeleBot: self.token, chat_id, latitude, longitude, live_period, reply_to_message_id, reply_markup, disable_notification, timeout, horizontal_accuracy, heading, proximity_alert_radius, - allow_sending_without_reply)) + allow_sending_without_reply, protect_content)) async def edit_message_live_location( self, latitude: float, longitude: float, @@ -2011,7 +2049,8 @@ class AsyncTeleBot: timeout: Optional[int]=None, allow_sending_without_reply: Optional[bool]=None, google_place_id: Optional[str]=None, - google_place_type: Optional[str]=None) -> types.Message: + google_place_type: Optional[str]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Use this method to send information about a venue. :param chat_id: Integer or String : Unique identifier for the target chat or username of the target channel @@ -2029,13 +2068,14 @@ class AsyncTeleBot: :param allow_sending_without_reply: :param google_place_id: :param google_place_type: + :param protect_content: :return: """ return types.Message.de_json( await asyncio_helper.send_venue( self.token, chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type, disable_notification, reply_to_message_id, reply_markup, timeout, - allow_sending_without_reply, google_place_id, google_place_type) + allow_sending_without_reply, google_place_id, google_place_type, protect_content) ) async def send_contact( @@ -2046,12 +2086,27 @@ class AsyncTeleBot: reply_to_message_id: Optional[int]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: + """ + Use this method to send phone contacts. + :param chat_id: Integer or String : Unique identifier for the target chat or username of the target channel + :param phone_number: String : Contact's phone number + :param first_name: String : Contact's first name + :param last_name: String : Contact's last name + :param vcard: String : Additional data about the contact in the form of a vCard, 0-2048 bytes + :param disable_notification: + :param reply_to_message_id: + :param reply_markup: + :param timeout: + :param allow_sending_without_reply: + :param protect_content: + """ return types.Message.de_json( await asyncio_helper.send_contact( self.token, chat_id, phone_number, first_name, last_name, vcard, disable_notification, reply_to_message_id, reply_markup, timeout, - allow_sending_without_reply) + allow_sending_without_reply, protect_content) ) async def send_chat_action( @@ -2576,7 +2631,8 @@ class AsyncTeleBot: reply_to_message_id: Optional[int]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - allow_sending_without_reply: Optional[bool]=None) -> types.Message: + allow_sending_without_reply: Optional[bool]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Used to send the game :param chat_id: @@ -2586,12 +2642,13 @@ class AsyncTeleBot: :param reply_markup: :param timeout: :param allow_sending_without_reply: + :param protect_content: :return: """ result = await asyncio_helper.send_game( self.token, chat_id, game_short_name, disable_notification, reply_to_message_id, reply_markup, timeout, - allow_sending_without_reply) + allow_sending_without_reply, protect_content) return types.Message.de_json(result) async def set_game_score( @@ -2651,7 +2708,8 @@ class AsyncTeleBot: timeout: Optional[int]=None, allow_sending_without_reply: Optional[bool]=None, max_tip_amount: Optional[int] = None, - suggested_tip_amounts: Optional[List[int]]=None) -> types.Message: + suggested_tip_amounts: Optional[List[int]]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Sends invoice :param chat_id: Unique identifier for the target private chat @@ -2690,6 +2748,7 @@ class AsyncTeleBot: :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency. At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount. + :param protect_content: :return: """ result = await asyncio_helper.send_invoice( @@ -2698,7 +2757,7 @@ class AsyncTeleBot: photo_height, need_name, need_phone_number, need_email, need_shipping_address, send_phone_number_to_provider, send_email_to_provider, is_flexible, disable_notification, reply_to_message_id, reply_markup, provider_data, timeout, allow_sending_without_reply, - max_tip_amount, suggested_tip_amounts) + max_tip_amount, suggested_tip_amounts, protect_content) return types.Message.de_json(result) # noinspection PyShadowingBuiltins @@ -2717,7 +2776,8 @@ class AsyncTeleBot: reply_markup: Optional[REPLY_MARKUP_TYPES]=None, allow_sending_without_reply: Optional[bool]=None, timeout: Optional[int]=None, - explanation_entities: Optional[List[types.MessageEntity]]=None) -> types.Message: + explanation_entities: Optional[List[types.MessageEntity]]=None, + protect_content: Optional[bool]=None) -> types.Message: """ Send polls :param chat_id: @@ -2738,6 +2798,7 @@ class AsyncTeleBot: :param reply_markup: :param timeout: :param explanation_entities: + :param protect_content: :return: """ @@ -2751,7 +2812,7 @@ class AsyncTeleBot: is_anonymous, type, allows_multiple_answers, correct_option_id, explanation, explanation_parse_mode, open_period, close_date, is_closed, disable_notification, reply_to_message_id, allow_sending_without_reply, - reply_markup, timeout, explanation_entities)) + reply_markup, timeout, explanation_entities, protect_content)) async def stop_poll( self, chat_id: Union[int, str], message_id: int, diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index eab1aea..fc02775 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -39,7 +39,7 @@ MAX_RETRIES = 3 logger = telebot.logger async def _process_request(token, url, method='get', params=None, files=None, request_timeout=None): - params = compose_data(params, files) + params = prepare_data(params, files) if request_timeout is None: request_timeout = REQUEST_TIMEOUT timeout = aiohttp.ClientTimeout(total=request_timeout) @@ -54,6 +54,8 @@ async def _process_request(token, url, method='get', params=None, files=None, re json_result = await _check_result(url, response) if json_result: return json_result['result'] + except (ApiTelegramException,ApiInvalidJSONException, ApiHTTPException) as e: + raise e except: pass if not got_result: @@ -62,9 +64,9 @@ async def _process_request(token, url, method='get', params=None, files=None, re -def guess_filename(obj): +def prepare_file(obj): """ - Get file name from object + returns os.path.basename for a given file :param obj: :return: @@ -74,9 +76,9 @@ def guess_filename(obj): return os.path.basename(name) -def compose_data(params=None, files=None): +def prepare_data(params=None, files=None): """ - Prepare request data + prepare data for request. :param params: :param files: @@ -96,7 +98,7 @@ def compose_data(params=None, files=None): else: raise ValueError('Tuple must have exactly 2 elements: filename, fileobj') else: - filename, fileobj = guess_filename(f) or key, f + filename, fileobj = prepare_file(f) or key, f data.add_field(key, fileobj, filename=filename) @@ -239,7 +241,7 @@ async def send_message( token, chat_id, text, disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, - entities=None, allow_sending_without_reply=None): + entities=None, allow_sending_without_reply=None, protect_content=None): """ Use this method to send text messages. On success, the sent Message is returned. :param token: @@ -253,6 +255,7 @@ async def send_message( :param timeout: :param entities: :param allow_sending_without_reply: + :param protect_content: :return: """ method_name = 'sendMessage' @@ -273,6 +276,8 @@ async def send_message( params['entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(entities)) if allow_sending_without_reply is not None: params['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + params['protect_content'] = protect_content return await _process_request(token, method_name, params=params) @@ -344,19 +349,21 @@ async def get_chat_member(token, chat_id, user_id): async def forward_message( token, chat_id, from_chat_id, message_id, - disable_notification=None, timeout=None): + disable_notification=None, timeout=None, protect_content=None): method_url = r'forwardMessage' payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id} if disable_notification is not None: payload['disable_notification'] = disable_notification if timeout: payload['timeout'] = timeout + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload) async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None, disable_notification=None, reply_to_message_id=None, allow_sending_without_reply=None, - reply_markup=None, timeout=None): + reply_markup=None, timeout=None, protect_content=None): method_url = r'copyMessage' payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id} if caption is not None: @@ -375,13 +382,15 @@ async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, p payload['allow_sending_without_reply'] = allow_sending_without_reply if timeout: payload['timeout'] = timeout + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload) async def send_dice( token, chat_id, emoji=None, disable_notification=None, reply_to_message_id=None, - reply_markup=None, timeout=None, allow_sending_without_reply=None): + reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendDice' payload = {'chat_id': chat_id} if emoji: @@ -396,6 +405,8 @@ async def send_dice( payload['timeout'] = timeout if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload) @@ -403,7 +414,7 @@ async def send_photo( token, chat_id, photo, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, - caption_entities=None, allow_sending_without_reply=None): + caption_entities=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendPhoto' payload = {'chat_id': chat_id} files = None @@ -429,13 +440,15 @@ async def send_photo( payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_media_group( token, chat_id, media, disable_notification=None, reply_to_message_id=None, - timeout=None, allow_sending_without_reply=None): + timeout=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendMediaGroup' media_json, files = await convert_input_media_array(media) payload = {'chat_id': chat_id, 'media': media_json} @@ -447,6 +460,8 @@ async def send_media_group( payload['timeout'] = timeout if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request( token, method_url, params=payload, method='post' if files else 'get', @@ -458,7 +473,7 @@ async def send_location( live_period=None, reply_to_message_id=None, reply_markup=None, disable_notification=None, timeout=None, horizontal_accuracy=None, heading=None, - proximity_alert_radius=None, allow_sending_without_reply=None): + proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendLocation' payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude} if live_period: @@ -479,6 +494,8 @@ async def send_location( payload['disable_notification'] = disable_notification if timeout: payload['timeout'] = timeout + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload) @@ -530,7 +547,7 @@ async def send_venue( foursquare_id=None, foursquare_type=None, disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None, allow_sending_without_reply=None, google_place_id=None, - google_place_type=None): + google_place_type=None, protect_content=None): method_url = r'sendVenue' payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address} if foursquare_id: @@ -551,13 +568,15 @@ async def send_venue( payload['google_place_id'] = google_place_id if google_place_type: payload['google_place_type'] = google_place_type + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload) async def send_contact( token, chat_id, phone_number, first_name, last_name=None, vcard=None, disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None, - allow_sending_without_reply=None): + allow_sending_without_reply=None, protect_content=None): method_url = r'sendContact' payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name} if last_name: @@ -574,6 +593,8 @@ async def send_contact( payload['timeout'] = timeout if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload) @@ -587,7 +608,8 @@ async def send_chat_action(token, chat_id, action, timeout=None): async def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None, - thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None): + thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, + protect_content=None): method_url = r'sendVideo' payload = {'chat_id': chat_id} files = None @@ -627,13 +649,15 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_to payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_animation( token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None, - allow_sending_without_reply=None): + allow_sending_without_reply=None, width=None, height=None, protect_content=None): method_url = r'sendAnimation' payload = {'chat_id': chat_id} files = None @@ -667,12 +691,18 @@ async def send_animation( payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if width: + payload['width'] = width + if height: + payload['height'] = height + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, caption_entities=None, - allow_sending_without_reply=None): + allow_sending_without_reply=None, protect_content=None): method_url = r'sendVoice' payload = {'chat_id': chat_id} files = None @@ -698,11 +728,13 @@ async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_t payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None, - disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None): + disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendVideoNote' payload = {'chat_id': chat_id} files = None @@ -734,12 +766,14 @@ async def send_video_note(token, chat_id, data, duration=None, length=None, repl payload['thumb'] = thumb if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None, - caption_entities=None, allow_sending_without_reply=None): + caption_entities=None, allow_sending_without_reply=None, protect_content=None): method_url = r'sendAudio' payload = {'chat_id': chat_id} files = None @@ -777,12 +811,14 @@ async def send_audio(token, chat_id, audio, caption=None, duration=None, perform payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload, files=files, method='post') 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): + allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None, protect_content=None): method_url = await get_method_by_type(data_type) payload = {'chat_id': chat_id} files = None @@ -1187,7 +1223,7 @@ async def delete_message(token, chat_id, message_id, timeout=None): async def send_game( token, chat_id, game_short_name, disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None, - allow_sending_without_reply=None): + allow_sending_without_reply=None, protect_content=None): method_url = r'sendGame' payload = {'chat_id': chat_id, 'game_short_name': game_short_name} if disable_notification is not None: @@ -1200,6 +1236,8 @@ async def send_game( payload['timeout'] = timeout if allow_sending_without_reply is not None: payload['allow_sending_without_reply'] = allow_sending_without_reply + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload) @@ -1264,7 +1302,7 @@ async def send_invoice( need_name=None, need_phone_number=None, need_email=None, need_shipping_address=None, send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None, disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None, - timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None): + timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None, protect_content=None): """ Use this method to send invoices. On success, the sent Message is returned. :param token: Bot's token (you don't need to fill this) @@ -1296,6 +1334,7 @@ async def send_invoice( :param max_tip_amount: The maximum accepted amount for tips in the smallest units of the currency :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency. At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount. + :param protect_content: :return: """ method_url = r'sendInvoice' @@ -1342,6 +1381,8 @@ async def send_invoice( payload['max_tip_amount'] = max_tip_amount if suggested_tip_amounts is not None: payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts) + if protect_content is not None: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload) @@ -1490,7 +1531,7 @@ async def send_poll( is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None, explanation = None, explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None, disable_notification=False, reply_to_message_id=None, allow_sending_without_reply=None, - reply_markup=None, timeout=None, explanation_entities=None): + reply_markup=None, timeout=None, explanation_entities=None, protect_content=None): method_url = r'sendPoll' payload = { 'chat_id': str(chat_id), @@ -1532,6 +1573,8 @@ async def send_poll( if explanation_entities: payload['explanation_entities'] = json.dumps( types.MessageEntity.to_list_of_dicts(explanation_entities)) + if protect_content: + payload['protect_content'] = protect_content return await _process_request(token, method_url, params=payload) async def _convert_list_json_serializable(results): diff --git a/telebot/types.py b/telebot/types.py index eb3fabf..a200b73 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -582,7 +582,8 @@ class Message(JsonDeserializable): # "url": "{text}", # @badiboy plain URLs have no text and do not need tags "text_link": "{text}", "strikethrough": "{text}", - "underline": "{text}" + "underline": "{text}", + "spoiler": "{text}", } if hasattr(self, "custom_subs"):