diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 3357d911..8c75d711 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -209,7 +209,6 @@ def pyrogram_api(): get_chat_member get_chat_members get_chat_members_count - iter_chat_members get_dialogs iter_dialogs get_dialogs_count diff --git a/pyrogram/methods/chats/get_chat_members.py b/pyrogram/methods/chats/get_chat_members.py index a192c3e3..c2516a70 100644 --- a/pyrogram/methods/chats/get_chat_members.py +++ b/pyrogram/methods/chats/get_chat_members.py @@ -25,69 +25,90 @@ from pyrogram import raw, types, enums log = logging.getLogger(__name__) +async def get_chunk( + client: "pyrogram.Client", + chat_id: Union[int, str], + offset: int, + filter: "enums.ChatMembersFilter", + limit: int, + query: str, +): + is_queryable = filter in [enums.ChatMembersFilter.SEARCH, + enums.ChatMembersFilter.BANNED, + enums.ChatMembersFilter.RESTRICTED] + + filter = filter.value(q=query) if is_queryable else filter.value() + + r = await client.invoke( + raw.functions.channels.GetParticipants( + channel=await client.resolve_peer(chat_id), + filter=filter, + offset=offset, + limit=limit, + hash=0 + ), + sleep_threshold=60 + ) + + members = r.participants + users = {u.id: u for u in r.users} + chats = {c.id: c for c in r.chats} + + return [types.ChatMember._parse(client, member, users, chats) for member in members] + + class GetChatMembers: async def get_chat_members( self: "pyrogram.Client", chat_id: Union[int, str], - offset: int = 0, - limit: int = 200, query: str = "", - filter: "enums.ChatMembersFilter" = enums.ChatMembersFilter.ANY + limit: int = 0, + filter: "enums.ChatMembersFilter" = enums.ChatMembersFilter.SEARCH ) -> List["types.ChatMember"]: - """Get a chunk of the members list of a chat. + """Get the members list of a chat. - You can get up to 200 chat members at once. A chat can be either a basic group, a supergroup or a channel. - You must be admin to retrieve the members list of a channel (also known as "subscribers"). - For a more convenient way of getting chat members see :meth:`~pyrogram.Client.iter_chat_members`. + Requires administrator rights in channels. Parameters: chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. - offset (``int``, *optional*): - Sequential number of the first member to be returned. - Only applicable to supergroups and channels. Defaults to 0. - - limit (``int``, *optional*): - Limits the number of members to be retrieved. - Only applicable to supergroups and channels. - Defaults to 200. - query (``str``, *optional*): Query string to filter members based on their display names and usernames. Only applicable to supergroups and channels. Defaults to "" (empty string). - A query string is applicable only for *"all"*, *"banned"* and *"restricted"* filters only + A query string is applicable only for :obj:`~pyrogram.enums.ChatMembersFilter.SEARCH`, + :obj:`~pyrogram.enums.ChatMembersFilter.BANNED` and :obj:`~pyrogram.enums.ChatMembersFilter.RESTRICTED` + filters only. - filter (``str``, *optional*): + limit (``int``, *optional*): + Limits the number of members to be retrieved. + + filter (:obj:`~pyrogram.enums.ChatMembersFilter`, *optional*): Filter used to select the kind of members you want to retrieve. Only applicable for supergroups - and channels. It can be any of the followings: - *"all"* - all kind of members, - *"banned"* - banned members only, - *"restricted"* - restricted members only, - *"bots"* - bots only, - *"recent"* - recent members only, - *"administrators"* - chat administrators only. - Only applicable to supergroups and channels. - Defaults to *"recent"*. + and channels. Returns: - List of :obj:`~pyrogram.types.ChatMember`: On success, a list of chat members is returned. - - Raises: - ValueError: In case you used an invalid filter or a chat id that belongs to a user. + ``Generator``: On success, a generator yielding :obj:`~pyrogram.types.ChatMember` objects is returned. Example: .. code-block:: python - # Get first 200 recent members - app.get_chat_members(chat_id) + from pyrogram import enums - # Get all administrators - app.get_chat_members(chat_id, filter="administrators") + # Get members + for member in app.get_chat_members(chat_id): + print(member) - # Get all bots - app.get_chat_members(chat_id, filter="bots") + # Get administrators + administrators = list(app.get_chat_members( + chat_id, + filter=enums.ChatMembersFilter.ADMINISTRATORS)) + + # Get bots + bots = list(app.get_chat_members( + chat_id, + filter=enums.ChatMembersFilter.BOTS)) """ peer = await self.resolve_peer(chat_id) @@ -101,40 +122,35 @@ class GetChatMembers: members = getattr(r.full_chat.participants, "participants", []) users = {i.id: i for i in r.users} - return types.List(types.ChatMember._parse(self, member, users, {}) for member in members) - elif isinstance(peer, raw.types.InputPeerChannel): - filter = filter.lower() + for member in members: + yield types.ChatMember._parse(self, member, users, {}) - if filter == enums.ChatMembersFilter.ANY: - filter = raw.types.ChannelParticipantsSearch(q=query) - elif filter == enums.ChatMembersFilter.BANNED: - filter = raw.types.ChannelParticipantsKicked(q=query) - elif filter == enums.ChatMembersFilter.RESTRICTED: - filter = raw.types.ChannelParticipantsBanned(q=query) - elif filter == enums.ChatMembersFilter.BOTS: - filter = raw.types.ChannelParticipantsBots() - elif filter == enums.ChatMembersFilter.RECENT: - filter = raw.types.ChannelParticipantsRecent() - elif filter == enums.ChatMembersFilter.ADMINISTRATORS: - filter = raw.types.ChannelParticipantsAdmins() - else: - raise ValueError(f'Invalid filter "{filter}"') + return - r = await self.invoke( - raw.functions.channels.GetParticipants( - channel=peer, - filter=filter, - offset=offset, - limit=limit, - hash=0 - ), - sleep_threshold=60 + current = 0 + offset = 0 + total = abs(limit) or (1 << 31) - 1 + limit = min(200, total) + + while True: + members = await get_chunk( + client=self, + chat_id=chat_id, + offset=offset, + filter=filter, + limit=limit, + query=query ) - members = r.participants - users = {i.id: i for i in r.users} - chats = {i.id: i for i in r.chats} + if not members: + return - return types.List(types.ChatMember._parse(self, member, users, chats) for member in members) - else: - raise ValueError(f'The chat_id "{chat_id}" belongs to a user') + offset += len(members) + + for member in members: + yield member + + current += 1 + + if current >= total: + return