From 436a5760853065016e794f909a637f86699ea8af Mon Sep 17 00:00:00 2001 From: xCyanGrizzly Date: Sat, 2 May 2026 23:02:46 +0200 Subject: [PATCH] feat: detect and persist Telegram Premium status after authentication After TDLib login completes, calls getMe() to detect isPremium, persists it to DB via updateAccountPremiumStatus, and returns { client, isPremium } from createTdlibClient. All callers updated to destructure accordingly. Co-Authored-By: Claude Sonnet 4.6 --- worker/src/extract-listener.ts | 2 +- worker/src/fetch-listener.ts | 6 +++--- worker/src/manual-upload.ts | 2 +- worker/src/rebuild.ts | 2 +- worker/src/recovery.ts | 2 +- worker/src/tdlib/client.ts | 28 ++++++++++++++++++++++++++-- worker/src/worker.ts | 9 +++++---- 7 files changed, 38 insertions(+), 13 deletions(-) diff --git a/worker/src/extract-listener.ts b/worker/src/extract-listener.ts index 7228bb9..0f77ded 100644 --- a/worker/src/extract-listener.ts +++ b/worker/src/extract-listener.ts @@ -110,7 +110,7 @@ export async function processExtractRequest(requestId: string): Promise { } const account = accounts[0]; - const client = await createTdlibClient({ id: account.id, phone: account.phone }); + const { client } = await createTdlibClient({ id: account.id, phone: account.phone }); try { // Load chat list so TDLib can find the dest channel diff --git a/worker/src/fetch-listener.ts b/worker/src/fetch-listener.ts index 8fb3388..fcd89f1 100644 --- a/worker/src/fetch-listener.ts +++ b/worker/src/fetch-listener.ts @@ -162,7 +162,7 @@ function handleGenerateInvite(channelId: string): void { } const account = accounts[0]; - const client = await createTdlibClient({ id: account.id, phone: account.phone }); + const { client } = await createTdlibClient({ id: account.id, phone: account.phone }); try { const link = await generateInviteLink(client, destChannel.telegramId); @@ -203,7 +203,7 @@ function handleCreateDestination(payload: string): void { } const account = accounts[0]; - const client = await createTdlibClient({ id: account.id, phone: account.phone }); + const { client } = await createTdlibClient({ id: account.id, phone: account.phone }); try { // Create the supergroup via TDLib @@ -337,7 +337,7 @@ function handleJoinChannel(payload: string): void { throw new Error("No authenticated accounts available"); } - const client = await createTdlibClient({ id: account.id, phone: account.phone }); + const { client } = await createTdlibClient({ id: account.id, phone: account.phone }); try { const linkInfo = parseTelegramInput(parsed.input); diff --git a/worker/src/manual-upload.ts b/worker/src/manual-upload.ts index d66f441..3cef614 100644 --- a/worker/src/manual-upload.ts +++ b/worker/src/manual-upload.ts @@ -49,7 +49,7 @@ export async function processManualUpload(uploadId: string): Promise { const account = accounts[0]; if (!account) throw new Error("No authenticated Telegram account available"); - const client = await createTdlibClient({ id: account.id, phone: account.phone }); + const { client } = await createTdlibClient({ id: account.id, phone: account.phone }); try { const packageIds: string[] = []; diff --git a/worker/src/rebuild.ts b/worker/src/rebuild.ts index 3bfaad5..924285b 100644 --- a/worker/src/rebuild.ts +++ b/worker/src/rebuild.ts @@ -63,7 +63,7 @@ export async function rebuildPackageDatabase( } const account = accounts[0]; - const client = await createTdlibClient({ + const { client } = await createTdlibClient({ id: account.id, phone: account.phone, }); diff --git a/worker/src/recovery.ts b/worker/src/recovery.ts index cabe2f8..38197a2 100644 --- a/worker/src/recovery.ts +++ b/worker/src/recovery.ts @@ -63,7 +63,7 @@ export async function recoverIncompleteUploads(): Promise { let client: Client | undefined; try { - client = await createTdlibClient({ id: account.id, phone: account.phone }); + ({ client } = await createTdlibClient({ id: account.id, phone: account.phone })); // Load the chat list so TDLib can resolve chat IDs try { diff --git a/worker/src/tdlib/client.ts b/worker/src/tdlib/client.ts index 41493bf..74cb5e1 100644 --- a/worker/src/tdlib/client.ts +++ b/worker/src/tdlib/client.ts @@ -6,6 +6,7 @@ import { childLogger } from "../util/logger.js"; import { updateAccountAuthState, getAccountAuthCode, + updateAccountPremiumStatus, } from "../db/queries.js"; const log = childLogger("tdlib-client"); @@ -27,7 +28,7 @@ interface AccountConfig { */ export async function createTdlibClient( account: AccountConfig -): Promise { +): Promise<{ client: Client; isPremium: boolean }> { const dbPath = path.join(config.tdlibStateDir, account.id); const client = createClient({ @@ -78,7 +79,30 @@ export async function createTdlibClient( await updateAccountAuthState(account.id, "AUTHENTICATED"); log.info({ accountId: account.id }, "TDLib client authenticated"); - return client; + + let isPremium = false; + try { + const me = await client.invoke({ _: "getMe" }) as { is_premium?: boolean }; + isPremium = me.is_premium ?? false; + await updateAccountPremiumStatus(account.id, isPremium); + log.info({ accountId: account.id, isPremium }, "Account Premium status detected"); + } catch (err) { + log.warn({ err, accountId: account.id }, "Could not detect Premium status, defaulting to false"); + } + + client.on("update", (update: unknown) => { + const u = update as { _?: string; is_upload?: boolean }; + if (u?._ === "updateSpeedLimitNotification") { + log.warn( + { accountId: account.id, isUpload: u.is_upload }, + u.is_upload + ? "Upload speed limited by Telegram (account is not Premium)" + : "Download speed limited by Telegram (account is not Premium)" + ); + } + }); + + return { client, isPremium }; } catch (err) { log.error({ err, accountId: account.id }, "TDLib authentication failed"); await updateAccountAuthState(account.id, "EXPIRED"); diff --git a/worker/src/worker.ts b/worker/src/worker.ts index f7365b3..be76d7d 100644 --- a/worker/src/worker.ts +++ b/worker/src/worker.ts @@ -73,10 +73,10 @@ export async function authenticateAccount( let client: Client | undefined; try { - client = await createTdlibClient({ + client = (await createTdlibClient({ id: account.id, phone: account.phone, - }); + })).client; aLog.info("Authentication successful"); // Auto-fetch channels and create a fetch request result @@ -131,7 +131,7 @@ export async function processFetchRequest(requestId: string): Promise { await updateFetchRequestStatus(requestId, "IN_PROGRESS"); aLog.info({ accountId: request.accountId }, "Processing fetch request"); - const client = await createTdlibClient({ + const { client } = await createTdlibClient({ id: request.account.id, phone: request.account.phone, }); @@ -336,10 +336,11 @@ export async function runWorkerForAccount( currentStep: "connecting", }); - const client = await createTdlibClient({ + const { client, isPremium } = await createTdlibClient({ id: account.id, phone: account.phone, }); + void isPremium; // will be used in Task 6 for upload limits // Load all chats into TDLib's local cache using loadChats (the recommended API). // Without this, getChat/searchChatMessages fail with "Chat not found".