Skip to content

Commit

Permalink
Merge branch 'master' into statesv2
Browse files Browse the repository at this point in the history
  • Loading branch information
coder2020official authored Jul 8, 2024
2 parents 4a7bc5d + 18834e4 commit 90a8f32
Show file tree
Hide file tree
Showing 11 changed files with 607 additions and 96 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/setup_python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12', 'pypy-3.8', 'pypy-3.9', 'pypy-3.10']
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12', 'pypy-3.9', 'pypy-3.10']
name: ${{ matrix.python-version }} and tests
steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.</p>
<p align="center">Both synchronous and asynchronous.</p>

## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#june-18-2024">7.5</a>!
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#july-1-2024">7.6</a>!

<h2><a href='https://pytba.readthedocs.io/en/latest/index.html'>Official documentation</a></h2>
<h2><a href='https://pytba.readthedocs.io/ru/latest/index.html'>Official ru documentation</a></h2>
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
copyright = f'2022-{datetime.now().year}, {author}'

# The full version, including alpha/beta/rc tags
release = '4.20.0'
release = '4.21.0'


# -- General configuration ---------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "pyTelegramBotAPI"
version = "4.20.0"
version = "4.21.0"
description = "Python Telegram bot api."
authors = [{name = "eternnoir", email = "[email protected]"}]
license = {text = "GPL2"}
Expand Down
132 changes: 97 additions & 35 deletions telebot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,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
Expand Down Expand Up @@ -2007,47 +2010,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(
Expand Down Expand Up @@ -2606,6 +2609,10 @@ def send_document(
logger.warning('The parameter "thumb" is deprecated. Use "thumbnail" instead.')
thumbnail = thumb

if isinstance(document, types.InputFile) and visible_file_name:
# inputfile name ignored, warn
logger.warning('Cannot use both InputFile and visible_file_name. InputFile name will be ignored.')

return types.Message.de_json(
apihelper.send_data(
self.token, chat_id, document, 'document',
Expand Down Expand Up @@ -3120,6 +3127,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(
Expand Down Expand Up @@ -4731,7 +4793,7 @@ def edit_message_text(
parse_mode=parse_mode, entities=entities, reply_markup=reply_markup, link_preview_options=link_preview_options,
business_connection_id=business_connection_id, timeout=timeout)

if type(result) == bool: # if edit inline message return is bool not Message.
if isinstance(result, bool): # if edit inline message return is bool not Message.
return result
return types.Message.de_json(result)

Expand Down Expand Up @@ -4778,7 +4840,7 @@ def edit_message_media(
self.token, media, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id,
reply_markup=reply_markup, business_connection_id=business_connection_id, timeout=timeout)

if type(result) == bool: # if edit inline message return is bool not Message.
if isinstance(result, bool): # if edit inline message return is bool not Message.
return result
return types.Message.de_json(result)

Expand Down Expand Up @@ -4820,7 +4882,7 @@ def edit_message_reply_markup(
self.token, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id,
reply_markup=reply_markup, business_connection_id=business_connection_id, timeout=timeout)

if type(result) == bool:
if isinstance(result, bool):
return result
return types.Message.de_json(result)

Expand Down Expand Up @@ -4954,7 +5016,7 @@ def set_game_score(
self.token, user_id, score, force=force, disable_edit_message=disable_edit_message,
chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id)

if type(result) == bool:
if isinstance(result, bool):
return result
return types.Message.de_json(result)

Expand Down Expand Up @@ -5618,7 +5680,7 @@ def edit_message_caption(
show_caption_above_media=show_caption_above_media, business_connection_id=business_connection_id,
timeout=timeout)

if type(result) == bool:
if isinstance(result, bool):
return result
return types.Message.de_json(result)

Expand Down
32 changes: 30 additions & 2 deletions telebot/apihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def _make_request(token, method_name, method='get', params=None, files=None):
# process types.InputFile
for key, value in files_copy.items():
if isinstance(value, types.InputFile):
files[key] = value.file
files[key] = (value.file_name, value.file)
elif isinstance(value, tuple) and (len(value) == 2) and isinstance(value[1], types.InputFile):
files[key] = (value[0], value[1].file)

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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://', '')
Expand Down
Loading

0 comments on commit 90a8f32

Please sign in to comment.