Add support for forum topics

This commit is contained in:
wulan17 2023-10-12 22:48:12 +03:00 committed by KurimuzonAkuma
parent 85c2d7a885
commit 58f2254f4f
51 changed files with 1434 additions and 52 deletions

View File

@ -123,5 +123,14 @@ class ChatEventAction(AutoName):
MESSAGE_UNPINNED = auto()
"a message has been unpinned (see ``unpinned_message``)"
CREATED_FORUM_TOPIC = auto()
"a new forum topic has been created (see `created_forum_topic`)"
EDITED_FORUM_TOPIC = auto()
"a forum topic has been edited (see `old_forum_topic` and `new_forum_topic`)"
DELETED_FORUM_TOPIC = auto()
"a forum topic has been deleted (see `deleted_forum_topic`)"
UNKNOWN = auto()
"Unknown chat event action"

View File

@ -39,6 +39,24 @@ class MessageServiceType(AutoName):
DELETE_CHAT_PHOTO = auto()
"Deleted chat photo"
FORUM_TOPIC_CREATED = auto()
"a new forum topic created in the chat"
FORUM_TOPIC_CLOSED = auto()
"a new forum topic closed in the chat"
FORUM_TOPIC_REOPENED = auto()
"a new forum topic reopened in the chat"
FORUM_TOPIC_EDITED = auto()
"a new forum topic renamed in the chat"
GENERAL_TOPIC_HIDDEN = auto()
"a forum general topic hidden in the chat"
GENERAL_TOPIC_UNHIDDEN = auto()
"a forum general topic unhidden in the chat"
GROUP_CHAT_CREATED = auto()
"Group chat created"

View File

@ -21,6 +21,7 @@ from typing import Union
import pyrogram
from pyrogram import raw
from pyrogram import types
from pyrogram import utils
class SendGame:
@ -29,6 +30,7 @@ class SendGame:
chat_id: Union[int, str],
game_short_name: str,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
protect_content: bool = None,
reply_markup: Union[
@ -55,6 +57,10 @@ class SendGame:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs.
for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -84,7 +90,7 @@ class SendGame:
),
message="",
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
noforwards=protect_content,
reply_markup=await reply_markup.write(self) if reply_markup else None

View File

@ -20,6 +20,7 @@ from typing import Union
import pyrogram
from pyrogram import raw
from pyrogram import utils
class SendInlineBotResult:
@ -29,6 +30,7 @@ class SendInlineBotResult:
query_id: int,
result_id: str,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None
) -> "raw.base.Updates":
"""Send an inline bot result.
@ -52,6 +54,10 @@ class SendInlineBotResult:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs.
for supergroups only
reply_to_message_id (``bool``, *optional*):
If the message is a reply, ID of the original message.
@ -70,6 +76,6 @@ class SendInlineBotResult:
id=result_id,
random_id=self.rnd_id(),
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id)
)
)

View File

@ -20,12 +20,16 @@ from .add_chat_members import AddChatMembers
from .archive_chats import ArchiveChats
from .ban_chat_member import BanChatMember
from .create_channel import CreateChannel
from .create_forum_topic import CreateForumTopic
from .create_group import CreateGroup
from .create_supergroup import CreateSupergroup
from .close_forum_topic import CloseForumTopic
from .delete_channel import DeleteChannel
from .delete_chat_photo import DeleteChatPhoto
from .delete_forum_topic import DeleteForumTopic
from .delete_supergroup import DeleteSupergroup
from .delete_user_history import DeleteUserHistory
from .edit_forum_topic import EditForumTopic
from .get_chat import GetChat
from .get_chat_event_log import GetChatEventLog
from .get_chat_member import GetChatMember
@ -34,6 +38,8 @@ from .get_chat_members_count import GetChatMembersCount
from .get_chat_online_count import GetChatOnlineCount
from .get_dialogs import GetDialogs
from .get_dialogs_count import GetDialogsCount
from .get_forum_topics import GetForumTopics
from .get_forum_topics_by_id import GetForumTopicsByID
from .get_nearby_chats import GetNearbyChats
from .get_send_as_chats import GetSendAsChats
from .join_chat import JoinChat
@ -78,14 +84,20 @@ class Chats(
SetChatUsername,
SetChatPermissions,
GetDialogsCount,
GetForumTopics,
GetForumTopicsByID,
ArchiveChats,
UnarchiveChats,
CreateGroup,
CreateSupergroup,
CreateChannel,
CreateForumTopic,
CloseForumTopic,
AddChatMembers,
DeleteChannel,
DeleteForumTopic,
DeleteSupergroup,
EditForumTopic,
GetNearbyChats,
SetAdministratorTitle,
SetSlowMode,

View File

@ -0,0 +1,58 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw
from pyrogram import types
from typing import Union
class CloseForumTopic:
async def close_forum_topic(
self: "pyrogram.Client",
chat_id: Union[int, str],
topic_id: int
) -> bool:
"""Close a forum topic.
.. include:: /_includes/usable-by/users-bots.rst
Parameters:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
topic_id (``int``):
Unique identifier (int) of the target forum topic.
Returns:
`bool`: On success, a Boolean is returned.
Example:
.. code-block:: python
await app.close_forum_topic(chat_id, topic_id)
"""
await self.invoke(
raw.functions.channels.EditForumTopic(
channel=await self.resolve_peer(chat_id),
topic_id=topic_id,
closed=True
)
)
return True

View File

@ -0,0 +1,68 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw
from pyrogram import types
from typing import Union
class CreateForumTopic:
async def create_forum_topic(
self: "pyrogram.Client",
chat_id: Union[int, str],
title: str,
icon_color: int = None,
icon_emoji_id: int = None
) -> "types.ForumTopicCreated":
"""Create a new forum topic.
.. include:: /_includes/usable-by/users-bots.rst
Parameters:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
title (``str``):
The forum topic title.
icon_color (``int``, *optional*):
The color of forum topic icon.
icon_emoji_id (``int``, *optional*):
Unique identifier of the custom emoji shown as the topic icon
Returns:
:obj:`~pyrogram.types.ForumTopicCreated`: On success, a forum_topic_created object is returned.
Example:
.. code-block:: python
await app.create_forum_topic("Topic Title")
"""
r = await self.invoke(
raw.functions.channels.CreateForumTopic(
channel=await self.resolve_peer(chat_id),
title=title,
random_id=self.rnd_id(),
icon_color=icon_color,
icon_emoji_id=icon_emoji_id
)
)
return types.ForumTopicCreated._parse(r.updates[1].message)

View File

@ -0,0 +1,57 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw
from pyrogram import types
from typing import Union
class DeleteForumTopic:
async def delete_forum_topic(
self: "pyrogram.Client",
chat_id: Union[int, str],
topic_id: int
) -> bool:
"""Delete a forum topic.
.. include:: /_includes/usable-by/users-bots.rst
Parameters:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
topic_id (``int``):
Unique identifier (int) of the target forum topic.
Returns:
`bool`: On success, a Boolean is returned.
Example:
.. code-block:: python
await app.delete_forum_topic(chat_id, topic_id)
"""
await self.invoke(
raw.functions.channels.DeleteTopicHistory(
channel=await self.resolve_peer(chat_id),
top_msg_id=topic_id
)
)
return True

View File

@ -0,0 +1,77 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import pyrogram
from pyrogram import raw
from pyrogram import types
from typing import Union
class EditForumTopic:
async def edit_forum_topic(
self: "pyrogram.Client",
chat_id: Union[int, str],
topic_id: int,
title: str = None,
icon_emoji_id: int = None,
closed: bool = None,
hidden: bool = None
) -> bool:
"""Edit a forum topic.
.. include:: /_includes/usable-by/users-bots.rst
Parameters:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
topic_id (``int``):
Unique identifier (int) of the target forum topic.
title (``str``, *optional*):
The forum topic title.
icon_emoji_id (``int``, *optional*):
Unique identifier of the custom emoji shown as the topic icon.
closed (``bool``, *optional*):
Close forum topic.
hidden (``bool``, *optional*):
Hide forum topic.
Returns:
`bool`: On success, a Boolean is returned.
Example:
.. code-block:: python
await app.edit_forum_topic(chat_id,topic_id,"New Topic Title")
"""
await self.invoke(
raw.functions.channels.EditForumTopic(
channel=await self.resolve_peer(chat_id),
topic_id=topic_id,
title=title,
icon_emoji_id=icon_emoji_id,
closed=closed,
hidden=hidden
)
)
return True

View File

@ -0,0 +1,64 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Union, Optional, AsyncGenerator
import pyrogram
from pyrogram import raw
from pyrogram import types
class GetForumTopics:
async def get_forum_topics(
self: "pyrogram.Client",
chat_id: Union[int, str],
limit: int = 0
) -> Optional[AsyncGenerator["types.ForumTopic", None]]:
"""Get one or more topic from a chat.
.. include:: /_includes/usable-by/users.rst
Parameters:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
limit (``int``, *optional*):
Limits the number of topics to be retrieved.
Returns:
``Generator``: On success, a generator yielding :obj:`~pyrogram.types.ForumTopic` objects is returned.
Example:
.. code-block:: python
# get all forum topics
async for topic in app.get_forum_topics(chat_id):
print(topic)
"""
r = await self.invoke(
raw.functions.channels.GetForumTopics(
channel=await self.resolve_peer(chat_id),
offset_date=0,
offset_id=0,
offset_topic=0,
limit=limit
)
)
for topic in r.topics:
yield types.ForumTopic._parse(topic)

View File

@ -0,0 +1,79 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import logging
from typing import Union, List, Iterable
import pyrogram
from pyrogram import raw
from pyrogram import types
from pyrogram import utils
log = logging.getLogger(__name__)
class GetForumTopicsByID:
async def get_forum_topics_by_id(
self: "pyrogram.Client",
chat_id: Union[int, str],
topic_ids: Union[int, Iterable[int]]
) -> Union["types.ForumTopic", List["types.ForumTopic"]]:
"""Get one or more topic from a chat by using topic identifiers.
.. include:: /_includes/usable-by/users.rst
Parameters:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
topic_ids (``int`` | Iterable of ``int``, *optional*):
Pass a single topic identifier or an iterable of topic ids (as integers) to get the information of the
topic themselves.
Returns:
:obj:`~pyrogram.types.ForumTopic` | List of :obj:`~pyrogram.types.ForumTopic`: In case *topic_ids* was not
a list, a single topic is returned, otherwise a list of topics is returned.
Example:
.. code-block:: python
# Get one topic
await app.get_forum_topics_by_id(chat_id, 12345)
# Get more than one topic (list of topics)
await app.get_forum_topics_by_id(chat_id, [12345, 12346])
Raises:
ValueError: In case of invalid arguments.
"""
is_iterable = not isinstance(topic_ids, int)
ids = list(topic_ids) if is_iterable else [topic_ids]
r = await self.invoke(
raw.functions.channels.GetForumTopicsByID(
channel=await self.resolve_peer(chat_id),
topics=ids
)
)
topics = types.List()
for i in r:
topics.append(types.ForumTopic._parse(i))
return topics if is_iterable else topics[0]

View File

@ -92,6 +92,7 @@ class PromoteChatMember:
pin_messages=privileges.can_pin_messages,
add_admins=privileges.can_promote_members,
manage_call=privileges.can_manage_video_chats,
manage_topics=privileges.can_manage_topics,
other=privileges.can_manage_chat
),
rank=rank or ""

View File

@ -92,6 +92,7 @@ class RestrictChatMember:
change_info=not permissions.can_change_info,
invite_users=not permissions.can_invite_users,
pin_messages=not permissions.can_pin_messages,
manage_topics=not permissions.can_manage_topics,
)
)
)

View File

@ -80,6 +80,7 @@ class SetChatPermissions:
change_info=not permissions.can_change_info,
invite_users=not permissions.can_invite_users,
pin_messages=not permissions.can_pin_messages,
manage_topics=not permissions.can_manage_topics,
)
)
)

View File

@ -31,6 +31,7 @@ class CopyMediaGroup:
message_id: int,
captions: Union[List[str], str] = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
) -> List["types.Message"]:
@ -65,6 +66,10 @@ class CopyMediaGroup:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -81,7 +86,7 @@ class CopyMediaGroup:
await app.copy_media_group(to_chat, from_chat, 123)
await app.copy_media_group(to_chat, from_chat, 123, captions="single caption")
await app.copy_media_group(to_chat, from_chat, 123,
captions=["caption 1", None, ""])
"""
@ -119,7 +124,7 @@ class CopyMediaGroup:
peer=await self.resolve_peer(chat_id),
multi_media=multi_media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
schedule_date=utils.datetime_to_timestamp(schedule_date)
),
sleep_threshold=60

View File

@ -21,7 +21,7 @@ from datetime import datetime
from typing import Union, List, Optional
import pyrogram
from pyrogram import types, enums
from pyrogram import types, enums, utils
log = logging.getLogger(__name__)
@ -36,6 +36,7 @@ class CopyMessage:
parse_mode: Optional["enums.ParseMode"] = None,
caption_entities: List["types.MessageEntity"] = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -83,6 +84,10 @@ class CopyMessage:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -114,6 +119,7 @@ class CopyMessage:
parse_mode=parse_mode,
caption_entities=caption_entities,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
schedule_date=schedule_date,
protect_content=protect_content,

View File

@ -46,6 +46,7 @@ class SendAnimation:
thumb: Union[str, BinaryIO] = None,
file_name: str = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -115,6 +116,10 @@ class SendAnimation:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -230,7 +235,7 @@ class SendAnimation:
peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -44,6 +44,7 @@ class SendAudio:
thumb: Union[str, BinaryIO] = None,
file_name: str = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -108,6 +109,10 @@ class SendAudio:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -217,7 +222,7 @@ class SendAudio:
peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -34,6 +34,7 @@ class SendCachedMedia:
parse_mode: Optional["enums.ParseMode"] = None,
caption_entities: List["types.MessageEntity"] = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -76,12 +77,16 @@ class SendCachedMedia:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
schedule_date (:py:obj:`~datetime.datetime`, *optional*):
Date when the message will be automatically sent.
protect_content (``bool``, *optional*):
Protects the contents of the sent message from forwarding and saving.
@ -97,13 +102,12 @@ class SendCachedMedia:
await app.send_cached_media("me", file_id)
"""
r = await self.invoke(
raw.functions.messages.SendMedia(
peer=await self.resolve_peer(chat_id),
media=utils.get_input_media_from_file_id(file_id),
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -33,6 +33,7 @@ class SendContact:
last_name: str = None,
vcard: str = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -69,6 +70,10 @@ class SendContact:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -101,7 +106,7 @@ class SendContact:
),
message="",
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -30,6 +30,7 @@ class SendDice:
chat_id: Union[int, str],
emoji: str = "🎲",
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -61,6 +62,10 @@ class SendDice:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -89,13 +94,12 @@ class SendDice:
# Send a basketball
await app.send_dice(chat_id, "🏀")
"""
r = await self.invoke(
raw.functions.messages.SendMedia(
peer=await self.resolve_peer(chat_id),
media=raw.types.InputMediaDice(emoticon=emoji),
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -42,6 +42,7 @@ class SendDocument:
file_name: str = None,
force_document: bool = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -100,6 +101,10 @@ class SendDocument:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -195,7 +200,7 @@ class SendDocument:
peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -31,6 +31,7 @@ class SendLocation:
latitude: float,
longitude: float,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -61,6 +62,10 @@ class SendLocation:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message
@ -93,7 +98,7 @@ class SendLocation:
),
message="",
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -43,6 +43,7 @@ class SendMediaGroup:
"types.InputMediaDocument"
]],
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -64,6 +65,10 @@ class SendMediaGroup:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -395,7 +400,7 @@ class SendMediaGroup:
peer=await self.resolve_peer(chat_id),
multi_media=multi_media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content
),

View File

@ -33,6 +33,7 @@ class SendMessage:
entities: List["types.MessageEntity"] = None,
disable_web_page_preview: bool = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -70,6 +71,10 @@ class SendMessage:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -128,7 +133,7 @@ class SendMessage:
peer=await self.resolve_peer(chat_id),
no_webpage=disable_web_page_preview or None,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
reply_markup=await reply_markup.write(self) if reply_markup else None,

View File

@ -40,6 +40,7 @@ class SendPhoto:
has_spoiler: bool = None,
ttl_seconds: int = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -91,6 +92,10 @@ class SendPhoto:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -179,7 +184,7 @@ class SendPhoto:
peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -42,6 +42,7 @@ class SendPoll:
is_closed: bool = None,
disable_notification: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
reply_markup: Union[
@ -114,6 +115,10 @@ class SendPoll:
protect_content (``bool``, *optional*):
Protects the contents of the sent message from forwarding and saving.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -132,7 +137,6 @@ class SendPoll:
await app.send_poll(chat_id, "Is this a poll question?", ["Yes", "No", "Maybe"])
"""
solution, solution_entities = (await utils.parse_text_entities(
self, explanation, explanation_parse_mode, explanation_entities
)).values()
@ -161,7 +165,7 @@ class SendPoll:
),
message="",
silent=disable_notification,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -36,6 +36,7 @@ class SendSticker:
chat_id: Union[int, str],
sticker: Union[str, BinaryIO],
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -69,6 +70,10 @@ class SendSticker:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -154,7 +159,7 @@ class SendSticker:
peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -35,6 +35,7 @@ class SendVenue:
foursquare_id: str = "",
foursquare_type: str = "",
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -78,6 +79,10 @@ class SendVenue:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message
@ -117,7 +122,7 @@ class SendVenue:
),
message="",
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -47,6 +47,7 @@ class SendVideo:
file_name: str = None,
supports_streaming: bool = True,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -121,6 +122,10 @@ class SendVideo:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -236,7 +241,7 @@ class SendVideo:
peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -38,6 +38,7 @@ class SendVideoNote:
length: int = 1,
thumb: Union[str, BinaryIO] = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -83,6 +84,10 @@ class SendVideoNote:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message
@ -178,7 +183,7 @@ class SendVideoNote:
peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -40,6 +40,7 @@ class SendVoice:
caption_entities: List["types.MessageEntity"] = None,
duration: int = 0,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -86,6 +87,10 @@ class SendVoice:
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message
@ -179,7 +184,7 @@ class SendVoice:
peer=await self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
reply_to=utils.get_reply_to(reply_to_message_id, message_thread_id),
random_id=self.rnd_id(),
schedule_date=utils.datetime_to_timestamp(schedule_date),
noforwards=protect_content,

View File

@ -17,8 +17,9 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from .input_message_content import InputMessageContent
from .input_reply_to_message import InputReplyToMessage
from .input_text_message_content import InputTextMessageContent
__all__ = [
"InputMessageContent", "InputTextMessageContent"
"InputMessageContent", "InputReplyToMessage", "InputTextMessageContent"
]

View File

@ -0,0 +1,52 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram import raw
from ..object import Object
class InputReplyToMessage(Object):
"""Contains information about a target replied message.
Parameters:
reply_to_message_id (``int``, *optional*):
ID of the original message you want to reply.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
"""
def __init__(
self, *,
reply_to_message_id: int = None,
message_thread_id: int = None
):
super().__init__()
self.reply_to_message_id = reply_to_message_id
self.message_thread_id = message_thread_id
def write(self):
if not any((self.reply_to_message_id, self.message_thread_id)):
return None
return raw.types.InputReplyToMessage(
reply_to_msg_id=self.reply_to_message_id or message_thread_id, # type: ignore[arg-type]
top_msg_id=self.message_thread_id if self.reply_to_message_id else None,
).write()

View File

@ -21,6 +21,13 @@ from .audio import Audio
from .contact import Contact
from .dice import Dice
from .document import Document
from .forum_topic import ForumTopic
from .forum_topic_created import ForumTopicCreated
from .forum_topic_closed import ForumTopicClosed
from .forum_topic_reopened import ForumTopicReopened
from .forum_topic_edited import ForumTopicEdited
from .general_forum_topic_hidden import GeneralTopicHidden
from .general_forum_topic_unhidden import GeneralTopicUnhidden
from .game import Game
from .location import Location
from .message import Message
@ -41,7 +48,9 @@ from .web_page import WebPage
from .message_reactions import MessageReactions
__all__ = [
"Animation", "Audio", "Contact", "Document", "Game", "Location", "Message", "MessageEntity", "Photo", "Thumbnail",
"StrippedThumbnail", "Poll", "PollOption", "Sticker", "Venue", "Video", "VideoNote", "Voice", "WebPage", "Dice",
"Reaction", "WebAppData", "MessageReactions"
"Animation", "Audio", "Contact", "Document", "ForumTopic", "ForumTopicCreated",
"ForumTopicClosed", "ForumTopicReopened", "ForumTopicEdited", "GeneralTopicHidden",
"GeneralTopicUnhidden", "Game", "Location", "Message", "MessageEntity", "Photo", "Thumbnail",
"StrippedThumbnail", "Poll", "PollOption", "Sticker", "Venue", "Video", "VideoNote", "Voice",
"WebPage", "Dice", "Reaction", "WebAppData", "MessageReactions"
]

View File

@ -0,0 +1,150 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram import raw, types
from typing import Union
from ..object import Object
class ForumTopic(Object):
# todo
# notify_settings: `~pyrogram.types.PeerNotifySettings`
# draft: `~pyrogram.types.DraftMessage`
"""A forum topic.
Parameters:
id (``Integer``):
Id of the topic
date (``Integer``):
Date topic created
title (``String``):
Name of the topic
icon_color (``Integer``):
Color of the topic icon in RGB format
top_message (``Integer``):
N/A
read_inbox_max_id (``Integer``):
N/A
read_outbox_max_id (``Integer``):
N/A
unread_count (``Integer``):
N/A
unread_mentions_count (``Integer``):
N/A
unread_reactions_count (``Integer``):
N/A
from_id (:obj:`~pyrogram.types.PeerChannel` | :obj:`~pyrogram.types.PeerUser`):
Topic creator.
my (``Boolean``, *optional*):
N/A
closed (``Boolean``, *optional*):
N/A
pinned (``Boolean``, *optional*):
N/A
short (``Boolean``, *optional*):
N/A
icon_emoji_id (``Integer``, *optional*):
Unique identifier of the custom emoji shown as the topic icon
"""
def __init__(
self,
*,
id: int,
date: int,
title: str,
icon_color: int,
top_message: int,
read_inbox_max_id: int,
read_outbox_max_id: int,
unread_count: int,
unread_mentions_count: int,
unread_reactions_count: int,
from_id: Union["types.PeerChannel", "types.PeerUser"],
# notify_settings: "types.PeerNotifySettings", //todo
my: bool = None,
closed: bool = None,
pinned: bool = None,
short: bool = None,
icon_emoji_id: int = None,
# draft: "types.DraftMessage" = None //todo
):
super().__init__()
self.id = id
self.date = date
self.title = title
self.icon_color = icon_color
self.top_message = top_message
self.read_inbox_max_id = read_inbox_max_id
self.read_outbox_max_id = read_outbox_max_id
self.unread_count = unread_count
self.unread_mentions_count = unread_mentions_count
self.unread_reactions_count = unread_reactions_count
self.from_id = from_id
# self.notify_settings = notify_settings //todo
self.my = my
self.closed = closed
self.pinned = pinned
self.short = short
self.icon_emoji_id = icon_emoji_id
# self.draft = draft //todo
@staticmethod
def _parse(forum_topic: "raw.types.forum_topic") -> "ForumTopic":
from_id = forum_topic.from_id
if isinstance(from_id, raw.types.PeerChannel):
peer = types.PeerChannel._parse(from_id)
if isinstance(from_id, raw.types.PeerUser):
peer = types.PeerUser._parse(from_id)
return ForumTopic(
id=getattr(forum_topic, "id", None),
date=getattr(forum_topic, "date", None),
title=getattr(forum_topic, "title", None),
icon_color=getattr(forum_topic, "icon_color", None),
top_message=getattr(forum_topic, "top_message", None),
read_inbox_max_id=getattr(forum_topic, "read_inbox_max_id", None),
read_outbox_max_id=getattr(forum_topic, "read_outbox_max_id", None),
unread_count=getattr(forum_topic, "unread_count", None),
unread_mentions_count=getattr(forum_topic, "unread_mentions_count", None),
unread_reactions_count=getattr(forum_topic, "unread_reactions_count", None),
from_id=peer,
# notify_settings=None, //todo
my=getattr(forum_topic, "my", None),
closed=getattr(forum_topic, "closed", None),
pinned=getattr(forum_topic, "pinned", None),
short=getattr(forum_topic, "short", None),
icon_emoji_id=getattr(forum_topic, "icon_emoji_id", None),
# draft=None //todo
)

View File

@ -0,0 +1,29 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from ..object import Object
class ForumTopicClosed(Object):
"""A service message about a forum topic closed in the chat.
Currently holds no information.
"""
def __init__(self):
super().__init__()

View File

@ -0,0 +1,62 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram import raw
from ..object import Object
class ForumTopicCreated(Object):
"""A service message about a new forum topic created in the chat.
Parameters:
id (``Integer``):
Id of the topic
title (``String``):
Name of the topic.
icon_color (``Integer``):
Color of the topic icon in RGB format
icon_emoji_id (``Integer``, *optional*):
Unique identifier of the custom emoji shown as the topic icon
"""
def __init__(
self, *,
id: int,
title: str,
icon_color: int,
icon_emoji_id: int = None
):
super().__init__()
self.id = id
self.title = title
self.icon_color = icon_color
self.icon_emoji_id = icon_emoji_id
@staticmethod
def _parse(message: "raw.base.Message") -> "ForumTopicCreated":
return ForumTopicCreated(
id=getattr(message, "id", None),
title=getattr(message.action, "title", None),
icon_color=getattr(message.action, "icon_color", None),
icon_emoji_id=getattr(message.action, "icon_emoji_id", None)
)

View File

@ -0,0 +1,56 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram import raw
from ..object import Object
class ForumTopicEdited(Object):
"""A service message about a forum topic renamed in the chat.
Parameters:
title (``String``):
Name of the topic.
icon_color (``Integer``):
Color of the topic icon in RGB format
icon_custom_emoji_id (``String``, *optional*):
Unique identifier of the custom emoji shown as the topic icon
"""
def __init__(
self, *,
title: str = None,
icon_color: int = None,
icon_emoji_id: str = None
):
super().__init__()
self.title = title
self.icon_color = icon_color
self.icon_emoji_id = icon_emoji_id
@staticmethod
def _parse(action: "raw.types.MessageActionTopicEdit") -> "ForumTopicEdited":
return ForumTopicEdited(
title=getattr(action, "title", None),
icon_color=getattr(action, "icon_color", None),
icon_emoji_id=getattr(action, "icon_emoji_id", None)
)

View File

@ -0,0 +1,29 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from ..object import Object
class ForumTopicReopened(Object):
"""A service message about a forum topic reopened in the chat.
Currently holds no information.
"""
def __init__(self):
super().__init__()

View File

@ -0,0 +1,29 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from ..object import Object
class GeneralTopicHidden(Object):
"""A service message about a general topic hidden in the chat.
Currently holds no information.
"""
def __init__(self):
super().__init__()

View File

@ -0,0 +1,29 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from ..object import Object
class GeneralTopicUnhidden(Object):
"""A service message about a general topic unhidden in the chat.
Currently holds no information.
"""
def __init__(self):
super().__init__()

View File

@ -78,6 +78,9 @@ class Message(Object, Update):
chat (:obj:`~pyrogram.types.Chat`, *optional*):
Conversation the message belongs to.
topics (:obj:`~pyrogram.types.ForumTopic`, *optional*):
Topic the message belongs to.
forward_from (:obj:`~pyrogram.types.User`, *optional*):
For forwarded messages, sender of the original message.
@ -96,6 +99,13 @@ class Message(Object, Update):
forward_date (:py:obj:`~datetime.datetime`, *optional*):
For forwarded messages, date the original message was sent.
is_topic_message (``bool``, *optional*):
True, if the message is sent to a forum topic
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs.
for supergroups only
reply_to_message_id (``int``, *optional*):
The id of the message which this message directly replied to.
@ -257,8 +267,8 @@ class Message(Object, Update):
views (``int``, *optional*):
Channel post views.
forwards (``int``, *optional*):
forwards (``int``, *optional*):
Channel post forwards.
via_bot (:obj:`~pyrogram.types.User`):
@ -279,6 +289,24 @@ class Message(Object, Update):
E.g.: "/start 1 2 3" would produce ["start", "1", "2", "3"].
Only applicable when using :obj:`~pyrogram.filters.command`.
forum_topic_created (:obj:`~pyrogram.types.ForumTopicCreated`, *optional*):
Service message: forum topic created
forum_topic_closed (:obj:`~pyrogram.types.ForumTopicClosed`, *optional*):
Service message: forum topic closed
forum_topic_reopened (:obj:`~pyrogram.types.ForumTopicReopened`, *optional*):
Service message: forum topic reopened
forum_topic_edited (:obj:`~pyrogram.types.ForumTopicEdited`, *optional*):
Service message: forum topic edited
general_topic_hidden (:obj:`~pyrogram.types.GeneralTopicHidden`, *optional*):
Service message: forum general topic hidden
general_topic_unhidden (:obj:`~pyrogram.types.GeneralTopicUnhidden`, *optional*):
Service message: forum general topic unhidden
video_chat_scheduled (:obj:`~pyrogram.types.VideoChatScheduled`, *optional*):
Service message: voice chat scheduled.
@ -316,12 +344,15 @@ class Message(Object, Update):
sender_chat: "types.Chat" = None,
date: datetime = None,
chat: "types.Chat" = None,
topics: "types.ForumTopic" = None,
forward_from: "types.User" = None,
forward_sender_name: str = None,
forward_from_chat: "types.Chat" = None,
forward_from_message_id: int = None,
forward_signature: str = None,
forward_date: datetime = None,
is_topic_message: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_to_top_message_id: int = None,
reply_to_message: "Message" = None,
@ -373,6 +404,12 @@ class Message(Object, Update):
outgoing: bool = None,
matches: List[Match] = None,
command: List[str] = None,
forum_topic_created: "types.ForumTopicCreated" = None,
forum_topic_closed: "types.ForumTopicClosed" = None,
forum_topic_reopened: "types.ForumTopicReopened" = None,
forum_topic_edited: "types.ForumTopicEdited" = None,
general_topic_hidden: "types.GeneralTopicHidden" = None,
general_topic_unhidden: "types.GeneralTopicUnhidden" = None,
video_chat_scheduled: "types.VideoChatScheduled" = None,
video_chat_started: "types.VideoChatStarted" = None,
video_chat_ended: "types.VideoChatEnded" = None,
@ -393,12 +430,15 @@ class Message(Object, Update):
self.sender_chat = sender_chat
self.date = date
self.chat = chat
self.topics = topics
self.forward_from = forward_from
self.forward_sender_name = forward_sender_name
self.forward_from_chat = forward_from_chat
self.forward_from_message_id = forward_from_message_id
self.forward_signature = forward_signature
self.forward_date = forward_date
self.is_topic_message = is_topic_message
self.message_thread_id = message_thread_id
self.reply_to_message_id = reply_to_message_id
self.reply_to_top_message_id = reply_to_top_message_id
self.reply_to_message = reply_to_message
@ -451,6 +491,12 @@ class Message(Object, Update):
self.matches = matches
self.command = command
self.reply_markup = reply_markup
self.forum_topic_created = forum_topic_created
self.forum_topic_closed = forum_topic_closed
self.forum_topic_reopened = forum_topic_reopened
self.forum_topic_edited = forum_topic_edited
self.general_topic_hidden = general_topic_hidden
self.general_topic_unhidden = general_topic_unhidden
self.video_chat_scheduled = video_chat_scheduled
self.video_chat_started = video_chat_started
self.video_chat_ended = video_chat_ended
@ -464,6 +510,7 @@ class Message(Object, Update):
message: raw.base.Message,
users: dict,
chats: dict,
topics: dict = None,
is_scheduled: bool = False,
replies: int = 1
):
@ -491,6 +538,7 @@ class Message(Object, Update):
users.update({i.id: i for i in r})
if isinstance(message, raw.types.MessageService):
message_thread_id = None
action = message.action
new_chat_members = None
@ -502,6 +550,13 @@ class Message(Object, Update):
group_chat_created = None
channel_chat_created = None
new_chat_photo = None
is_topic_message = None
forum_topic_created = None
forum_topic_closed = None
forum_topic_reopened = None
forum_topic_edited = None
general_topic_hidden = None
general_topic_unhidden = None
video_chat_scheduled = None
video_chat_started = None
video_chat_ended = None
@ -540,6 +595,26 @@ class Message(Object, Update):
elif isinstance(action, raw.types.MessageActionChatEditPhoto):
new_chat_photo = types.Photo._parse(client, action.photo)
service_type = enums.MessageServiceType.NEW_CHAT_PHOTO
elif isinstance(action, raw.types.MessageActionTopicCreate):
forum_topic_created = types.ForumTopicCreated._parse(message)
service_type = enums.MessageServiceType.FORUM_TOPIC_CREATED
elif isinstance(action, raw.types.MessageActionTopicEdit):
if action.title:
forum_topic_edited = types.ForumTopicEdited._parse(action)
service_type = enums.MessageServiceType.FORUM_TOPIC_EDITED
elif action.hidden:
general_topic_hidden = types.GeneralTopicHidden()
service_type = enums.MessageServiceType.GENERAL_TOPIC_HIDDEN
elif action.closed:
forum_topic_closed = types.ForumTopicClosed()
service_type = enums.MessageServiceType.FORUM_TOPIC_CLOSED
else:
if hasattr(action, "hidden"):
general_topic_unhidden = types.GeneralTopicUnhidden()
service_type = enums.MessageServiceType.GENERAL_TOPIC_UNHIDDEN
else:
forum_topic_reopened = types.ForumTopicReopened()
service_type = enums.MessageServiceType.FORUM_TOPIC_REOPENED
elif isinstance(action, raw.types.MessageActionGroupCallScheduled):
video_chat_scheduled = types.VideoChatScheduled._parse(action)
service_type = enums.MessageServiceType.VIDEO_CHAT_SCHEDULED
@ -562,8 +637,10 @@ class Message(Object, Update):
parsed_message = Message(
id=message.id,
message_thread_id=message_thread_id,
date=utils.timestamp_to_datetime(message.date),
chat=types.Chat._parse(client, message, users, chats, is_chat=True),
topics=None,
from_user=from_user,
sender_chat=sender_chat,
service=service_type,
@ -576,6 +653,13 @@ class Message(Object, Update):
migrate_from_chat_id=-migrate_from_chat_id if migrate_from_chat_id else None,
group_chat_created=group_chat_created,
channel_chat_created=channel_chat_created,
is_topic_message=is_topic_message,
forum_topic_created=forum_topic_created,
forum_topic_closed=forum_topic_closed,
forum_topic_reopened=forum_topic_reopened,
forum_topic_edited=forum_topic_edited,
general_topic_hidden=general_topic_hidden,
general_topic_unhidden=general_topic_unhidden,
video_chat_scheduled=video_chat_scheduled,
video_chat_started=video_chat_started,
video_chat_ended=video_chat_ended,
@ -614,9 +698,18 @@ class Message(Object, Update):
client.message_cache[(parsed_message.chat.id, parsed_message.id)] = parsed_message
if message.reply_to:
if message.reply_to.forum_topic:
if message.reply_to.reply_to_top_id:
parsed_message.message_thread_id = message.reply_to.reply_to_top_id
else:
parsed_message.message_thread_id = message.reply_to.reply_to_msg_id
parsed_message.is_topic_message = True
return parsed_message
if isinstance(message, raw.types.Message):
message_thread_id = None
entities = [types.MessageEntity._parse(client, entity, users) for entity in message.entities]
entities = types.List(filter(lambda x: x is not None, entities))
@ -626,6 +719,7 @@ class Message(Object, Update):
forward_from_message_id = None
forward_signature = None
forward_date = None
is_topic_message = None
forward_header = message.fwd_from # type: raw.types.MessageFwdHeader
@ -760,8 +854,10 @@ class Message(Object, Update):
parsed_message = Message(
id=message.id,
message_thread_id=message_thread_id,
date=utils.timestamp_to_datetime(message.date),
chat=types.Chat._parse(client, message, users, chats, is_chat=True),
topics=None,
from_user=from_user,
sender_chat=sender_chat,
text=(
@ -793,6 +889,7 @@ class Message(Object, Update):
forward_from_message_id=forward_from_message_id,
forward_signature=forward_signature,
forward_date=forward_date,
is_topic_message=is_topic_message,
mentioned=message.mentioned,
scheduled=is_scheduled,
from_scheduled=message.from_scheduled,
@ -824,8 +921,26 @@ class Message(Object, Update):
)
if message.reply_to:
parsed_message.reply_to_message_id = message.reply_to.reply_to_msg_id
parsed_message.reply_to_top_message_id = message.reply_to.reply_to_top_id
if message.reply_to.forum_topic:
if message.reply_to.reply_to_top_id:
thread_id = message.reply_to.reply_to_top_id
parsed_message.reply_to_message_id = message.reply_to.reply_to_msg_id
else:
thread_id = message.reply_to.reply_to_msg_id
parsed_message.message_thread_id = thread_id
parsed_message.is_topic_message = True
if topics:
parsed_message.topics = types.ForumTopic._parse(topics[thread_id])
else:
try:
msg = await client.get_messages(parsed_message.chat.id,message.id)
if getattr(msg, "topics"):
parsed_message.topics = msg.topics
except Exception:
pass
else:
parsed_message.reply_to_message_id = message.reply_to.reply_to_msg_id
parsed_message.reply_to_top_message_id = message.reply_to.reply_to_top_id
if replies:
try:
@ -838,8 +953,8 @@ class Message(Object, Update):
reply_to_message_ids=message.id,
replies=replies - 1
)
parsed_message.reply_to_message = reply_to_message
if reply_to_message and not reply_to_message.forum_topic_created:
parsed_message.reply_to_message = reply_to_message
except MessageIdsEmpty:
pass
@ -860,24 +975,24 @@ class Message(Object, Update):
async def get_media_group(self) -> List["types.Message"]:
"""Bound method *get_media_group* of :obj:`~pyrogram.types.Message`.
Use as a shortcut for:
.. code-block:: python
await client.get_media_group(
chat_id=message.chat.id,
message_id=message.id
)
Example:
.. code-block:: python
await message.get_media_group()
Returns:
List of :obj:`~pyrogram.types.Message`: On success, a list of messages of the media group is returned.
Raises:
ValueError: In case the passed message id doesn't belong to a media group.
"""
@ -895,6 +1010,7 @@ class Message(Object, Update):
entities: List["types.MessageEntity"] = None,
disable_web_page_preview: bool = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -942,6 +1058,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -974,6 +1093,7 @@ class Message(Object, Update):
entities=entities,
disable_web_page_preview=disable_web_page_preview,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
schedule_date=schedule_date,
protect_content=protect_content,
@ -1001,6 +1121,7 @@ class Message(Object, Update):
"types.ReplyKeyboardRemove",
"types.ForceReply"
] = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
progress: Callable = None,
progress_args: tuple = ()
@ -1065,6 +1186,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -1120,6 +1244,7 @@ class Message(Object, Update):
height=height,
thumb=thumb,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup,
progress=progress,
@ -1138,6 +1263,7 @@ class Message(Object, Update):
title: str = None,
thumb: str = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -1205,6 +1331,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -1259,6 +1388,7 @@ class Message(Object, Update):
title=title,
thumb=thumb,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup,
progress=progress,
@ -1273,6 +1403,7 @@ class Message(Object, Update):
parse_mode: Optional["enums.ParseMode"] = None,
caption_entities: List["types.MessageEntity"] = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -1321,6 +1452,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -1347,6 +1481,7 @@ class Message(Object, Update):
parse_mode=parse_mode,
caption_entities=caption_entities,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup
)
@ -1396,6 +1531,7 @@ class Message(Object, Update):
last_name: str = "",
vcard: str = "",
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -1443,6 +1579,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -1469,6 +1608,7 @@ class Message(Object, Update):
last_name=last_name,
vcard=vcard,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup
)
@ -1484,6 +1624,7 @@ class Message(Object, Update):
file_name: str = None,
force_document: bool = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
reply_markup: Union[
@ -1538,7 +1679,7 @@ class Message(Object, Update):
caption_entities (List of :obj:`~pyrogram.types.MessageEntity`):
List of special entities that appear in the caption, which can be specified instead of *parse_mode*.
file_name (``str``, *optional*):
File name of the document sent.
Defaults to file's path basename.
@ -1552,9 +1693,12 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
schedule_date (:py:obj:`~datetime.datetime`, *optional*):
Date when the message will be automatically sent.
@ -1608,6 +1752,7 @@ class Message(Object, Update):
file_name=file_name,
force_document=force_document,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
schedule_date=schedule_date,
reply_markup=reply_markup,
@ -1620,6 +1765,7 @@ class Message(Object, Update):
game_short_name: str,
quote: bool = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -1657,6 +1803,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -1680,6 +1829,7 @@ class Message(Object, Update):
chat_id=self.chat.id,
game_short_name=game_short_name,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup
)
@ -1690,6 +1840,7 @@ class Message(Object, Update):
result_id: str,
quote: bool = None,
disable_notification: bool = None,
message_thread_id: bool = None,
reply_to_message_id: int = None
) -> "Message":
"""Bound method *reply_inline_bot_result* of :obj:`~pyrogram.types.Message`.
@ -1725,6 +1876,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``bool``, *optional*):
If the message is a reply, ID of the original message.
@ -1745,6 +1899,7 @@ class Message(Object, Update):
query_id=query_id,
result_id=result_id,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id
)
@ -1754,6 +1909,7 @@ class Message(Object, Update):
longitude: float,
quote: bool = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -1795,6 +1951,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message
@ -1819,6 +1978,7 @@ class Message(Object, Update):
latitude=latitude,
longitude=longitude,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup
)
@ -1828,6 +1988,7 @@ class Message(Object, Update):
media: List[Union["types.InputMediaPhoto", "types.InputMediaVideo"]],
quote: bool = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None
) -> List["types.Message"]:
"""Bound method *reply_media_group* of :obj:`~pyrogram.types.Message`.
@ -1861,6 +2022,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -1881,6 +2045,7 @@ class Message(Object, Update):
chat_id=self.chat.id,
media=media,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id
)
@ -1894,6 +2059,7 @@ class Message(Object, Update):
has_spoiler: bool = None,
ttl_seconds: int = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -1954,6 +2120,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -2006,6 +2175,7 @@ class Message(Object, Update):
has_spoiler=has_spoiler,
ttl_seconds=ttl_seconds,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup,
progress=progress,
@ -2029,6 +2199,7 @@ class Message(Object, Update):
quote: bool = None,
disable_notification: bool = None,
protect_content: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
reply_markup: Union[
@ -2114,6 +2285,9 @@ class Message(Object, Update):
protect_content (``bool``, *optional*):
Protects the contents of the sent message from forwarding and saving.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -2152,6 +2326,7 @@ class Message(Object, Update):
is_closed=is_closed,
disable_notification=disable_notification,
protect_content=protect_content,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
schedule_date=schedule_date,
reply_markup=reply_markup
@ -2162,6 +2337,7 @@ class Message(Object, Update):
sticker: Union[str, BinaryIO],
quote: bool = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -2204,6 +2380,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -2251,6 +2430,7 @@ class Message(Object, Update):
chat_id=self.chat.id,
sticker=sticker,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup,
progress=progress,
@ -2267,6 +2447,7 @@ class Message(Object, Update):
foursquare_id: str = "",
foursquare_type: str = "",
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -2323,6 +2504,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message
@ -2351,6 +2535,7 @@ class Message(Object, Update):
foursquare_id=foursquare_id,
foursquare_type=foursquare_type,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup
)
@ -2370,6 +2555,7 @@ class Message(Object, Update):
thumb: str = None,
supports_streaming: bool = True,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -2448,6 +2634,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -2505,6 +2694,7 @@ class Message(Object, Update):
thumb=thumb,
supports_streaming=supports_streaming,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup,
progress=progress,
@ -2519,6 +2709,7 @@ class Message(Object, Update):
length: int = 1,
thumb: str = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -2573,6 +2764,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message
@ -2623,6 +2817,7 @@ class Message(Object, Update):
length=length,
thumb=thumb,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup,
progress=progress,
@ -2638,6 +2833,7 @@ class Message(Object, Update):
caption_entities: List["types.MessageEntity"] = None,
duration: int = 0,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
reply_markup: Union[
"types.InlineKeyboardMarkup",
@ -2693,6 +2889,9 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message
@ -2744,6 +2943,7 @@ class Message(Object, Update):
caption_entities=caption_entities,
duration=duration,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup,
progress=progress,
@ -2945,6 +3145,7 @@ class Message(Object, Update):
async def forward(
self,
chat_id: Union[int, str],
message_thread_id: int = None,
disable_notification: bool = None,
schedule_date: datetime = None
) -> Union["types.Message", List["types.Message"]]:
@ -2971,6 +3172,9 @@ class Message(Object, Update):
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
message_thread_id (``int``, *optional*):
Unique identifier of a message thread to which the message belongs; for supergroups only
disable_notification (``bool``, *optional*):
Sends the message silently.
Users will receive a notification with no sound.
@ -2988,6 +3192,7 @@ class Message(Object, Update):
chat_id=chat_id,
from_chat_id=self.chat.id,
message_ids=self.id,
message_thread_id=message_thread_id,
disable_notification=disable_notification,
schedule_date=schedule_date
)
@ -2999,6 +3204,7 @@ class Message(Object, Update):
parse_mode: Optional["enums.ParseMode"] = None,
caption_entities: List["types.MessageEntity"] = None,
disable_notification: bool = None,
message_thread_id: int = None,
reply_to_message_id: int = None,
schedule_date: datetime = None,
protect_content: bool = None,
@ -3048,6 +3254,10 @@ class Message(Object, Update):
Sends the message silently.
Users will receive a notification with no sound.
message_thread_id (``int``, *optional*):
Unique identifier for the target message thread (topic) of the forum.
for forum supergroups only.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
@ -3085,6 +3295,7 @@ class Message(Object, Update):
parse_mode=enums.ParseMode.DISABLED,
disable_web_page_preview=not self.web_page,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
schedule_date=schedule_date,
protect_content=protect_content,
@ -3095,6 +3306,7 @@ class Message(Object, Update):
self._client.send_cached_media,
chat_id=chat_id,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
reply_to_message_id=reply_to_message_id,
schedule_date=schedule_date,
protect_content=protect_content,
@ -3125,6 +3337,7 @@ class Message(Object, Update):
last_name=self.contact.last_name,
vcard=self.contact.vcard,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
schedule_date=schedule_date
)
elif self.location:
@ -3133,6 +3346,7 @@ class Message(Object, Update):
latitude=self.location.latitude,
longitude=self.location.longitude,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
schedule_date=schedule_date
)
elif self.venue:
@ -3145,6 +3359,7 @@ class Message(Object, Update):
foursquare_id=self.venue.foursquare_id,
foursquare_type=self.venue.foursquare_type,
disable_notification=disable_notification,
message_thread_id=message_thread_id,
schedule_date=schedule_date
)
elif self.poll:
@ -3153,19 +3368,24 @@ class Message(Object, Update):
question=self.poll.question,
options=[opt.text for opt in self.poll.options],
disable_notification=disable_notification,
message_thread_id=message_thread_id,
schedule_date=schedule_date
)
elif self.game:
return await self._client.send_game(
chat_id,
game_short_name=self.game.short_name,
disable_notification=disable_notification
disable_notification=disable_notification,
message_thread_id=message_thread_id
)
else:
raise ValueError("Unknown media type")
if self.sticker or self.video_note: # Sticker and VideoNote should have no caption
return await send_media(file_id=file_id)
return await send_media(
file_id=file_id,
message_thread_id=message_thread_id
)
else:
if caption is None:
caption = self.caption or ""
@ -3175,7 +3395,8 @@ class Message(Object, Update):
file_id=file_id,
caption=caption,
parse_mode=parse_mode,
caption_entities=caption_entities
caption_entities=caption_entities,
message_thread_id=message_thread_id
)
else:
raise ValueError("Can't copy this message")
@ -3359,7 +3580,7 @@ class Message(Object, Update):
emoji (``str``, *optional*):
Reaction emoji.
Pass "" as emoji (default) to retract the reaction.
big (``bool``, *optional*):
Pass True to show a bigger and longer reaction.
Defaults to False.

View File

@ -34,6 +34,8 @@ from .dialog import Dialog
from .emoji_status import EmojiStatus
from .invite_link_importer import InviteLinkImporter
from .restriction import Restriction
from .peer_channel import PeerChannel
from .peer_user import PeerUser
from .user import User
from .username import Username
from .video_chat_ended import VideoChatEnded
@ -48,6 +50,8 @@ __all__ = [
"ChatPhoto",
"ChatPreview",
"Dialog",
"PeerChannel",
"PeerUser",
"User",
"Username",
"Restriction",

View File

@ -36,6 +36,9 @@ class Chat(Object):
type (:obj:`~pyrogram.enums.ChatType`):
Type of chat.
is_forum (``bool``, *optional*):
True, if the supergroup chat is a forum
is_verified (``bool``, *optional*):
True, if this chat has been verified by Telegram. Supergroups, channels and bots only.
@ -146,6 +149,7 @@ class Chat(Object):
client: "pyrogram.Client" = None,
id: int,
type: "enums.ChatType",
is_forum: bool = None,
is_verified: bool = None,
is_participants_hidden: bool = None,
is_restricted: bool = None,
@ -179,6 +183,7 @@ class Chat(Object):
self.id = id
self.type = type
self.is_forum = is_forum
self.is_verified = is_verified
self.is_participants_hidden = is_participants_hidden
self.is_restricted = is_restricted
@ -258,6 +263,7 @@ class Chat(Object):
return Chat(
id=peer_id,
type=enums.ChatType.SUPERGROUP if getattr(channel, "megagroup", None) else enums.ChatType.CHANNEL,
is_forum=getattr(channel, "forum", None),
is_verified=getattr(channel, "verified", None),
is_restricted=getattr(channel, "restricted", None),
is_creator=getattr(channel, "creator", None),

View File

@ -130,6 +130,18 @@ class ChatEvent(Object):
deleted_invite_link (:obj:`~pyrogram.types.ChatInviteLink`, *optional*):
Deleted invite link.
For :obj:`~pyrogram.enums.ChatEventAction.INVITE_LINK_DELETED` action only.
created_forum_topic (:obj:`~pyrogram.types.ForumTopic`, *optional*):
New forum topic.
For :obj:`~pyrogram.enums.ChatEvenAction.CREATED_FORUM_TOPIC` action only.
old_forum_topic, new_forum_topic (:obj:`~pyrogram.types.ForumTopic`, *optional*):
Edited forum topic.
For :obj:`~pyrogram.enums.ChatEvenAction.EDITED_FORUM_TOPIC` action only.
deleted_forum_topic (:obj:`~pyrogram.types.ForumTopic`, *optional*):
Deleted forum topic.
For :obj:`~pyrogram.enums.ChatEvenAction.DELETED_FORUM_TOPIC` action only.
"""
def __init__(
@ -190,7 +202,12 @@ class ChatEvent(Object):
old_invite_link: "types.ChatInviteLink" = None,
new_invite_link: "types.ChatInviteLink" = None,
revoked_invite_link: "types.ChatInviteLink" = None,
deleted_invite_link: "types.ChatInviteLink" = None
deleted_invite_link: "types.ChatInviteLink" = None,
created_forum_topic: "types.ForumTopic" = None,
old_forum_topic: "types.ForumTopic" = None,
new_forum_topic: "types.ForumTopic" = None,
deleted_forum_topic: "types.ForumTopic" = None
):
super().__init__()
@ -252,6 +269,11 @@ class ChatEvent(Object):
self.revoked_invite_link = revoked_invite_link
self.deleted_invite_link = deleted_invite_link
self.created_forum_topic = created_forum_topic
self.old_forum_topic = old_forum_topic
self.new_forum_topic = new_forum_topic
self.deleted_forum_topic = deleted_forum_topic
@staticmethod
async def _parse(
client: "pyrogram.Client",
@ -318,6 +340,11 @@ class ChatEvent(Object):
revoked_invite_link: Optional[types.ChatInviteLink] = None
deleted_invite_link: Optional[types.ChatInviteLink] = None
created_forum_topic: Optional[types.ForumTopic] = None
old_forum_topic: Optional[types.ForumTopic] = None
new_forum_topic: Optional[types.ForumTopic] = None
deleted_forum_topic: Optional[types.ForumTopic] = None
if isinstance(action, raw.types.ChannelAdminLogEventActionChangeAbout):
old_description = action.prev_value
new_description = action.new_value
@ -426,6 +453,19 @@ class ChatEvent(Object):
deleted_invite_link = types.ChatInviteLink._parse(client, action.invite, users)
action = enums.ChatEventAction.INVITE_LINK_DELETED
elif isinstance(action, raw.types.ChannelAdminLogEventActionCreateTopic):
created_forum_topic = types.ForumTopic._parse(action.topic)
action = enums.ChatEventAction.CREATED_FORUM_TOPIC
elif isinstance(action, raw.types.ChannelAdminLogEventActionEditTopic):
old_forum_topic = types.ForumTopic._parse(action.prev_topic)
new_forum_topic = types.ForumTopic._parse(action.new_topic)
action = enums.ChatEventAction.EDITED_FORUM_TOPIC
elif isinstance(action, raw.types.ChannelAdminLogEventActionDeleteTopic):
created_forum_topic = types.ForumTopic._parse(action.topic)
action = enums.ChatEventAction.DELETED_FORUM_TOPIC
else:
action = f"{enums.ChatEventAction.UNKNOWN}-{action.QUALNAME}"
@ -485,5 +525,10 @@ class ChatEvent(Object):
old_invite_link=old_invite_link,
new_invite_link=new_invite_link,
revoked_invite_link=revoked_invite_link,
deleted_invite_link=deleted_invite_link
deleted_invite_link=deleted_invite_link,
created_forum_topic=created_forum_topic,
old_forum_topic=old_forum_topic,
new_forum_topic=new_forum_topic,
deleted_forum_topic=deleted_forum_topic
)

View File

@ -53,6 +53,10 @@ class ChatPermissions(Object):
can_pin_messages (``bool``, *optional*):
True, if the user is allowed to pin messages.
Ignored in public supergroups.
can_manage_topics (``bool``, *optional*):
True, if the user is allowed to create, rename, close, and reopen forum topics.
supergroups only.
"""
def __init__(
@ -65,7 +69,8 @@ class ChatPermissions(Object):
can_add_web_page_previews: bool = None,
can_change_info: bool = None,
can_invite_users: bool = None,
can_pin_messages: bool = None
can_pin_messages: bool = None,
can_manage_topics: bool = None
):
super().__init__(None)
@ -77,6 +82,7 @@ class ChatPermissions(Object):
self.can_change_info = can_change_info
self.can_invite_users = can_invite_users
self.can_pin_messages = can_pin_messages
self.can_manage_topics = can_manage_topics
@staticmethod
def _parse(denied_permissions: "raw.base.ChatBannedRights") -> "ChatPermissions":
@ -94,5 +100,6 @@ class ChatPermissions(Object):
can_send_polls=not denied_permissions.send_polls,
can_change_info=not denied_permissions.change_info,
can_invite_users=not denied_permissions.invite_users,
can_pin_messages=not denied_permissions.pin_messages
can_pin_messages=not denied_permissions.pin_messages,
can_manage_topics=not denied_permissions.manage_topics
)

View File

@ -62,6 +62,10 @@ class ChatPrivileges(Object):
Groups and supergroups only.
True, if the user is allowed to pin messages.
can_manage_topics (``bool``, *optional*):
supergroups only.
True, if the user is allowed to create, rename, close, and reopen forum topics.
is_anonymous (``bool``, *optional*):
True, if the user's presence in the chat is hidden.
"""
@ -79,6 +83,7 @@ class ChatPrivileges(Object):
can_edit_messages: bool = False, # Channels only
can_invite_users: bool = False,
can_pin_messages: bool = False, # Groups and supergroups only
can_manage_topics: bool = False, # Supergroups only
is_anonymous: bool = False
):
super().__init__(None)
@ -93,6 +98,7 @@ class ChatPrivileges(Object):
self.can_edit_messages: bool = can_edit_messages
self.can_invite_users: bool = can_invite_users
self.can_pin_messages: bool = can_pin_messages
self.can_manage_topics: bool = can_manage_topics
self.is_anonymous: bool = is_anonymous
@staticmethod
@ -108,5 +114,6 @@ class ChatPrivileges(Object):
can_edit_messages=admin_rights.edit_messages,
can_invite_users=admin_rights.invite_users,
can_pin_messages=admin_rights.pin_messages,
can_manage_topics=admin_rights.manage_topics,
is_anonymous=admin_rights.anonymous
)

View File

@ -0,0 +1,44 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram import raw
from ..object import Object
class PeerChannel(Object):
"""A PeerChannel.
Parameters:
channel_id (``int``):
Id of the channel.
"""
def __init__(
self, *,
channel_id: int
):
super().__init__()
self.channel_id = channel_id
@staticmethod
def _parse(action: "raw.types.PeerChannel") -> "PeerChannel":
return PeerChannel(
channel_id=getattr(action, "channel_id", None)
)

View File

@ -0,0 +1,44 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram import raw
from ..object import Object
class PeerUser(Object):
"""A PeerUser.
Parameters:
user_id (``int``):
Id of the user.
"""
def __init__(
self, *,
user_id: int
):
super().__init__()
self.user_id = user_id
@staticmethod
def _parse(action: "raw.types.PeerUser") -> "PeerUser":
return PeerUser(
user_id=getattr(action, "user_id", None)
)

View File

@ -91,6 +91,7 @@ async def parse_messages(
) -> List["types.Message"]:
users = {i.id: i for i in messages.users}
chats = {i.id: i for i in messages.chats}
topics = {i.id: i for i in messages.topics} if hasattr(messages, "topics") else None
if not messages.messages:
return types.List()
@ -98,7 +99,7 @@ async def parse_messages(
parsed_messages = []
for message in messages.messages:
parsed_messages.append(await types.Message._parse(client, message, users, chats, replies=0))
parsed_messages.append(await types.Message._parse(client, message, users, chats, topics, replies=0))
if replies:
messages_with_replies = {
@ -128,7 +129,8 @@ async def parse_messages(
for reply in reply_messages:
if reply.id == reply_id:
message.reply_to_message = reply
if not reply.forum_topic_created:
message.reply_to_message = reply
return types.List(parsed_messages)
@ -245,6 +247,17 @@ def get_peer_type(peer_id: int) -> str:
raise ValueError(f"Peer id invalid: {peer_id}")
def get_reply_to(
reply_to_message_id: Optional[int],
message_thread_id: Optional[int],
) -> Optional[raw.types.InputReplyToMessage]:
if not any((reply_to_message_id, message_thread_id)):
return None
return raw.types.InputReplyToMessage(
reply_to_msg_id=reply_to_message_id or message_thread_id, # type: ignore[arg-type]
top_msg_id=message_thread_id if reply_to_message_id else None,
)
def get_channel_id(peer_id: int) -> int:
return MAX_CHANNEL_ID - peer_id