Support getting more than 10k members on .get_participants()

Discussed on #580, original PR made on #639.
This commit is contained in:
Lonami Exo 2018-02-28 13:24:44 +01:00
parent 229cd78df0
commit 057c6a0b12

View File

@ -1015,9 +1015,10 @@ class TelegramClient(TelegramBareClient):
raise TypeError('Invalid message type: {}'.format(type(message))) raise TypeError('Invalid message type: {}'.format(type(message)))
def get_participants(self, entity, limit=None, search=''): def get_participants(self, entity, limit=None, search='',
aggressive=False):
""" """
Gets the list of participants from the specified entity Gets the list of participants from the specified entity.
Args: Args:
entity (:obj:`entity`): entity (:obj:`entity`):
@ -1029,34 +1030,55 @@ class TelegramClient(TelegramBareClient):
search (:obj:`str`, optional): search (:obj:`str`, optional):
Look for participants with this string in name/username. Look for participants with this string in name/username.
aggressive (:obj:`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 make over
20 times more requests and take over 5 minutes in some
cases, but often returns well over 10,000 members.
This has no effect for groups or channels with less than
10,000 members.
Returns: Returns:
A list of participants with an additional .total variable on the list A list of participants with an additional .total variable on the
indicating the total amount of members in this group/channel. list indicating the total amount of members in this group/channel.
""" """
entity = self.get_input_entity(entity) entity = self.get_input_entity(entity)
limit = float('inf') if limit is None else int(limit) limit = float('inf') if limit is None else int(limit)
if isinstance(entity, InputPeerChannel): if isinstance(entity, InputPeerChannel):
offset = 0 total = self(GetFullChannelRequest(
entity
)).full_chat.participants_count
all_participants = {} all_participants = {}
search = ChannelParticipantsSearch(search) if total > 10000 and aggressive:
searches = tuple(chr(x) for x in range(ord('a'), ord('z') + 1))
else:
searches = ('',)
for extra_search in searches:
req = GetParticipantsRequest(
channel=entity,
filter=ChannelParticipantsSearch(search + extra_search),
offset=0,
limit=0,
hash=0
)
while True: while True:
loop_limit = min(limit - offset, 200) req.limit = min(limit - req.offset, 200)
participants = self(GetParticipantsRequest( participants = self(req)
entity, search, offset, loop_limit, hash=0
))
if not participants.users: if not participants.users:
break break
for user in participants.users: for user in participants.users:
if len(all_participants) < limit: if len(all_participants) < limit:
all_participants[user.id] = user all_participants[user.id] = user
offset += len(participants.users) req.offset += len(participants.users)
if offset > limit: if req.offset > limit:
break break
users = UserList(all_participants.values()) users = UserList(all_participants.values())
users.total = self(GetFullChannelRequest( users.total = total
entity)).full_chat.participants_count
elif isinstance(entity, InputPeerChat): elif isinstance(entity, InputPeerChat):
users = self(GetFullChatRequest(entity.chat_id)).users users = self(GetFullChatRequest(entity.chat_id)).users
if len(users) > limit: if len(users) > limit: