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!
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