From 5e5e51102f020a4f399097ca3e7f374fe7e9cf76 Mon Sep 17 00:00:00 2001 From: Wizou <11647984+wiz0u@users.noreply.github.com> Date: Wed, 9 Feb 2022 22:17:19 +0100 Subject: [PATCH] renamed Channels_GetAllParticipantsSlow. use clever alphabet and detect lying subcounts to fetch more entries. (WIP) --- src/Client.cs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Client.cs b/src/Client.cs index f19d306..00164ac 100644 --- a/src/Client.cs +++ b/src/Client.cs @@ -1630,13 +1630,18 @@ namespace WTelegram /// Helper method that tries to fetch all participants from a Channel (beyond Telegram server-side limitations) /// The channel to query /// Also fetch the kicked/banned members? + /// first letters used to search for in participants names
(default values crafted with ♥ to find most latin and cyrillic names) + /// second (and further) letters used to search for in participants names /// Field count indicates the total count of members. Field participants contains those that were successfully fetched - /// This method can take a few minutes to complete on big channels. It likely won't be able to obtain the full total count of members - public async Task Channels_GetAllParticipants(InputChannelBase channel, bool includeKickBan = false) + /// ⚠ This method can take a few minutes to complete on big broadcast channels. It likely won't be able to obtain the full total count of members + public async Task Channels_GetAllParticipantsSlow(InputChannelBase channel, bool includeKickBan = false, string alphabet1 = "АБCДЕЄЖФГHИІJКЛМНОПQРСТУВWХЦЧШЩЫЮЯЗ", string alphabet2 = "АCЕHИJЛМНОРСТУВWЫ") { + alphabet2 ??= alphabet1; + File.AppendAllText("AllPart.txt", alphabet1 + "\n"); + var sw = System.Diagnostics.Stopwatch.StartNew(); var result = new Channels_ChannelParticipants { chats = new(), users = new() }; - var sem = new SemaphoreSlim(10); // prevents flooding Telegram with requests + var sem = new SemaphoreSlim(1); // prevents flooding Telegram with requests var user_ids = new HashSet(); var participants = new List(); @@ -1644,30 +1649,33 @@ namespace WTelegram { GetWithFilter(new ChannelParticipantsAdmins()), GetWithFilter(new ChannelParticipantsBots()), - GetWithFilter(new ChannelParticipantsSearch { q = "" }, (f, c) => new ChannelParticipantsSearch { q = f.q + c }), + GetWithFilter(new ChannelParticipantsSearch { q = "" }, (f, c) => new ChannelParticipantsSearch { q = f.q + c }, alphabet1), }; var mcf = this.Channels_GetFullChannel(channel); tasks.Add(mcf); if (includeKickBan) { - tasks.Add(GetWithFilter(new ChannelParticipantsKicked { q = "" }, (f, c) => new ChannelParticipantsKicked { q = f.q + c })); - tasks.Add(GetWithFilter(new ChannelParticipantsBanned { q = "" }, (f, c) => new ChannelParticipantsBanned { q = f.q + c })); + tasks.Add(GetWithFilter(new ChannelParticipantsKicked { q = "" }, (f, c) => new ChannelParticipantsKicked { q = f.q + c }, alphabet1)); + tasks.Add(GetWithFilter(new ChannelParticipantsBanned { q = "" }, (f, c) => new ChannelParticipantsBanned { q = f.q + c }, alphabet1)); } await Task.WhenAll(tasks); result.count = ((ChannelFull)mcf.Result.full_chat).participants_count; result.participants = participants.ToArray(); + File.AppendAllText("AllPart.txt", $"{alphabet1} {participants.Count}/{result.count} in {sw.Elapsed}\n"); return result; - async Task GetWithFilter(T filter, Func recurse = null) where T : ChannelParticipantsFilter + async Task GetWithFilter(T filter, Func recurse = null, string alphabet = null) where T : ChannelParticipantsFilter { Channels_ChannelParticipants ccp; + int maxCount = 0; for (int offset = 0; ;) { await sem.WaitAsync(); try { ccp = await this.Channels_GetParticipants(channel, filter, offset, 1024, 0); + if (ccp.count > maxCount) maxCount = ccp.count; } finally { @@ -1682,8 +1690,10 @@ namespace WTelegram offset += ccp.participants.Length; if (offset >= ccp.count || ccp.participants.Length == 0) break; } - if (recurse != null && (ccp.count == 200 || ccp.count == 1000)) - await Task.WhenAll(Enumerable.Range('a', 26).Select(c => GetWithFilter(recurse(filter, (char)c), recurse))); + Console.WriteLine($"{participants.Count} {(filter as ChannelParticipantsSearch)?.q} {ccp.count} {maxCount}"); + File.AppendAllText("AllPart.txt", $"{(filter as ChannelParticipantsSearch)?.q}\t{participants.Count,4}\t{ccp.count}/{maxCount}\n"); + if (recurse != null && (ccp.count < maxCount - 100 || ccp.count == 200 || ccp.count == 1000)) + await Task.WhenAll(alphabet.Select(c => GetWithFilter(recurse(filter, (char)c), recurse, c == 'А' ? alphabet : alphabet2))); } }