From 83f2111be95e4e52d5b0df7146468bbed7318fb7 Mon Sep 17 00:00:00 2001 From: NickolaiH <48893302+WubbaLubbaDubDubDev@users.noreply.github.com> Date: Tue, 19 Aug 2025 18:30:56 +0300 Subject: [PATCH 1/5] FIX get_dialogs.py Fix infinite loop in get_dialogs() by preventing repeated dialogs - Added tracking of seen dialog IDs to avoid yielding duplicates - Added check for None top_message to safely stop pagination - Preserved support for limit, pinned_only, and chat_list parameters - Ensured correct offset updates for reliable pagination --- pyrogram/methods/chats/get_dialogs.py | 60 +++++++++------------------ 1 file changed, 19 insertions(+), 41 deletions(-) diff --git a/pyrogram/methods/chats/get_dialogs.py b/pyrogram/methods/chats/get_dialogs.py index cfd8c145a3..660637d5b7 100644 --- a/pyrogram/methods/chats/get_dialogs.py +++ b/pyrogram/methods/chats/get_dialogs.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 asyncio import sleep from typing import AsyncGenerator, Optional -import pyrogram from pyrogram import types, raw, utils +from pyrogram.errors import ChannelPrivate, PeerIdInvalid class GetDialogs: @@ -30,47 +29,24 @@ async def get_dialogs( pinned_only: bool = False, chat_list: int = 0 ) -> Optional[AsyncGenerator["types.Dialog", None]]: - """Get a user's dialogs sequentially. - - .. include:: /_includes/usable-by/users.rst - - Parameters: - limit (``int``, *optional*): - Limits the number of dialogs to be retrieved. - By default, no limit is applied and all dialogs are returned. - - pinned_only (``bool``, *optional*): - Pass True if you want to get only pinned dialogs. - Defaults to False. - - chat_list (``int``, *optional*): - Chat list from which to get the dialogs; Only Main (0) and Archive (1) chat lists are supported. Defaults to (0) Main chat list. - - Returns: - ``Generator``: A generator yielding :obj:`~pyrogram.types.Dialog` objects. - - Example: - .. code-block:: python - - # Iterate through all dialogs - async for dialog in app.get_dialogs(): - print(dialog.chat.first_name or dialog.chat.title) - """ + current = 0 total = limit or (1 << 31) - 1 - limit = min(100, total) + request_limit = min(100, total) offset_date = 0 offset_id = 0 offset_peer = raw.types.InputPeerEmpty() + seen_dialog_ids = set() + while True: r = await self.invoke( raw.functions.messages.GetDialogs( offset_date=offset_date, offset_id=offset_id, offset_peer=offset_peer, - limit=limit, + limit=request_limit, hash=0, exclude_pinned=not pinned_only, folder_id=chat_list @@ -88,13 +64,10 @@ async def get_dialogs( continue chat_id = utils.get_peer_id(message.peer_id) - messages[chat_id] = await types.Message._parse( - self, - message, - users, - chats, - replies=self.fetch_replies - ) + try: + messages[chat_id] = await types.Message._parse(self, message, users, chats) + except (ChannelPrivate, PeerIdInvalid): + continue dialogs = [] @@ -102,22 +75,27 @@ async def get_dialogs( if not isinstance(dialog, raw.types.Dialog): continue - dialogs.append(types.Dialog._parse(self, dialog, messages, users, chats)) + parsed = types.Dialog._parse(self, dialog, messages, users, chats) + if parsed.chat.id in seen_dialog_ids: + continue + seen_dialog_ids.add(parsed.chat.id) + + dialogs.append(parsed) if not dialogs: return last = dialogs[-1] + if last.top_message is None: + return + offset_id = last.top_message.id offset_date = utils.datetime_to_timestamp(last.top_message.date) offset_peer = await self.resolve_peer(last.chat.id) for dialog in dialogs: - await sleep(0) yield dialog - current += 1 - if current >= total: return From 6ebe425edf79f955c2b2695c0efff11c85b9e6e6 Mon Sep 17 00:00:00 2001 From: NickolaiH <48893302+WubbaLubbaDubDubDev@users.noreply.github.com> Date: Tue, 19 Aug 2025 18:59:59 +0300 Subject: [PATCH 2/5] FIX get_dialogs.py fix: skip dialogs with no parsed chat to avoid errors --- pyrogram/methods/chats/get_dialogs.py | 35 +++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/pyrogram/methods/chats/get_dialogs.py b/pyrogram/methods/chats/get_dialogs.py index 660637d5b7..89a1f3b0bb 100644 --- a/pyrogram/methods/chats/get_dialogs.py +++ b/pyrogram/methods/chats/get_dialogs.py @@ -29,7 +29,32 @@ async def get_dialogs( pinned_only: bool = False, chat_list: int = 0 ) -> Optional[AsyncGenerator["types.Dialog", None]]: - + """Get a user's dialogs sequentially. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + limit (``int``, *optional*): + Limits the number of dialogs to be retrieved. + By default, no limit is applied and all dialogs are returned. + + pinned_only (``bool``, *optional*): + Pass True if you want to get only pinned dialogs. + Defaults to False. + + chat_list (``int``, *optional*): + Chat list from which to get the dialogs; Only Main (0) and Archive (1) chat lists are supported. Defaults to (0) Main chat list. + + Returns: + ``Generator``: A generator yielding :obj:`~pyrogram.types.Dialog` objects. + + Example: + .. code-block:: python + + # Iterate through all dialogs + async for dialog in app.get_dialogs(): + print(dialog.chat.first_name or dialog.chat.title) + """ current = 0 total = limit or (1 << 31) - 1 request_limit = min(100, total) @@ -76,10 +101,16 @@ async def get_dialogs( continue parsed = types.Dialog._parse(self, dialog, messages, users, chats) + if parsed is None: + continue + + if parsed.chat is None: + continue + if parsed.chat.id in seen_dialog_ids: continue + seen_dialog_ids.add(parsed.chat.id) - dialogs.append(parsed) if not dialogs: From 7c5883360baef2eb462c0d752b7f3bb1d8084375 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Wed, 20 Aug 2025 09:16:54 +0530 Subject: [PATCH 3/5] Update get_dialogs.py --- pyrogram/methods/chats/get_dialogs.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pyrogram/methods/chats/get_dialogs.py b/pyrogram/methods/chats/get_dialogs.py index 89a1f3b0bb..40e1e173b9 100644 --- a/pyrogram/methods/chats/get_dialogs.py +++ b/pyrogram/methods/chats/get_dialogs.py @@ -16,10 +16,10 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from asyncio import sleep from typing import AsyncGenerator, Optional -from pyrogram import types, raw, utils -from pyrogram.errors import ChannelPrivate, PeerIdInvalid +from pyrogram import raw, types, utils class GetDialogs: @@ -89,10 +89,7 @@ async def get_dialogs( continue chat_id = utils.get_peer_id(message.peer_id) - try: - messages[chat_id] = await types.Message._parse(self, message, users, chats) - except (ChannelPrivate, PeerIdInvalid): - continue + messages[chat_id] = await types.Message._parse(self, message, users, chats, replies=self.fetch_replies) dialogs = [] @@ -126,6 +123,7 @@ async def get_dialogs( offset_peer = await self.resolve_peer(last.chat.id) for dialog in dialogs: + await sleep(0) yield dialog current += 1 if current >= total: From 1414e4ceb19587ad3dad07cfd52923d2813bef3b Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Wed, 20 Aug 2025 09:17:21 +0530 Subject: [PATCH 4/5] Update get_dialogs.py --- pyrogram/methods/chats/get_dialogs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyrogram/methods/chats/get_dialogs.py b/pyrogram/methods/chats/get_dialogs.py index 40e1e173b9..f06913a4c9 100644 --- a/pyrogram/methods/chats/get_dialogs.py +++ b/pyrogram/methods/chats/get_dialogs.py @@ -19,6 +19,7 @@ from asyncio import sleep from typing import AsyncGenerator, Optional +import pyrogram from pyrogram import raw, types, utils From d54c5bd5a89028b662ecd2201eadfcab8986c496 Mon Sep 17 00:00:00 2001 From: Shrimadhav U K Date: Wed, 20 Aug 2025 09:18:05 +0530 Subject: [PATCH 5/5] Update get_dialogs.py --- pyrogram/methods/chats/get_dialogs.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pyrogram/methods/chats/get_dialogs.py b/pyrogram/methods/chats/get_dialogs.py index f06913a4c9..3318dd2535 100644 --- a/pyrogram/methods/chats/get_dialogs.py +++ b/pyrogram/methods/chats/get_dialogs.py @@ -90,7 +90,13 @@ async def get_dialogs( continue chat_id = utils.get_peer_id(message.peer_id) - messages[chat_id] = await types.Message._parse(self, message, users, chats, replies=self.fetch_replies) + messages[chat_id] = await types.Message._parse( + self, + message, + users, + chats, + replies=self.fetch_replies + ) dialogs = []