diff --git a/pyrogram/methods/chats/get_dialogs.py b/pyrogram/methods/chats/get_dialogs.py index 2ebf090ae34..f4f7e01601e 100644 --- a/pyrogram/methods/chats/get_dialogs.py +++ b/pyrogram/methods/chats/get_dialogs.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import AsyncGenerator, Optional +from typing import AsyncGenerator import pyrogram from pyrogram import types, raw, utils diff --git a/pyrogram/methods/chats/get_forum_topics.py b/pyrogram/methods/chats/get_forum_topics.py index 3bd38c03dc1..8e24e48ebf1 100644 --- a/pyrogram/methods/chats/get_forum_topics.py +++ b/pyrogram/methods/chats/get_forum_topics.py @@ -16,11 +16,10 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Union, Optional, AsyncGenerator +from typing import Union, AsyncGenerator import pyrogram -from pyrogram import raw -from pyrogram import types +from pyrogram import types, raw, utils class GetForumTopics: @@ -39,26 +38,66 @@ async def get_forum_topics( limit (``int``, *optional*): Limits the number of topics to be retrieved. + By default, no limit is applied and all topics are returned. Returns: - ``Generator``: On success, a generator yielding :obj:`~pyrogram.types.ForumTopic` objects is returned. + ``Generator``: A generator yielding :obj:`~pyrogram.types.ForumTopic` objects. Example: .. code-block:: python - # get all forum topics + # Iterate through all 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 + current = 0 + total = limit or (1 << 31) - 1 + limit = min(100, total) + + offset_date = 0 + offset_id = 0 + offset_topic = 0 + + while True: + r = await self.invoke( + raw.functions.channels.GetForumTopics( + channel=await self.resolve_peer(chat_id), + offset_date=offset_date, + offset_id=offset_id, + offset_topic=offset_topic, + limit=limit + ) ) - ) - for topic in r.topics: - yield types.ForumTopic._parse(topic) + users = {i.id: i for i in r.users} + chats = {i.id: i for i in r.chats} + + messages = {} + + for message in r.messages: + if isinstance(message, raw.types.MessageEmpty): + continue + + messages[message.id] = await types.Message._parse(self, message, users, chats) + + topics = [] + + for topic in r.topics: + topics.append(types.ForumTopic._parse(self, topic, messages, users, chats)) + + if not topics: + return + + last = topics[-1] + + offset_id = last.top_message.id + offset_date = utils.datetime_to_timestamp(last.top_message.date) + offset_topic = last.id + + for topic in topics: + yield topic + + current += 1 + + if current >= total: + return diff --git a/pyrogram/methods/chats/get_forum_topics_by_id.py b/pyrogram/methods/chats/get_forum_topics_by_id.py index 4e685e98144..ee79aad3be2 100644 --- a/pyrogram/methods/chats/get_forum_topics_by_id.py +++ b/pyrogram/methods/chats/get_forum_topics_by_id.py @@ -71,9 +71,20 @@ async def get_forum_topics_by_id( ) ) + users = {i.id: i for i in r.users} + chats = {i.id: i for i in r.chats} + + messages = {} + + for message in r.messages: + if isinstance(message, raw.types.MessageEmpty): + continue + + messages[message.id] = await types.Message._parse(self, message, users, chats) + topics = types.List() - for i in r: - topics.append(types.ForumTopic._parse(i)) + for i in r.topics: + topics.append(types.ForumTopic._parse(self, i, messages, users, chats)) - return topics if is_iterable else topics[0] + return topics if is_iterable else topics[0] if topics else None diff --git a/pyrogram/types/messages_and_media/forum_topic.py b/pyrogram/types/messages_and_media/forum_topic.py index a7e425b4845..a2525c69728 100644 --- a/pyrogram/types/messages_and_media/forum_topic.py +++ b/pyrogram/types/messages_and_media/forum_topic.py @@ -16,7 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram import raw, utils +import pyrogram +from pyrogram import types, raw, utils from ..object import Object @@ -27,28 +28,31 @@ class ForumTopic(Object): id (``int``): Unique topic identifier inside this chat. - date (``int``): - Date when the topic was created. - title (``str``): The topic title. - icon_color (``int``): - Color of the topic icon in RGB format + date (``int``, *optional*): + Date when the topic was created. + + icon_color (``str``, *optional*): + Color of the topic icon in HEX format icon_emoji_id (``int``, *optional*): Unique identifier of the custom emoji shown as the topic icon - top_message (``int``): + creator (:obj:`~pyrogram.types.Chat`, *optional*): + Topic creator. + + top_message (:obj:`~pyrogram.types.Message`, *optional*): The last message sent in the topic at this time. - unread_count (``int``): + unread_count (``int``, *optional*): Amount of unread messages in this topic. - unread_mentions_count (``int``): + unread_mentions_count (``int``, *optional*): Amount of unread messages containing a mention in this topic. - unread_reactions_count (``int``): + unread_reactions_count (``int``, *optional*): Amount of unread messages containing a reaction in this topic. is_my (``bool``, *optional*): @@ -59,31 +63,41 @@ class ForumTopic(Object): is_pinned (``bool``, *optional*): True, if the topic is pinned. + + is_short (``bool``, *optional*): + True, if the topic is short. + + is_hidden (``bool``, *optional*): + True, if the topic is hidden. """ def __init__( self, *, id: int, - date: int, - title: str, - icon_color: int, + title: str = None, + date: int = None, + icon_color: str = None, icon_emoji_id: int = None, - top_message: int, - unread_count: int, - unread_mentions_count: int, - unread_reactions_count: int, + creator: "types.Chat" = None, + top_message: "types.Message" = None, + unread_count: int = None, + unread_mentions_count: int = None, + unread_reactions_count: int = None, is_my: bool = None, is_closed: bool = None, is_pinned: bool = None, + is_short: bool = None, + is_hidden: bool = None ): super().__init__() self.id = id - self.date = date self.title = title + self.date = date self.icon_color = icon_color self.icon_emoji_id = icon_emoji_id + self.creator = creator self.top_message = top_message self.unread_count = unread_count self.unread_mentions_count = unread_mentions_count @@ -91,20 +105,37 @@ def __init__( self.is_my = is_my self.is_closed = is_closed self.is_pinned = is_pinned + self.is_short = is_short + self.is_hidden = is_hidden @staticmethod - def _parse(forum_topic: "raw.types.ForumTopic") -> "ForumTopic": + def _parse(client: "pyrogram.Client", forum_topic: "raw.types.ForumTopic", messages: dict = {}, users: dict = {}, chats: dict = {}) -> "ForumTopic": + creator = None + + peer = getattr(forum_topic, "from_id", None) + + if peer: + peer_id = utils.get_raw_peer_id(peer) + + if isinstance(peer, raw.types.PeerUser): + creator = types.Chat._parse_user_chat(client, users[peer_id]) + else: + creator = types.Chat._parse_channel_chat(client, chats[peer_id]) + return ForumTopic( id=forum_topic.id, - date=utils.timestamp_to_datetime(forum_topic.date), title=forum_topic.title, - icon_color=getattr(forum_topic, "icon_color", None), + date=utils.timestamp_to_datetime(forum_topic.date), + icon_color=format(forum_topic.icon_color, "x") if getattr(forum_topic, "icon_color", None) else None, icon_emoji_id=getattr(forum_topic, "icon_emoji_id", None), - top_message=getattr(forum_topic, "top_message", None), + creator=creator, + top_message=messages.get(getattr(forum_topic, "top_message", 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), is_my=getattr(forum_topic, "my", None), is_closed=getattr(forum_topic, "closed", None), is_pinned=getattr(forum_topic, "pinned", None), + is_short=getattr(forum_topic, "short", None), + is_hidden=getattr(forum_topic, "hidden", None), ) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index e0d592130ff..fb54f5570ac 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1025,12 +1025,14 @@ async def _parse( 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 + if topics: - parsed_message.topic = types.ForumTopic._parse(topics[thread_id]) + parsed_message.topic = types.ForumTopic._parse(client, topics[thread_id], users=users, chats=chats) else: try: - msg = await client.get_messages(parsed_message.chat.id,message.id) + msg = await client.get_messages(parsed_message.chat.id, message.id, replies=0) if msg.topic: parsed_message.topic = msg.topic except Exception: @@ -1051,6 +1053,7 @@ async def _parse( if media is None or web_page is not None else None ) + 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 else: diff --git a/pyrogram/types/user_and_chats/chat_event.py b/pyrogram/types/user_and_chats/chat_event.py index 2c4ddb411c5..9faea6a0c0e 100644 --- a/pyrogram/types/user_and_chats/chat_event.py +++ b/pyrogram/types/user_and_chats/chat_event.py @@ -454,16 +454,16 @@ async def _parse( action = enums.ChatEventAction.INVITE_LINK_DELETED elif isinstance(action, raw.types.ChannelAdminLogEventActionCreateTopic): - created_forum_topic = types.ForumTopic._parse(action.topic) + created_forum_topic = types.ForumTopic._parse(client, action.topic, users=users, chats=chats) 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) + old_forum_topic = types.ForumTopic._parse(client, action.prev_topic, users=users, chats=chats) + new_forum_topic = types.ForumTopic._parse(client, action.new_topic, users=users, chats=chats) action = enums.ChatEventAction.EDITED_FORUM_TOPIC elif isinstance(action, raw.types.ChannelAdminLogEventActionDeleteTopic): - created_forum_topic = types.ForumTopic._parse(action.topic) + created_forum_topic = types.ForumTopic._parse(client, action.topic, users=users, chats=chats) action = enums.ChatEventAction.DELETED_FORUM_TOPIC else: @@ -526,7 +526,7 @@ async def _parse( new_invite_link=new_invite_link, revoked_invite_link=revoked_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,