fix: support large accounts and archived chats in channel discovery
Some checks failed
continuous-integration/drone/push Build is failing

- Increase getChats pagination from 50 pages (5K chats) to 500 pages
  (50K chats) to support accounts with many channels/groups
- Load from both chatListMain AND chatListArchive so older/archived
  chats are discovered and scannable
- Deduplicate chat IDs across both lists
- Worker startup also loads both lists before scanning

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-23 19:50:14 +01:00
parent 29e95f780c
commit aef76828ef
2 changed files with 95 additions and 79 deletions

View File

@@ -34,16 +34,22 @@ export async function getAccountChats(
log.warn("Failed to get current user via getMe"); log.warn("Failed to get current user via getMe");
} }
// Load ALL chats from the main list by paginating getChats. // Load ALL chats from both main and archive lists by paginating getChats.
// TDLib's getChats returns batches — keep calling until it returns // TDLib's getChats returns batches — keep calling until it returns
// an empty list, which signals all chats have been loaded. // an empty list, which signals all chats have been loaded.
const MAX_PAGES = 50; // safety limit (50 × 100 = 5000 chats) const seenChatIds = new Set<number>();
for (const chatList of [
{ _: "chatListMain" as const },
{ _: "chatListArchive" as const },
]) {
const MAX_PAGES = 500; // support up to 50,000 chats per list
for (let page = 0; page < MAX_PAGES; page++) { for (let page = 0; page < MAX_PAGES; page++) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = (await withFloodWait( const result = (await withFloodWait(
() => client.invoke({ () => client.invoke({
_: "getChats", _: "getChats",
chat_list: { _: "chatListMain" }, chat_list: chatList,
limit: 100, limit: 100,
}), }),
"getChats" "getChats"
@@ -54,6 +60,9 @@ export async function getAccountChats(
} }
for (const chatId of result.chat_ids) { for (const chatId of result.chat_ids) {
if (seenChatIds.has(chatId)) continue;
seenChatIds.add(chatId);
try { try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const chat = (await withFloodWait( const chat = (await withFloodWait(
@@ -109,10 +118,11 @@ export async function getAccountChats(
await sleep(config.apiDelayMs); await sleep(config.apiDelayMs);
} }
}
log.info( log.info(
{ total: chats.length }, { total: chats.length },
"Fetched all chats from Telegram" "Fetched all chats from Telegram (main + archive)"
); );
return chats; return chats;

View File

@@ -338,11 +338,16 @@ export async function runWorkerForAccount(
// Load the full chat list so TDLib knows about all chats. // Load the full chat list so TDLib knows about all chats.
// Without this, getChat/searchChatMessages fail with "Chat not found". // Without this, getChat/searchChatMessages fail with "Chat not found".
// TDLib returns chats in batches — keep calling until empty. // TDLib returns chats in batches — keep calling until empty.
// Load from both main and archive lists to cover older/archived chats.
for (const chatList of [
{ _: "chatListMain" as const },
{ _: "chatListArchive" as const },
]) {
try { try {
for (let page = 0; page < 50; page++) { for (let page = 0; page < 500; page++) {
const chatResult = await client.invoke({ const chatResult = await client.invoke({
_: "getChats", _: "getChats",
chat_list: { _: "chatListMain" }, chat_list: chatList,
limit: 100, limit: 100,
}) as { chat_ids?: number[] }; }) as { chat_ids?: number[] };
if (!chatResult.chat_ids || chatResult.chat_ids.length === 0) break; if (!chatResult.chat_ids || chatResult.chat_ids.length === 0) break;
@@ -350,6 +355,7 @@ export async function runWorkerForAccount(
} catch { } catch {
// Ignore — chat list may already be loaded // Ignore — chat list may already be loaded
} }
}
const counters = { const counters = {
messagesScanned: 0, messagesScanned: 0,