mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-05-10 22:01:16 +00:00
feat: fix channel scanning bugs, add package tags, and kickstarters tab
Bug fixes: - Fix channels not being scanned by paginating TDLib getChats (was only loading first batch, additional channels were unknown to TDLib) - Add per-channel getChat pre-load as safety net before scanning - Fix preview pictures not loading by checking previewData instead of previewMsgId for hasPreview flag - Prevent previewMsgId from being set when preview download fails Package Tags: - Add tags Text[] column to Package with migration backfilling from channel categories - Worker auto-inherits source channel category as initial tag - Tag filter dropdown and Tags column in STL Files table - Server actions for individual and bulk tag editing Kickstarters Tab: - New KickstarterHost, Kickstarter, and KickstarterPackage models - Full CRUD with delivery status, payment status, host management - Package linking (many-to-many with existing packages) - Sidebar entry with Gift icon - Table with search, filters, modal forms Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -103,6 +103,7 @@ export interface CreatePackageInput {
|
||||
partCount: number;
|
||||
ingestionRunId: string;
|
||||
creator?: string | null;
|
||||
tags?: string[];
|
||||
previewData?: Buffer | null;
|
||||
previewMsgId?: bigint | null;
|
||||
files: {
|
||||
@@ -132,6 +133,7 @@ export async function createPackageWithFiles(input: CreatePackageInput) {
|
||||
fileCount: input.files.length,
|
||||
ingestionRunId: input.ingestionRunId,
|
||||
creator: input.creator ?? undefined,
|
||||
tags: input.tags && input.tags.length > 0 ? input.tags : undefined,
|
||||
previewData: input.previewData ? new Uint8Array(input.previewData) : undefined,
|
||||
previewMsgId: input.previewMsgId ?? undefined,
|
||||
files: {
|
||||
|
||||
@@ -23,12 +23,11 @@ export async function getAccountChats(
|
||||
): Promise<TelegramChatInfo[]> {
|
||||
const chats: TelegramChatInfo[] = [];
|
||||
|
||||
// Load main chat list — TDLib loads in batches
|
||||
let offsetOrder = "9223372036854775807"; // max int64 as string
|
||||
let offsetChatId = 0;
|
||||
let hasMore = true;
|
||||
|
||||
while (hasMore) {
|
||||
// Load ALL chats from the main list by paginating getChats.
|
||||
// TDLib's getChats returns batches — keep calling until it returns
|
||||
// an empty list, which signals all chats have been loaded.
|
||||
const MAX_PAGES = 50; // safety limit (50 × 100 = 5000 chats)
|
||||
for (let page = 0; page < MAX_PAGES; page++) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const result = (await withFloodWait(
|
||||
() => client.invoke({
|
||||
@@ -95,10 +94,6 @@ export async function getAccountChats(
|
||||
}
|
||||
}
|
||||
|
||||
// getChats with chatListMain returns all chats at once in newer TDLib versions
|
||||
// So we break after the first batch
|
||||
hasMore = false;
|
||||
|
||||
await sleep(config.apiDelayMs);
|
||||
}
|
||||
|
||||
|
||||
@@ -335,14 +335,18 @@ export async function runWorkerForAccount(
|
||||
phone: account.phone,
|
||||
});
|
||||
|
||||
// Load the chat list so TDLib knows about all chats
|
||||
// Without this, getChat/getChatHistory fail with "Chat not found"
|
||||
// Load the full chat list so TDLib knows about all chats.
|
||||
// Without this, getChat/searchChatMessages fail with "Chat not found".
|
||||
// TDLib returns chats in batches — keep calling until empty.
|
||||
try {
|
||||
await client.invoke({
|
||||
_: "getChats",
|
||||
chat_list: { _: "chatListMain" },
|
||||
limit: 1000,
|
||||
});
|
||||
for (let page = 0; page < 50; page++) {
|
||||
const chatResult = await client.invoke({
|
||||
_: "getChats",
|
||||
chat_list: { _: "chatListMain" },
|
||||
limit: 100,
|
||||
}) as { chat_ids?: number[] };
|
||||
if (!chatResult.chat_ids || chatResult.chat_ids.length === 0) break;
|
||||
}
|
||||
} catch {
|
||||
// Ignore — chat list may already be loaded
|
||||
}
|
||||
@@ -377,6 +381,22 @@ export async function runWorkerForAccount(
|
||||
: channel.title;
|
||||
|
||||
try {
|
||||
// ── Ensure TDLib knows about this chat ──
|
||||
// getChats may not have loaded all channels (pagination, archive folder, etc.)
|
||||
// so we explicitly load each channel before scanning.
|
||||
try {
|
||||
await client.invoke({
|
||||
_: "getChat",
|
||||
chat_id: Number(channel.telegramId),
|
||||
});
|
||||
} catch (chatErr) {
|
||||
accountLog.warn(
|
||||
{ err: chatErr, channelId: channel.id, title: channel.title, telegramId: channel.telegramId.toString() },
|
||||
"TDLib does not know about this chat — it may not be accessible to this account. Skipping."
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ── Check if channel is a forum ──
|
||||
const forum = await isChatForum(client, channel.telegramId);
|
||||
if (forum !== channel.isForum) {
|
||||
@@ -969,7 +989,11 @@ async function processOneArchiveSet(
|
||||
totalFiles: totalSets,
|
||||
});
|
||||
previewData = await downloadPhotoThumbnail(client, matchedPhoto.fileId);
|
||||
previewMsgId = matchedPhoto.id;
|
||||
// Only set previewMsgId if we actually got the image data —
|
||||
// otherwise the UI thinks there's a preview but the API returns 404
|
||||
if (previewData) {
|
||||
previewMsgId = matchedPhoto.id;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Fallback: extract preview image from inside the archive ──
|
||||
@@ -1008,6 +1032,12 @@ async function processOneArchiveSet(
|
||||
// Clean up any orphaned record (same hash but no dest upload) before creating
|
||||
await deleteOrphanedPackageByHash(contentHash);
|
||||
|
||||
// Auto-inherit source channel category as initial tag
|
||||
const tags: string[] = [];
|
||||
if (channel.category) {
|
||||
tags.push(channel.category);
|
||||
}
|
||||
|
||||
await createPackageWithFiles({
|
||||
contentHash,
|
||||
fileName: archiveName,
|
||||
@@ -1023,6 +1053,7 @@ async function processOneArchiveSet(
|
||||
partCount: uploadPaths.length,
|
||||
ingestionRunId,
|
||||
creator,
|
||||
tags,
|
||||
previewData,
|
||||
previewMsgId,
|
||||
files: entries,
|
||||
|
||||
Reference in New Issue
Block a user