diff --git a/README.md b/README.md index 10694e4b0..22be0a24c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@

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

Both synchronous and asynchronous.

-##

Supported Bot API version: 7.5! +##

Supported Bot API version: 7.6!

Official documentation

Official ru documentation

diff --git a/telebot/__init__.py b/telebot/__init__.py index 408a11902..eef715af2 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -1822,6 +1822,9 @@ def copy_message( show_caption_above_media: Optional[bool]=None) -> types.MessageID: """ Use this method to copy messages of any kind. + Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. + A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method + forwardMessage, but the copied message doesn't have a link to the original message. Returns the MessageId of the sent message on success. Telegram documentation: https://core.telegram.org/bots/api#copymessage @@ -1999,47 +2002,47 @@ def forward_messages(self, chat_id: Union[str, int], from_chat_id: Union[str, in def copy_messages(self, chat_id: Union[str, int], from_chat_id: Union[str, int], message_ids: List[int], disable_notification: Optional[bool] = None, message_thread_id: Optional[int] = None, protect_content: Optional[bool] = None, remove_caption: Optional[bool] = None) -> List[types.MessageID]: - """ - Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. - Service messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. - A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. - The method is analogous to the method forwardMessages, but the copied messages don't have a link to the original message. - Album grouping is kept for copied messages. On success, an array of MessageId of the sent messages is returned. + """ + Use this method to copy messages of any kind. + If some of the specified messages can't be found or copied, they are skipped. Service messages, paid media messages, giveaway messages, giveaway winners messages, + and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous + to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an array + of MessageId of the sent messages is returned. - Telegram documentation: https://core.telegram.org/bots/api#copymessages + Telegram documentation: https://core.telegram.org/bots/api#copymessages - :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) - :type chat_id: :obj:`int` or :obj:`str` + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` - :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername) - :type from_chat_id: :obj:`int` or :obj:`str` + :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername) + :type from_chat_id: :obj:`int` or :obj:`str` - :param message_ids: Message identifiers in the chat specified in from_chat_id - :type message_ids: :obj:`list` of :obj:`int` + :param message_ids: Message identifiers in the chat specified in from_chat_id + :type message_ids: :obj:`list` of :obj:`int` - :param disable_notification: Sends the message silently. Users will receive a notification with no sound - :type disable_notification: :obj:`bool` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound + :type disable_notification: :obj:`bool` - :param message_thread_id: Identifier of a message thread, in which the messages will be sent - :type message_thread_id: :obj:`int` + :param message_thread_id: Identifier of a message thread, in which the messages will be sent + :type message_thread_id: :obj:`int` - :param protect_content: Protects the contents of the forwarded message from forwarding and saving - :type protect_content: :obj:`bool` + :param protect_content: Protects the contents of the forwarded message from forwarding and saving + :type protect_content: :obj:`bool` - :param remove_caption: Pass True to copy the messages without their captions - :type remove_caption: :obj:`bool` + :param remove_caption: Pass True to copy the messages without their captions + :type remove_caption: :obj:`bool` - :return: On success, an array of MessageId of the sent messages is returned. - :rtype: :obj:`list` of :class:`telebot.types.MessageID` - """ - disable_notification = self.disable_notification if disable_notification is None else disable_notification - protect_content = self.protect_content if protect_content is None else protect_content + :return: On success, an array of MessageId of the sent messages is returned. + :rtype: :obj:`list` of :class:`telebot.types.MessageID` + """ + disable_notification = self.disable_notification if disable_notification is None else disable_notification + protect_content = self.protect_content if protect_content is None else protect_content - result = apihelper.copy_messages( - self.token, chat_id, from_chat_id, message_ids, disable_notification=disable_notification, - message_thread_id=message_thread_id, protect_content=protect_content, remove_caption=remove_caption) - return [types.MessageID.de_json(message_id) for message_id in result] + result = apihelper.copy_messages( + self.token, chat_id, from_chat_id, message_ids, disable_notification=disable_notification, + message_thread_id=message_thread_id, protect_content=protect_content, remove_caption=remove_caption) + return [types.MessageID.de_json(message_id) for message_id in result] def send_dice( @@ -3112,6 +3115,61 @@ def send_video_note( protect_content=protect_content, message_thread_id=message_thread_id, reply_parameters=reply_parameters, business_connection_id=business_connection_id, message_effect_id=message_effect_id) ) + + def send_paid_media( + self, chat_id: Union[int, str], star_count: int, media: List[types.InputPaidMedia], + caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, + show_caption_above_media: Optional[bool]=None, disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, reply_parameters: Optional[types.ReplyParameters]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None) -> types.Message: + """ + Use this method to send paid media to channel chats. On success, the sent Message is returned. + + Telegram documentation: https://core.telegram.org/bots/api#sendpaidmedia + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + + :param star_count: The number of Telegram Stars that must be paid to buy access to the media + :type star_count: :obj:`int` + + :param media: A JSON-serialized array describing the media to be sent; up to 10 items + :type media: :obj:`list` of :class:`telebot.types.InputPaidMedia` + + :param caption: Media caption, 0-1024 characters after entities parsing + :type caption: :obj:`str` + + :param parse_mode: Mode for parsing entities in the media caption + :type parse_mode: :obj:`str` + + :param caption_entities: 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` + + :param show_caption_above_media: Pass True, if the caption must be shown above the message media + :type show_caption_above_media: :obj:`bool` + + :param disable_notification: Sends the message silently. Users will receive a notification with no sound. + :type disable_notification: :obj:`bool` + + :param protect_content: Protects the contents of the sent message from forwarding and saving + :type protect_content: :obj:`bool` + + :param reply_parameters: Description of the message to reply to + :type reply_parameters: :class:`telebot.types.ReplyParameters` + + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove a reply keyboard or to force a reply from the user + :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply` + + :return: On success, the sent Message is returned. + :rtype: :class:`telebot.types.Message` + """ + return types.Message.de_json( + apihelper.send_paid_media( + self.token, chat_id, star_count, media, caption=caption, parse_mode=parse_mode, + caption_entities=caption_entities, show_caption_above_media=show_caption_above_media, + disable_notification=disable_notification, protect_content=protect_content, + reply_parameters=reply_parameters, reply_markup=reply_markup) + ) def send_media_group( diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 54ce9f691..8c170ec2a 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -525,6 +525,34 @@ def send_photo( if show_caption_above_media is not None: payload['show_caption_above_media'] = show_caption_above_media return _make_request(token, method_url, params=payload, files=files, method='post') + +def send_paid_media( + token, chat_id, star_count, media, + caption=None, parse_mode=None, caption_entities=None, show_caption_above_media=None, + disable_notification=None, protect_content=None, reply_parameters=None, reply_markup=None): + method_url = r'sendPaidMedia' + media_json, files = convert_input_media_array(media) + payload = {'chat_id': chat_id, 'star_count': star_count, 'media': media_json} + if caption: + payload['caption'] = caption + if parse_mode: + payload['parse_mode'] = parse_mode + if caption_entities: + payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) + if show_caption_above_media is not None: + payload['show_caption_above_media'] = show_caption_above_media + if disable_notification is not None: + payload['disable_notification'] = disable_notification + if protect_content is not None: + payload['protect_content'] = protect_content + if reply_parameters is not None: + payload['reply_parameters'] = reply_parameters.to_json() + if reply_markup: + payload['reply_markup'] = _convert_markup(reply_markup) + return _make_request( + token, method_url, params=payload, + method='post' if files else 'get', + files=files if files else None) def send_media_group( @@ -2117,7 +2145,7 @@ def convert_input_media_array(array): media = [] files = {} for input_media in array: - if isinstance(input_media, types.InputMedia): + if isinstance(input_media, types.InputMedia) or isinstance(input_media, types.InputPaidMedia): media_dict = input_media.to_dict() if media_dict['media'].startswith('attach://'): key = media_dict['media'].replace('attach://', '') diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 4ad59c4da..75ebe6791 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -3248,6 +3248,10 @@ async def copy_message( show_caption_above_media: Optional[bool]=None) -> types.MessageID: """ Use this method to copy messages of any kind. + If some of the specified messages can't be found or copied, they are skipped. Service messages, paid media messages, giveaway messages, giveaway winners messages, + and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous + to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an array + of MessageId of the sent messages is returned. Telegram documentation: https://core.telegram.org/bots/api#copymessage @@ -3415,44 +3419,43 @@ async def forward_messages(self, chat_id: Union[str, int], from_chat_id: Union[s async def copy_messages(self, chat_id: Union[str, int], from_chat_id: Union[str, int], message_ids: List[int], disable_notification: Optional[bool] = None, message_thread_id: Optional[int] = None, protect_content: Optional[bool] = None, remove_caption: Optional[bool] = None) -> List[types.MessageID]: - """ - Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. - Service messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied - only if the value of the field correct_option_id is known to the bot. The method is analogous to the method forwardMessages, but - the copied messages don't have a link to the original message. Album grouping is kept for copied messages. - On success, an array of MessageId of the sent messages is returned. + """ + Use this method to copy messages of any kind. + Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. + A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method + forwardMessage, but the copied message doesn't have a link to the original message. Returns the MessageId of the sent message on success. - Telegram documentation: https://core.telegram.org/bots/api#copymessages + Telegram documentation: https://core.telegram.org/bots/api#copymessages - :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) - :type chat_id: :obj:`int` or :obj:`str` + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` - :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername) - :type from_chat_id: :obj:`int` or :obj:`str` + :param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername) + :type from_chat_id: :obj:`int` or :obj:`str` - :param message_ids: Message identifiers in the chat specified in from_chat_id - :type message_ids: :obj:`list` of :obj:`int` + :param message_ids: Message identifiers in the chat specified in from_chat_id + :type message_ids: :obj:`list` of :obj:`int` - :param disable_notification: Sends the message silently. Users will receive a notification with no sound - :type disable_notification: :obj:`bool` + :param disable_notification: Sends the message silently. Users will receive a notification with no sound + :type disable_notification: :obj:`bool` - :param message_thread_id: Identifier of a message thread, in which the messages will be sent - :type message_thread_id: :obj:`int` + :param message_thread_id: Identifier of a message thread, in which the messages will be sent + :type message_thread_id: :obj:`int` - :param protect_content: Protects the contents of the forwarded message from forwarding and saving - :type protect_content: :obj:`bool` + :param protect_content: Protects the contents of the forwarded message from forwarding and saving + :type protect_content: :obj:`bool` - :param remove_caption: Pass True to copy the messages without their captions - :type remove_caption: :obj:`bool` + :param remove_caption: Pass True to copy the messages without their captions + :type remove_caption: :obj:`bool` - :return: On success, an array of MessageId of the sent messages is returned. - :rtype: :obj:`list` of :class:`telebot.types.MessageID` - """ - disable_notification = self.disable_notification if disable_notification is None else disable_notification - protect_content = self.protect_content if protect_content is None else protect_content - result = await asyncio_helper.copy_messages(self.token, chat_id, from_chat_id, message_ids, disable_notification, message_thread_id, - protect_content, remove_caption) - return [types.MessageID.de_json(message_id) for message_id in result] + :return: On success, an array of MessageId of the sent messages is returned. + :rtype: :obj:`list` of :class:`telebot.types.MessageID` + """ + disable_notification = self.disable_notification if disable_notification is None else disable_notification + protect_content = self.protect_content if protect_content is None else protect_content + result = await asyncio_helper.copy_messages(self.token, chat_id, from_chat_id, message_ids, disable_notification, message_thread_id, + protect_content, remove_caption) + return [types.MessageID.de_json(message_id) for message_id in result] async def send_dice( self, chat_id: Union[int, str], @@ -4526,6 +4529,61 @@ async def send_video_note( self.token, chat_id, data, duration, length, reply_markup, disable_notification, timeout, thumbnail, protect_content, message_thread_id, reply_parameters, business_connection_id, message_effect_id=message_effect_id)) + async def send_paid_media( + self, chat_id: Union[int, str], star_count: int, media: List[types.InputPaidMedia], + caption: Optional[str]=None, parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, + show_caption_above_media: Optional[bool]=None, disable_notification: Optional[bool]=None, + protect_content: Optional[bool]=None, reply_parameters: Optional[types.ReplyParameters]=None, + reply_markup: Optional[REPLY_MARKUP_TYPES]=None) -> types.Message: + """ + Use this method to send paid media to channel chats. On success, the sent Message is returned. + + Telegram documentation: https://core.telegram.org/bots/api#sendpaidmedia + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + + :param star_count: The number of Telegram Stars that must be paid to buy access to the media + :type star_count: :obj:`int` + + :param media: A JSON-serialized array describing the media to be sent; up to 10 items + :type media: :obj:`list` of :class:`telebot.types.InputPaidMedia` + + :param caption: Media caption, 0-1024 characters after entities parsing + :type caption: :obj:`str` + + :param parse_mode: Mode for parsing entities in the media caption + :type parse_mode: :obj:`str` + + :param caption_entities: 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` + + :param show_caption_above_media: Pass True, if the caption must be shown above the message media + :type show_caption_above_media: :obj:`bool` + + :param disable_notification: Sends the message silently. Users will receive a notification with no sound. + :type disable_notification: :obj:`bool` + + :param protect_content: Protects the contents of the sent message from forwarding and saving + :type protect_content: :obj:`bool` + + :param reply_parameters: Description of the message to reply to + :type reply_parameters: :class:`telebot.types.ReplyParameters` + + :param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove a reply keyboard or to force a reply from the user + :type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply` + + :return: On success, the sent Message is returned. + :rtype: :class:`telebot.types.Message` + """ + return types.Message.de_json( + await asyncio_helper.send_paid_media( + self.token, chat_id, star_count, media, caption=caption, parse_mode=parse_mode, + caption_entities=caption_entities, show_caption_above_media=show_caption_above_media, + disable_notification=disable_notification, protect_content=protect_content, + reply_parameters=reply_parameters, reply_markup=reply_markup) + ) + async def send_media_group( self, chat_id: Union[int, str], media: List[Union[ diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 0a484f3b4..79f09b96b 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -514,6 +514,33 @@ async def send_photo( payload['show_caption_above_media'] = show_caption_above_media return await _process_request(token, method_url, params=payload, files=files, method='post') +async def send_paid_media( + token, chat_id, star_count, media, + caption=None, parse_mode=None, caption_entities=None, show_caption_above_media=None, + disable_notification=None, protect_content=None, reply_parameters=None, reply_markup=None): + method_url = r'sendPaidMedia' + media_json, files = convert_input_media_array(media) + payload = {'chat_id': chat_id, 'star_count': star_count, 'media': media_json} + if caption: + payload['caption'] = caption + if parse_mode: + payload['parse_mode'] = parse_mode + if caption_entities: + payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities)) + if show_caption_above_media is not None: + payload['show_caption_above_media'] = show_caption_above_media + if disable_notification is not None: + payload['disable_notification'] = disable_notification + if protect_content is not None: + payload['protect_content'] = protect_content + if reply_parameters is not None: + payload['reply_parameters'] = reply_parameters.to_json() + if reply_markup: + payload['reply_markup'] = _convert_markup(reply_markup) + return await _process_request( + token, method_url, params=payload, + method='post' if files else 'get', + files=files if files else None) async def send_media_group( token, chat_id, media, @@ -2081,7 +2108,7 @@ async def convert_input_media_array(array): media = [] files = {} for input_media in array: - if isinstance(input_media, types.InputMedia): + if isinstance(input_media, types.InputMedia) or isinstance(input_media, types.InputPaidMedia): media_dict = input_media.to_dict() if media_dict['media'].startswith('attach://'): key = media_dict['media'].replace('attach://', '') diff --git a/telebot/types.py b/telebot/types.py index 5d69af0ff..abbc69bbd 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -707,6 +707,10 @@ class ChatFullInfo(JsonDeserializable): :param location: Optional. For supergroups, the location to which the supergroup is connected. Returned only in getChat. :type location: :class:`telebot.types.ChatLocation` + :param can_send_paid_media: Optional. True, if paid media messages can be sent or forwarded to the channel chat. + The field is available only for channel chats. + :type can_send_paid_media: :obj:`bool` + :return: Instance of the class :rtype: :class:`telebot.types.ChatFullInfo` """ @@ -748,7 +752,8 @@ def __init__(self, id, type, title=None, username=None, first_name=None, available_reactions=None, accent_color_id=None, background_custom_emoji_id=None, profile_accent_color_id=None, profile_background_custom_emoji_id=None, has_visible_history=None, unrestrict_boost_count=None, custom_emoji_sticker_set_name=None, business_intro=None, business_location=None, - business_opening_hours=None, personal_chat=None, birthdate=None, **kwargs): + business_opening_hours=None, personal_chat=None, birthdate=None, + can_send_paid_media=None, **kwargs): self.id: int = id self.type: str = type self.title: str = title @@ -792,6 +797,7 @@ def __init__(self, id, type, title=None, username=None, first_name=None, self.business_opening_hours: BusinessOpeningHours = business_opening_hours self.personal_chat: Chat = personal_chat self.birthdate: Birthdate = birthdate + self.can_send_paid_media: bool = can_send_paid_media class Chat(ChatFullInfo): @@ -964,6 +970,9 @@ class Message(JsonDeserializable): :param document: Optional. Message is a general file, information about the file :type document: :class:`telebot.types.Document` + :param paid_media: Optional. Message contains paid media; information about the paid media + :type paid_media: :class:`telebot.types.PaidMediaInfo` + :param photo: Optional. Message is a photo, available sizes of the photo :type photo: :obj:`list` of :class:`telebot.types.PhotoSize` @@ -1380,7 +1389,8 @@ def de_json(cls, json_string): opts['effect_id'] = obj['effect_id'] if 'show_caption_above_media' in obj: opts['show_caption_above_media'] = obj['show_caption_above_media'] - + if 'paid_media' in obj: + opts['paid_media'] = PaidMediaInfo.de_json(obj['paid_media']) return cls(message_id, from_user, date, chat, content_type, opts, json_string) @@ -1491,6 +1501,7 @@ def __init__(self, message_id, from_user, date, chat, content_type, options, jso self.is_from_offline: Optional[bool] = None self.effect_id: Optional[str] = None self.show_caption_above_media: Optional[bool] = None + self.paid_media : Optional[PaidMediaInfo] = None for key in options: setattr(self, key, options[key]) @@ -6726,7 +6737,7 @@ def to_dict(self): ret['height'] = self.height if self.duration: ret['duration'] = self.duration - if self.supports_streaming: + if self.supports_streaming is not None: ret['supports_streaming'] = self.supports_streaming if self.has_spoiler is not None: ret['has_spoiler'] = self.has_spoiler @@ -7532,7 +7543,9 @@ class MenuButtonWebApp(MenuButton): :type text: :obj:`str` :param web_app: Description of the Web App that will be launched when the user presses the button. The Web App will be - able to send an arbitrary message on behalf of the user using the method answerWebAppQuery. + able to send an arbitrary message on behalf of the user using the method answerWebAppQuery. Alternatively, a t.me link + to a Web App of the bot can be specified in the object instead of the Web App's URL, in which case the Web App will be + opened as if the user pressed the link. :type web_app: :class:`telebot.types.WebAppInfo` :return: Instance of the class @@ -8511,6 +8524,9 @@ class ExternalReplyInfo(JsonDeserializable): :param document: Optional. Message is a general file, information about the file :type document: :class:`Document` + :param paid_media: Optional. Message is a paid media content + :type paid_media: :class:`PaidMedia` + :param photo: Optional. Message is a photo, available sizes of the photo :type photo: :obj:`list` of :class:`PhotoSize` @@ -8619,7 +8635,7 @@ def __init__( dice: Optional[Dice]=None, game: Optional[Game]=None, giveaway: Optional[Giveaway]=None, giveaway_winners: Optional[GiveawayWinners]=None, invoice: Optional[Invoice]=None, location: Optional[Location]=None, poll: Optional[Poll]=None, - venue: Optional[Venue]=None, **kwargs) -> None: + venue: Optional[Venue]=None, paid_media: Optional[PaidMediaInfo]=None, **kwargs) -> None: self.origin: MessageOrigin = origin self.chat: Optional[Chat] = chat self.message_id: Optional[int] = message_id @@ -8643,6 +8659,7 @@ def __init__( self.location: Optional[Location] = location self.poll: Optional[Poll] = poll self.venue: Optional[Venue] = venue + self.paid_media: Optional[PaidMediaInfo] = paid_media # noinspection PyUnresolvedReferences,PyShadowingBuiltins @@ -10209,6 +10226,8 @@ def de_json(cls, json_string): return TransactionPartnerFragment.de_json(obj) elif obj["type"] == "user": return TransactionPartnerUser.de_json(obj) + elif obj["type"] == "telegram_ads": + return TransactionPartnerTelegramAds.de_json(obj) elif obj["type"] == "other": return TransactionPartnerOther.de_json(obj) @@ -10255,13 +10274,17 @@ class TransactionPartnerUser(TransactionPartner): :param user: Information about the user :type user: :class:`User` + :param invoice_payload: Optional, Bot-specified invoice payload + :type invoice_payload: :obj:`str` + :return: Instance of the class :rtype: :class:`TransactionPartnerUser` """ - def __init__(self, type, user, **kwargs): + def __init__(self, type, user, invoice_payload=None, **kwargs): self.type: str = type self.user: User = user + self.invoice_payload: Optional[str] = invoice_payload @classmethod def de_json(cls, json_string): @@ -10270,6 +10293,27 @@ def de_json(cls, json_string): obj['user'] = User.de_json(obj['user']) return cls(**obj) +class TransactionPartnerTelegramAds(TransactionPartner): + """ + Describes a transaction with Telegram Ads. + + Telegram documentation: https://core.telegram.org/bots/api#transactionpartnertelegramads + + :param type: Type of the transaction partner, always “telegram_ads” + :type type: :obj:`str` + + :return: Instance of the class + :rtype: :class:`TransactionPartnerTelegramAds` + """ + + def __init__(self, type, **kwargs): + self.type: str = type + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + class TransactionPartnerOther(TransactionPartner): """ @@ -10361,3 +10405,266 @@ def de_json(cls, json_string): def __init__(self, transactions, **kwargs): self.transactions: List[StarTransaction] = transactions + + +class PaidMedia(JsonDeserializable): + """ + This object describes paid media. Currently, it can be one of + + PaidMediaPreview + PaidMediaPhoto + PaidMediaVideo + + Telegram documentation: https://core.telegram.org/bots/api#paidmedia + + :return: Instance of the class + :rtype: :class:`PaidMediaPreview` or :class:`PaidMediaPhoto` or :class:`PaidMediaVideo` + """ + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + if obj["type"] == "preview": + return PaidMediaPreview.de_json(obj) + elif obj["type"] == "photo": + return PaidMediaPhoto.de_json(obj) + elif obj["type"] == "video": + return PaidMediaVideo.de_json(obj) + +class PaidMediaPreview(PaidMedia): + """ + The paid media isn't available before the payment. + + Telegram documentation: https://core.telegram.org/bots/api#paidmediapreview + + :param type: Type of the paid media, always “preview” + :type type: :obj:`str` + + :param width: Optional. Media width as defined by the sender + :type width: :obj:`int` + + :param height: Optional. Media height as defined by the sender + :type height: :obj:`int` + + :param duration: Optional. Duration of the media in seconds as defined by the sender + :type duration: :obj:`int` + + :return: Instance of the class + :rtype: :class:`PaidMediaPreview` + """ + + def __init__(self, type, width=None, height=None, duration=None, **kwargs): + self.type: str = type + self.width: Optional[int] = width + self.height: Optional[int] = height + self.duration: Optional[int] = duration + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + return cls(**obj) + + +class PaidMediaPhoto(PaidMedia): + """ + The paid media is a photo. + + Telegram documentation: https://core.telegram.org/bots/api#paidmediaphoto + + :param type: Type of the paid media, always “photo” + :type type: :obj:`str` + + :param photo: The photo + :type photo: :obj:`list` of :class:`PhotoSize` + + :return: Instance of the class + :rtype: :class:`PaidMediaPhoto` + + """ + + def __init__(self, type, photo, **kwargs): + self.type: str = type + self.photo: List[PhotoSize] = photo + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + + obj['photo'] = [PhotoSize.de_json(photo) for photo in obj['photo']] + return cls(**obj) + + +class PaidMediaVideo(PaidMedia): + """ + The paid media is a video. + + Telegram documentation: https://core.telegram.org/bots/api#paidmediavideo + + :param type: Type of the paid media, always “video” + :type type: :obj:`str` + + :param video: The video + :type video: :class:`Video` + + :return: Instance of the class + :rtype: :class:`PaidMediaVideo` + """ + + def __init__(self, type, video, **kwargs): + self.type: str = type + self.video: Video = video + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['video'] = Video.de_json(obj['video']) + return cls(**obj) + + +class PaidMediaInfo(JsonDeserializable): + """ + Describes the paid media added to a message. + + Telegram documentation: https://core.telegram.org/bots/api#paidmediainfo + + :param star_count: The number of Telegram Stars that must be paid to buy access to the media + :type star_count: :obj:`int` + + :param paid_media: Information about the paid media + :type paid_media: :obj:`list` of :class:`PaidMedia` + + :return: Instance of the class + :rtype: :class:`PaidMediaInfo` + """ + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['paid_media'] = [PaidMedia.de_json(media) for media in obj['paid_media']] + return cls(**obj) + + def __init__(self, star_count, paid_media, **kwargs): + self.star_count: int = star_count + self.paid_media: List[PaidMedia] = paid_media + + +class InputPaidMedia(JsonSerializable): + """ + This object describes the paid media to be sent. Currently, it can be one of + InputPaidMediaPhoto + InputPaidMediaVideo + + Telegram documentation: https://core.telegram.org/bots/api#inputpaidmedia + + :return: Instance of the class + :rtype: :class:`InputPaidMediaPhoto` or :class:`InputPaidMediaVideo` + """ + + def __init__(self, type, media, **kwargs): + self.type = type + self.media = media + + if service_utils.is_string(self.media): + self._media_name = '' + self._media_dic = self.media + else: + self._media_name = service_utils.generate_random_token() + self._media_dic = 'attach://{0}'.format(self._media_name) + + def to_json(self): + return json.dumps(self.to_dict()) + + def to_dict(self): + data = { + 'type': self.type, + 'media': self._media_dic + } + return data + +class InputPaidMediaPhoto(InputPaidMedia): + """ + The paid media to send is a photo. + + Telegram documentation: https://core.telegram.org/bots/api#inputpaidmediaphoto + + :param type: Type of the media, must be photo + :type type: :obj:`str` + + :param media: File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for + Telegram to get a file from the Internet, or pass “attach://” to upload a new one using multipart/form-data + under name. More information on Sending Files » + :type media: :obj:`str` + + :return: Instance of the class + :rtype: :class:`InputPaidMediaPhoto` + """ + + def __init__(self, media, **kwargs): + super().__init__(type='photo', media=media) + +class InputPaidMediaVideo(InputPaidMedia): + """ + The paid media to send is a video. + + Telegram documentation: https://core.telegram.org/bots/api#inputpaidmediavideo + + :param type: Type of the media, must be video + :type type: :obj:`str` + + :param media: File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for + Telegram to get a file from the Internet, or pass “attach://” to upload a new one using multipart/form-data + under name. More information on Sending Files » + :type media: :obj:`str` + + :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 thumbnail: :class:`InputFile` + + :param width: Optional. Video width + :type width: :obj:`int` + + :param height: Optional. Video height + :type height: :obj:`int` + + :param duration: Optional. Video duration in seconds + :type duration: :obj:`int` + + :param supports_streaming: Optional. Pass True if the uploaded video is suitable for streaming + :type supports_streaming: :obj:`bool` + + :return: Instance of the class + :rtype: :class:`InputPaidMediaVideo` + + """ + + def __init__(self, media, thumbnail=None, width=None, height=None, duration=None, supports_streaming=None, **kwargs): + super().__init__(type='video', media=media) + self.thumbnail = thumbnail + self.width = width + self.height = height + self.duration = duration + self.supports_streaming = supports_streaming + + def to_dict(self): + data = super().to_dict() + if self.thumbnail: + data['thumbnail'] = self.thumbnail + if self.width: + data['width'] = self.width + if self.height: + data['height'] = self.height + if self.duration: + data['duration'] = self.duration + if self.supports_streaming is not None: + data['supports_streaming'] = self.supports_streaming + return data + + \ No newline at end of file