mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-11-04 09:57:29 +03:00 
			
		
		
		
	Separate chat requests from the TelegramClient
This commit is contained in:
		
							parent
							
								
									1e91e5a83c
								
							
						
					
					
						commit
						ad29f2f5b7
					
				
							
								
								
									
										184
									
								
								telethon/client/chats.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								telethon/client/chats.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,184 @@
 | 
				
			||||||
 | 
					from collections import UserList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .users import UserMethods
 | 
				
			||||||
 | 
					from .. import utils
 | 
				
			||||||
 | 
					from ..tl import types, functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ChatMethods(UserMethods):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # region Public methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async def iter_participants(
 | 
				
			||||||
 | 
					            self, entity, limit=None, search='',
 | 
				
			||||||
 | 
					            filter=None, aggressive=False, _total=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Iterator over the participants belonging to the specified chat.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Args:
 | 
				
			||||||
 | 
					            entity (`entity`):
 | 
				
			||||||
 | 
					                The entity from which to retrieve the participants list.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            limit (`int`):
 | 
				
			||||||
 | 
					                Limits amount of participants fetched.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            search (`str`, optional):
 | 
				
			||||||
 | 
					                Look for participants with this string in name/username.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            filter (:tl:`ChannelParticipantsFilter`, optional):
 | 
				
			||||||
 | 
					                The filter to be used, if you want e.g. only admins
 | 
				
			||||||
 | 
					                Note that you might not have permissions for some filter.
 | 
				
			||||||
 | 
					                This has no effect for normal chats or users.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            aggressive (`bool`, optional):
 | 
				
			||||||
 | 
					                Aggressively looks for all participants in the chat in
 | 
				
			||||||
 | 
					                order to get more than 10,000 members (a hard limit
 | 
				
			||||||
 | 
					                imposed by Telegram). Note that this might take a long
 | 
				
			||||||
 | 
					                time (over 5 minutes), but is able to return over 90,000
 | 
				
			||||||
 | 
					                participants on groups with 100,000 members.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                This has no effect for groups or channels with less than
 | 
				
			||||||
 | 
					                10,000 members, or if a ``filter`` is given.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _total (`list`, optional):
 | 
				
			||||||
 | 
					                A single-item list to pass the total parameter by reference.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Yields:
 | 
				
			||||||
 | 
					            The :tl:`User` objects returned by :tl:`GetParticipantsRequest`
 | 
				
			||||||
 | 
					            with an additional ``.participant`` attribute which is the
 | 
				
			||||||
 | 
					            matched :tl:`ChannelParticipant` type for channels/megagroups
 | 
				
			||||||
 | 
					            or :tl:`ChatParticipants` for normal chats.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if isinstance(filter, type):
 | 
				
			||||||
 | 
					            if filter in (types.ChannelParticipantsBanned,
 | 
				
			||||||
 | 
					                          types.ChannelParticipantsKicked,
 | 
				
			||||||
 | 
					                          types.ChannelParticipantsSearch):
 | 
				
			||||||
 | 
					                # These require a `q` parameter (support types for convenience)
 | 
				
			||||||
 | 
					                filter = filter('')
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                filter = filter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        entity = await self.get_input_entity(entity)
 | 
				
			||||||
 | 
					        if search and (filter
 | 
				
			||||||
 | 
					                       or not isinstance(entity, types.InputPeerChannel)):
 | 
				
			||||||
 | 
					            # We need to 'search' ourselves unless we have a PeerChannel
 | 
				
			||||||
 | 
					            search = search.lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            def filter_entity(ent):
 | 
				
			||||||
 | 
					                return search in utils.get_display_name(ent).lower() or\
 | 
				
			||||||
 | 
					                       search in (getattr(ent, 'username', '') or None).lower()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            def filter_entity(ent):
 | 
				
			||||||
 | 
					                return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        limit = float('inf') if limit is None else int(limit)
 | 
				
			||||||
 | 
					        if isinstance(entity, types.InputPeerChannel):
 | 
				
			||||||
 | 
					            if _total or (aggressive and not filter):
 | 
				
			||||||
 | 
					                total = (await self(functions.channels.GetFullChannelRequest(
 | 
				
			||||||
 | 
					                    entity
 | 
				
			||||||
 | 
					                ))).full_chat.participants_count
 | 
				
			||||||
 | 
					                if _total:
 | 
				
			||||||
 | 
					                    _total[0] = total
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                total = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if limit == 0:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            seen = set()
 | 
				
			||||||
 | 
					            if total > 10000 and aggressive and not filter:
 | 
				
			||||||
 | 
					                requests = [functions.channels.GetParticipantsRequest(
 | 
				
			||||||
 | 
					                    channel=entity,
 | 
				
			||||||
 | 
					                    filter=types.ChannelParticipantsSearch(search + chr(x)),
 | 
				
			||||||
 | 
					                    offset=0,
 | 
				
			||||||
 | 
					                    limit=200,
 | 
				
			||||||
 | 
					                    hash=0
 | 
				
			||||||
 | 
					                ) for x in range(ord('a'), ord('z') + 1)]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                requests = [functions.channels.GetParticipantsRequest(
 | 
				
			||||||
 | 
					                    channel=entity,
 | 
				
			||||||
 | 
					                    filter=filter or types.ChannelParticipantsSearch(search),
 | 
				
			||||||
 | 
					                    offset=0,
 | 
				
			||||||
 | 
					                    limit=200,
 | 
				
			||||||
 | 
					                    hash=0
 | 
				
			||||||
 | 
					                )]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while requests:
 | 
				
			||||||
 | 
					                # Only care about the limit for the first request
 | 
				
			||||||
 | 
					                # (small amount of people, won't be aggressive).
 | 
				
			||||||
 | 
					                #
 | 
				
			||||||
 | 
					                # Most people won't care about getting exactly 12,345
 | 
				
			||||||
 | 
					                # members so it doesn't really matter not to be 100%
 | 
				
			||||||
 | 
					                # precise with being out of the offset/limit here.
 | 
				
			||||||
 | 
					                requests[0].limit = min(limit - requests[0].offset, 200)
 | 
				
			||||||
 | 
					                if requests[0].offset > limit:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                results = await self(requests)
 | 
				
			||||||
 | 
					                for i in reversed(range(len(requests))):
 | 
				
			||||||
 | 
					                    participants = results[i]
 | 
				
			||||||
 | 
					                    if not participants.users:
 | 
				
			||||||
 | 
					                        requests.pop(i)
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        requests[i].offset += len(participants.participants)
 | 
				
			||||||
 | 
					                        users = {user.id: user for user in participants.users}
 | 
				
			||||||
 | 
					                        for participant in participants.participants:
 | 
				
			||||||
 | 
					                            user = users[participant.user_id]
 | 
				
			||||||
 | 
					                            if not filter_entity(user) or user.id in seen:
 | 
				
			||||||
 | 
					                                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            seen.add(participant.user_id)
 | 
				
			||||||
 | 
					                            user = users[participant.user_id]
 | 
				
			||||||
 | 
					                            user.participant = participant
 | 
				
			||||||
 | 
					                            yield user
 | 
				
			||||||
 | 
					                            if len(seen) >= limit:
 | 
				
			||||||
 | 
					                                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        elif isinstance(entity, types.InputPeerChat):
 | 
				
			||||||
 | 
					            # TODO We *could* apply the `filter` here ourselves
 | 
				
			||||||
 | 
					            full = await self(
 | 
				
			||||||
 | 
					                functions.messages.GetFullChatRequest(entity.chat_id))
 | 
				
			||||||
 | 
					            if not isinstance(
 | 
				
			||||||
 | 
					                    full.full_chat.participants, types.ChatParticipants):
 | 
				
			||||||
 | 
					                # ChatParticipantsForbidden won't have ``.participants``
 | 
				
			||||||
 | 
					                _total[0] = 0
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if _total:
 | 
				
			||||||
 | 
					                _total[0] = len(full.full_chat.participants.participants)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            have = 0
 | 
				
			||||||
 | 
					            users = {user.id: user for user in full.users}
 | 
				
			||||||
 | 
					            for participant in full.full_chat.participants.participants:
 | 
				
			||||||
 | 
					                user = users[participant.user_id]
 | 
				
			||||||
 | 
					                if not filter_entity(user):
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                have += 1
 | 
				
			||||||
 | 
					                if have > limit:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    user = users[participant.user_id]
 | 
				
			||||||
 | 
					                    user.participant = participant
 | 
				
			||||||
 | 
					                    yield user
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if _total:
 | 
				
			||||||
 | 
					                _total[0] = 1
 | 
				
			||||||
 | 
					            if limit != 0:
 | 
				
			||||||
 | 
					                user = await self.get_entity(entity)
 | 
				
			||||||
 | 
					                if filter_entity(user):
 | 
				
			||||||
 | 
					                    user.participant = None
 | 
				
			||||||
 | 
					                    yield user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async def get_participants(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Same as :meth:`iter_participants`, but returns a list instead
 | 
				
			||||||
 | 
					        with an additional ``.total`` attribute on the list.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        total = [0]
 | 
				
			||||||
 | 
					        kwargs['_total'] = total
 | 
				
			||||||
 | 
					        participants = UserList(x async for x in
 | 
				
			||||||
 | 
					                                self.iter_participants(*args, **kwargs))
 | 
				
			||||||
 | 
					        participants.total = total[0]
 | 
				
			||||||
 | 
					        return participants
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # endregion
 | 
				
			||||||
| 
						 | 
					@ -1,22 +1,15 @@
 | 
				
			||||||
import getpass
 | 
					import getpass
 | 
				
			||||||
import hashlib
 | 
					import hashlib
 | 
				
			||||||
import io
 | 
					import io
 | 
				
			||||||
import itertools
 | 
					 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import re
 | 
					 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
import warnings
 | 
					import warnings
 | 
				
			||||||
from collections import UserList
 | 
					 | 
				
			||||||
from io import BytesIO
 | 
					 | 
				
			||||||
from mimetypes import guess_type
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ..crypto import CdnDecrypter
 | 
					from ..crypto import CdnDecrypter
 | 
				
			||||||
from ..tl.custom import InputSizedFile
 | 
					 | 
				
			||||||
from ..tl.functions.help import AcceptTermsOfServiceRequest
 | 
					from ..tl.functions.help import AcceptTermsOfServiceRequest
 | 
				
			||||||
from ..tl.functions.updates import GetDifferenceRequest
 | 
					from ..tl.functions.updates import GetDifferenceRequest
 | 
				
			||||||
from ..tl.functions.upload import (
 | 
					from ..tl.functions.upload import (
 | 
				
			||||||
    SaveBigFilePartRequest, SaveFilePartRequest, GetFileRequest
 | 
					    GetFileRequest
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from ..tl.types.updates import (
 | 
					from ..tl.types.updates import (
 | 
				
			||||||
    DifferenceSlice, DifferenceEmpty, Difference, DifferenceTooLong
 | 
					    DifferenceSlice, DifferenceEmpty, Difference, DifferenceTooLong
 | 
				
			||||||
| 
						 | 
					@ -43,7 +36,6 @@ from ..errors import (
 | 
				
			||||||
    SessionPasswordNeededError, FileMigrateError, PhoneNumberUnoccupiedError,
 | 
					    SessionPasswordNeededError, FileMigrateError, PhoneNumberUnoccupiedError,
 | 
				
			||||||
    PhoneNumberOccupiedError
 | 
					    PhoneNumberOccupiedError
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from ..tl.custom import Draft, Dialog
 | 
					 | 
				
			||||||
from ..tl.functions.account import (
 | 
					from ..tl.functions.account import (
 | 
				
			||||||
    GetPasswordRequest, UpdatePasswordSettingsRequest
 | 
					    GetPasswordRequest, UpdatePasswordSettingsRequest
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -51,41 +43,19 @@ from ..tl.functions.auth import (
 | 
				
			||||||
    CheckPasswordRequest, LogOutRequest, SendCodeRequest, SignInRequest,
 | 
					    CheckPasswordRequest, LogOutRequest, SendCodeRequest, SignInRequest,
 | 
				
			||||||
    SignUpRequest, ResendCodeRequest, ImportBotAuthorizationRequest
 | 
					    SignUpRequest, ResendCodeRequest, ImportBotAuthorizationRequest
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from ..tl.functions.messages import (
 | 
					 | 
				
			||||||
    GetDialogsRequest, GetHistoryRequest, SendMediaRequest,
 | 
					 | 
				
			||||||
    SendMessageRequest, GetAllDraftsRequest,
 | 
					 | 
				
			||||||
    ReadMentionsRequest, SendMultiMediaRequest,
 | 
					 | 
				
			||||||
    UploadMediaRequest, EditMessageRequest, GetFullChatRequest,
 | 
					 | 
				
			||||||
    ForwardMessagesRequest, SearchRequest
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ..tl.functions import channels
 | 
					 | 
				
			||||||
from ..tl.functions import messages
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ..tl.functions.channels import (
 | 
					from ..tl.functions.channels import (
 | 
				
			||||||
    GetFullChannelRequest, GetParticipantsRequest
 | 
					    GetFullChannelRequest
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from ..tl.types import (
 | 
					from ..tl.types import (
 | 
				
			||||||
    DocumentAttributeAudio, DocumentAttributeFilename,
 | 
					    DocumentAttributeAudio, DocumentAttributeFilename,
 | 
				
			||||||
    InputMediaUploadedDocument, InputMediaUploadedPhoto, InputPeerEmpty,
 | 
					 | 
				
			||||||
    Message, MessageMediaContact, MessageMediaDocument, MessageMediaPhoto,
 | 
					    Message, MessageMediaContact, MessageMediaDocument, MessageMediaPhoto,
 | 
				
			||||||
    UserProfilePhoto, ChatPhoto, UpdateMessageID,
 | 
					    UserProfilePhoto, ChatPhoto, UpdateNewMessage, InputPeerChannel, Photo,
 | 
				
			||||||
    UpdateNewChannelMessage, UpdateNewMessage, UpdateShortSentMessage,
 | 
					    Document, Updates,
 | 
				
			||||||
    PeerUser, InputPeerChat, InputPeerChannel, MessageEmpty,
 | 
					    MessageMediaWebPage, PhotoSize, PhotoCachedSize,
 | 
				
			||||||
    Photo, InputSingleMedia, InputMediaPhoto, InputPhoto, InputFile, InputFileBig,
 | 
					    PhotoSizeEmpty, WebPage
 | 
				
			||||||
    InputDocument, InputMediaDocument, Document, MessageEntityTextUrl,
 | 
					 | 
				
			||||||
    InputMessageEntityMentionName, DocumentAttributeVideo,
 | 
					 | 
				
			||||||
    UpdateEditMessage, UpdateEditChannelMessage, UpdateShort, Updates,
 | 
					 | 
				
			||||||
    MessageMediaWebPage, ChannelParticipantsSearch, PhotoSize, PhotoCachedSize,
 | 
					 | 
				
			||||||
    PhotoSizeEmpty, MessageService, ChatParticipants, WebPage,
 | 
					 | 
				
			||||||
    ChannelParticipantsBanned, ChannelParticipantsKicked,
 | 
					 | 
				
			||||||
    InputMessagesFilterEmpty, UpdatesCombined
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from ..tl.types.messages import DialogsSlice, MessagesNotModified
 | 
					 | 
				
			||||||
from ..tl.types.account import PasswordInputSettings, NoPassword
 | 
					from ..tl.types.account import PasswordInputSettings, NoPassword
 | 
				
			||||||
from ..tl import custom
 | 
					 | 
				
			||||||
from ..utils import Default
 | 
					 | 
				
			||||||
from ..extensions import markdown, html
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
__log__ = logging.getLogger(__name__)
 | 
					__log__ = logging.getLogger(__name__)
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
| 
						 | 
					@ -429,180 +399,6 @@ class TelegramClient(TelegramBaseClient):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # endregion
 | 
					    # endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # region Dialogs ("chats") requests
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def iter_participants(self, entity, limit=None, search='',
 | 
					 | 
				
			||||||
                          filter=None, aggressive=False, _total=None):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Iterator over the participants belonging to the specified chat.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Args:
 | 
					 | 
				
			||||||
            entity (`entity`):
 | 
					 | 
				
			||||||
                The entity from which to retrieve the participants list.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            limit (`int`):
 | 
					 | 
				
			||||||
                Limits amount of participants fetched.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            search (`str`, optional):
 | 
					 | 
				
			||||||
                Look for participants with this string in name/username.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            filter (:tl:`ChannelParticipantsFilter`, optional):
 | 
					 | 
				
			||||||
                The filter to be used, if you want e.g. only admins
 | 
					 | 
				
			||||||
                Note that you might not have permissions for some filter.
 | 
					 | 
				
			||||||
                This has no effect for normal chats or users.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            aggressive (`bool`, optional):
 | 
					 | 
				
			||||||
                Aggressively looks for all participants in the chat in
 | 
					 | 
				
			||||||
                order to get more than 10,000 members (a hard limit
 | 
					 | 
				
			||||||
                imposed by Telegram). Note that this might take a long
 | 
					 | 
				
			||||||
                time (over 5 minutes), but is able to return over 90,000
 | 
					 | 
				
			||||||
                participants on groups with 100,000 members.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                This has no effect for groups or channels with less than
 | 
					 | 
				
			||||||
                10,000 members, or if a ``filter`` is given.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            _total (`list`, optional):
 | 
					 | 
				
			||||||
                A single-item list to pass the total parameter by reference.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Yields:
 | 
					 | 
				
			||||||
            The :tl:`User` objects returned by :tl:`GetParticipantsRequest`
 | 
					 | 
				
			||||||
            with an additional ``.participant`` attribute which is the
 | 
					 | 
				
			||||||
            matched :tl:`ChannelParticipant` type for channels/megagroups
 | 
					 | 
				
			||||||
            or :tl:`ChatParticipants` for normal chats.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        if isinstance(filter, type):
 | 
					 | 
				
			||||||
            if filter in (ChannelParticipantsBanned, ChannelParticipantsKicked,
 | 
					 | 
				
			||||||
                          ChannelParticipantsSearch):
 | 
					 | 
				
			||||||
                # These require a `q` parameter (support types for convenience)
 | 
					 | 
				
			||||||
                filter = filter('')
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                filter = filter()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        entity = self.get_input_entity(entity)
 | 
					 | 
				
			||||||
        if search and (filter or not isinstance(entity, InputPeerChannel)):
 | 
					 | 
				
			||||||
            # We need to 'search' ourselves unless we have a PeerChannel
 | 
					 | 
				
			||||||
            search = search.lower()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            def filter_entity(ent):
 | 
					 | 
				
			||||||
                return search in utils.get_display_name(ent).lower() or\
 | 
					 | 
				
			||||||
                       search in (getattr(ent, 'username', '') or None).lower()
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            def filter_entity(ent):
 | 
					 | 
				
			||||||
                return True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        limit = float('inf') if limit is None else int(limit)
 | 
					 | 
				
			||||||
        if isinstance(entity, InputPeerChannel):
 | 
					 | 
				
			||||||
            if _total or (aggressive and not filter):
 | 
					 | 
				
			||||||
                total = self(GetFullChannelRequest(
 | 
					 | 
				
			||||||
                    entity
 | 
					 | 
				
			||||||
                )).full_chat.participants_count
 | 
					 | 
				
			||||||
                if _total:
 | 
					 | 
				
			||||||
                    _total[0] = total
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                total = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if limit == 0:
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            seen = set()
 | 
					 | 
				
			||||||
            if total > 10000 and aggressive and not filter:
 | 
					 | 
				
			||||||
                requests = [GetParticipantsRequest(
 | 
					 | 
				
			||||||
                    channel=entity,
 | 
					 | 
				
			||||||
                    filter=ChannelParticipantsSearch(search + chr(x)),
 | 
					 | 
				
			||||||
                    offset=0,
 | 
					 | 
				
			||||||
                    limit=200,
 | 
					 | 
				
			||||||
                    hash=0
 | 
					 | 
				
			||||||
                ) for x in range(ord('a'), ord('z') + 1)]
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                requests = [GetParticipantsRequest(
 | 
					 | 
				
			||||||
                    channel=entity,
 | 
					 | 
				
			||||||
                    filter=filter or ChannelParticipantsSearch(search),
 | 
					 | 
				
			||||||
                    offset=0,
 | 
					 | 
				
			||||||
                    limit=200,
 | 
					 | 
				
			||||||
                    hash=0
 | 
					 | 
				
			||||||
                )]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            while requests:
 | 
					 | 
				
			||||||
                # Only care about the limit for the first request
 | 
					 | 
				
			||||||
                # (small amount of people, won't be aggressive).
 | 
					 | 
				
			||||||
                #
 | 
					 | 
				
			||||||
                # Most people won't care about getting exactly 12,345
 | 
					 | 
				
			||||||
                # members so it doesn't really matter not to be 100%
 | 
					 | 
				
			||||||
                # precise with being out of the offset/limit here.
 | 
					 | 
				
			||||||
                requests[0].limit = min(limit - requests[0].offset, 200)
 | 
					 | 
				
			||||||
                if requests[0].offset > limit:
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                results = self(requests)
 | 
					 | 
				
			||||||
                for i in reversed(range(len(requests))):
 | 
					 | 
				
			||||||
                    participants = results[i]
 | 
					 | 
				
			||||||
                    if not participants.users:
 | 
					 | 
				
			||||||
                        requests.pop(i)
 | 
					 | 
				
			||||||
                    else:
 | 
					 | 
				
			||||||
                        requests[i].offset += len(participants.participants)
 | 
					 | 
				
			||||||
                        users = {user.id: user for user in participants.users}
 | 
					 | 
				
			||||||
                        for participant in participants.participants:
 | 
					 | 
				
			||||||
                            user = users[participant.user_id]
 | 
					 | 
				
			||||||
                            if not filter_entity(user) or user.id in seen:
 | 
					 | 
				
			||||||
                                continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            seen.add(participant.user_id)
 | 
					 | 
				
			||||||
                            user = users[participant.user_id]
 | 
					 | 
				
			||||||
                            user.participant = participant
 | 
					 | 
				
			||||||
                            yield user
 | 
					 | 
				
			||||||
                            if len(seen) >= limit:
 | 
					 | 
				
			||||||
                                return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        elif isinstance(entity, InputPeerChat):
 | 
					 | 
				
			||||||
            # TODO We *could* apply the `filter` here ourselves
 | 
					 | 
				
			||||||
            full = self(GetFullChatRequest(entity.chat_id))
 | 
					 | 
				
			||||||
            if not isinstance(full.full_chat.participants, ChatParticipants):
 | 
					 | 
				
			||||||
                # ChatParticipantsForbidden won't have ``.participants``
 | 
					 | 
				
			||||||
                _total[0] = 0
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if _total:
 | 
					 | 
				
			||||||
                _total[0] = len(full.full_chat.participants.participants)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            have = 0
 | 
					 | 
				
			||||||
            users = {user.id: user for user in full.users}
 | 
					 | 
				
			||||||
            for participant in full.full_chat.participants.participants:
 | 
					 | 
				
			||||||
                user = users[participant.user_id]
 | 
					 | 
				
			||||||
                if not filter_entity(user):
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
                have += 1
 | 
					 | 
				
			||||||
                if have > limit:
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    user = users[participant.user_id]
 | 
					 | 
				
			||||||
                    user.participant = participant
 | 
					 | 
				
			||||||
                    yield user
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            if _total:
 | 
					 | 
				
			||||||
                _total[0] = 1
 | 
					 | 
				
			||||||
            if limit != 0:
 | 
					 | 
				
			||||||
                user = self.get_entity(entity)
 | 
					 | 
				
			||||||
                if filter_entity(user):
 | 
					 | 
				
			||||||
                    user.participant = None
 | 
					 | 
				
			||||||
                    yield user
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_participants(self, *args, **kwargs):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Same as :meth:`iter_participants`, but returns a list instead
 | 
					 | 
				
			||||||
        with an additional ``.total`` attribute on the list.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        total = [0]
 | 
					 | 
				
			||||||
        kwargs['_total'] = total
 | 
					 | 
				
			||||||
        participants = UserList(self.iter_participants(*args, **kwargs))
 | 
					 | 
				
			||||||
        participants.total = total[0]
 | 
					 | 
				
			||||||
        return participants
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # endregion
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # region Uploading files
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # endregion
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # region Downloading media requests
 | 
					    # region Downloading media requests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def download_profile_photo(self, entity, file=None, download_big=True):
 | 
					    def download_profile_photo(self, entity, file=None, download_big=True):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user