mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-05-11 06:11:15 +00:00
fix: use searchChatMessages instead of getChatHistory for channel scanning
getChatHistory fails silently in supergroups with hidden history for new members, returning only system messages. searchChatMessages with document and photo filters works regardless of history visibility settings. Also adds getChats call after TDLib client creation to populate the chat list, preventing 'Chat not found' errors.
This commit is contained in:
@@ -154,31 +154,25 @@ export async function getChannelMessages(
|
|||||||
const photos: TelegramPhoto[] = [];
|
const photos: TelegramPhoto[] = [];
|
||||||
const boundary = lastProcessedMessageId ? Number(lastProcessedMessageId) : null;
|
const boundary = lastProcessedMessageId ? Number(lastProcessedMessageId) : null;
|
||||||
|
|
||||||
// Open the chat so TDLib loads remote messages, then load chat history
|
// Open the chat so TDLib can access it
|
||||||
// from the server. getChat forces TDLib to fetch chat metadata and
|
|
||||||
// getChatHistory with from_message_id=0 triggers a server-side fetch.
|
|
||||||
await invokeWithTimeout(client, {
|
|
||||||
_: "openChat",
|
|
||||||
chat_id: Number(chatId),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Force TDLib to load the full chat list which populates chat state
|
|
||||||
try {
|
try {
|
||||||
await invokeWithTimeout(client, {
|
await invokeWithTimeout(client, { _: "openChat", chat_id: Number(chatId) });
|
||||||
_: "getChat",
|
|
||||||
chat_id: Number(chatId),
|
|
||||||
});
|
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore - chat may already be loaded
|
// Ignore — may already be open
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give TDLib time to sync chat data from the server
|
|
||||||
await sleep(2000);
|
|
||||||
|
|
||||||
let currentFromId = 0;
|
|
||||||
let totalScanned = 0;
|
let totalScanned = 0;
|
||||||
let pageCount = 0;
|
let pageCount = 0;
|
||||||
|
|
||||||
|
// Use searchChatMessages with document filter — this works even when
|
||||||
|
// getChatHistory is restricted (e.g. hidden history for new members).
|
||||||
|
// We search for documents first, then photos separately.
|
||||||
|
for (const filter of [
|
||||||
|
{ _: "searchMessagesFilterDocument" as const, kind: "document" },
|
||||||
|
{ _: "searchMessagesFilterPhoto" as const, kind: "photo" },
|
||||||
|
]) {
|
||||||
|
let fromMessageId = 0;
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
// eslint-disable-next-line no-constant-condition
|
||||||
while (true) {
|
while (true) {
|
||||||
if (pageCount >= MAX_SCAN_PAGES) {
|
if (pageCount >= MAX_SCAN_PAGES) {
|
||||||
@@ -190,15 +184,15 @@ export async function getChannelMessages(
|
|||||||
}
|
}
|
||||||
pageCount++;
|
pageCount++;
|
||||||
|
|
||||||
const previousFromId = currentFromId;
|
const result = await invokeWithTimeout<{ messages: TdMessage[]; total_count?: number }>(client, {
|
||||||
|
_: "searchChatMessages",
|
||||||
const result = await invokeWithTimeout<{ messages: TdMessage[] }>(client, {
|
|
||||||
_: "getChatHistory",
|
|
||||||
chat_id: Number(chatId),
|
chat_id: Number(chatId),
|
||||||
from_message_id: currentFromId,
|
query: "",
|
||||||
|
from_message_id: fromMessageId,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
limit: Math.min(limit, 100),
|
limit: Math.min(limit, 100),
|
||||||
only_local: false,
|
filter,
|
||||||
|
message_thread_id: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.messages || result.messages.length === 0) break;
|
if (!result.messages || result.messages.length === 0) break;
|
||||||
@@ -209,6 +203,8 @@ export async function getChannelMessages(
|
|||||||
// Check for archive documents
|
// Check for archive documents
|
||||||
const doc = msg.content?.document;
|
const doc = msg.content?.document;
|
||||||
if (doc?.file_name && doc.document && isArchiveAttachment(doc.file_name)) {
|
if (doc?.file_name && doc.document && isArchiveAttachment(doc.file_name)) {
|
||||||
|
// Skip if we've already processed past this message
|
||||||
|
if (boundary && msg.id <= boundary) continue;
|
||||||
archives.push({
|
archives.push({
|
||||||
id: BigInt(msg.id),
|
id: BigInt(msg.id),
|
||||||
fileName: doc.file_name,
|
fileName: doc.file_name,
|
||||||
@@ -223,6 +219,7 @@ export async function getChannelMessages(
|
|||||||
const photo = msg.content?.photo;
|
const photo = msg.content?.photo;
|
||||||
const caption = msg.content?.caption?.text ?? "";
|
const caption = msg.content?.caption?.text ?? "";
|
||||||
if (photo?.sizes && photo.sizes.length > 0) {
|
if (photo?.sizes && photo.sizes.length > 0) {
|
||||||
|
if (boundary && msg.id <= boundary) continue;
|
||||||
const smallest = photo.sizes[0];
|
const smallest = photo.sizes[0];
|
||||||
photos.push({
|
photos.push({
|
||||||
id: BigInt(msg.id),
|
id: BigInt(msg.id),
|
||||||
@@ -234,34 +231,21 @@ export async function getChannelMessages(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report scanning progress after each page
|
|
||||||
onProgress?.(totalScanned);
|
onProgress?.(totalScanned);
|
||||||
|
|
||||||
currentFromId = result.messages[result.messages.length - 1].id;
|
// Advance pagination
|
||||||
|
fromMessageId = result.messages[result.messages.length - 1].id;
|
||||||
// Stuck detection: if from_message_id didn't advance, break to prevent infinite loop
|
|
||||||
if (currentFromId === previousFromId) {
|
|
||||||
log.warn(
|
|
||||||
{ chatId: chatId.toString(), currentFromId, totalScanned },
|
|
||||||
"Pagination stuck (from_message_id not advancing), breaking"
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop scanning once we've gone past the boundary (this page is the lookback)
|
|
||||||
if (boundary && currentFromId < boundary) break;
|
|
||||||
|
|
||||||
if (result.messages.length < Math.min(limit, 100)) break;
|
if (result.messages.length < Math.min(limit, 100)) break;
|
||||||
|
|
||||||
// Rate limit delay
|
|
||||||
await sleep(config.apiDelayMs);
|
await sleep(config.apiDelayMs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Close the chat after scanning
|
// Close the chat after scanning
|
||||||
await invokeWithTimeout(client, {
|
await invokeWithTimeout(client, {
|
||||||
_: "closeChat",
|
_: "closeChat",
|
||||||
chat_id: Number(chatId),
|
chat_id: Number(chatId),
|
||||||
}).catch(() => {}); // Ignore close errors
|
}).catch(() => {});
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
{ chatId: chatId.toString(), archives: archives.length, photos: photos.length, totalScanned, pages: pageCount },
|
{ chatId: chatId.toString(), archives: archives.length, photos: photos.length, totalScanned, pages: pageCount },
|
||||||
|
|||||||
@@ -333,6 +333,18 @@ export async function runWorkerForAccount(
|
|||||||
phone: account.phone,
|
phone: account.phone,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Load the chat list so TDLib knows about all chats
|
||||||
|
// Without this, getChat/getChatHistory fail with "Chat not found"
|
||||||
|
try {
|
||||||
|
await client.invoke({
|
||||||
|
_: "getChats",
|
||||||
|
chat_list: { _: "chatListMain" },
|
||||||
|
limit: 1000,
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// Ignore — chat list may already be loaded
|
||||||
|
}
|
||||||
|
|
||||||
const counters = {
|
const counters = {
|
||||||
messagesScanned: 0,
|
messagesScanned: 0,
|
||||||
zipsFound: 0,
|
zipsFound: 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user