diff --git a/apps/desktop-client/src/main/account-binder.ts b/apps/desktop-client/src/main/account-binder.ts index 8bf0a8f..1fdf021 100644 --- a/apps/desktop-client/src/main/account-binder.ts +++ b/apps/desktop-client/src/main/account-binder.ts @@ -1989,30 +1989,11 @@ export async function resolvePublishAccountProfile( } async function finalizeDetectedAccountForBind( - definition: PublishPlatformBindingDefinition, - context: DetectContext, + _definition: PublishPlatformBindingDefinition, + _context: DetectContext, detected: DetectedAccount, ): Promise { - if (detected.avatarUrl) { - return detected; - } - - let resolved = detected; - for (let attempt = 0; attempt < 3; attempt += 1) { - await sleep(400 + attempt * 250); - const retried = await definition.detect(context).catch(() => null); - if (!retried) { - continue; - } - - const sanitized = sanitizeDetectedAccount(retried); - resolved = sanitized; - if (sanitized.avatarUrl) { - break; - } - } - - return resolved; + return detected; } function isToutiaoLoginURL(url: string): boolean { @@ -2722,9 +2703,14 @@ export async function bindPublishAccount(platformId: string): Promise | null = null; const finalizeOperation = () => { clearInterval(intervalHandle); + if (detectDebounceHandle) { + clearTimeout(detectDebounceHandle); + detectDebounceHandle = null; + } clearActiveBindOperation(platformId, window); }; @@ -2772,9 +2758,28 @@ export async function bindPublishAccount(platformId: string): Promise { + if (finished || window.isDestroyed()) { + return; + } + if (detectDebounceHandle) { + clearTimeout(detectDebounceHandle); + } + detectDebounceHandle = setTimeout(() => { + detectDebounceHandle = null; + void detectAndBind(); + }, delayMs); + }; + + const handleNavigationReady = () => { + syncDetectionState(); + scheduleDetectAndBind(); + }; + + window.webContents.on("did-finish-load", handleNavigationReady); + window.webContents.on("did-navigate", handleNavigationReady); + window.webContents.on("did-navigate-in-page", handleNavigationReady); + window.webContents.on("page-title-updated", () => scheduleDetectAndBind(250)); window.webContents.on( "did-fail-load", (_event, errorCode, _errorDescription, _validatedURL, isMainFrame) => { @@ -2844,7 +2849,7 @@ export async function bindPublishAccount(platformId: string): Promise { void detectAndBind(); - }, 1800); + }, 650); window.on("closed", () => { clearActiveBindOperation(platformId, window); diff --git a/apps/desktop-client/src/main/bootstrap.ts b/apps/desktop-client/src/main/bootstrap.ts index ce93198..9a70f19 100644 --- a/apps/desktop-client/src/main/bootstrap.ts +++ b/apps/desktop-client/src/main/bootstrap.ts @@ -18,6 +18,7 @@ import { getPlaywrightCDPPort, startHiddenPlaywrightReaper } from "./playwright- import { registerRendererDevtoolsProxyTarget } from "./renderer-devtools-proxy"; import { onRuntimeInvalidated } from "./runtime-events"; import { + noteRuntimeAccountBound, refreshRuntimeAccounts, releaseRuntimeSession, syncRuntimeSession, @@ -289,7 +290,12 @@ function registerBridgeHandlers(): void { ipcMain.handle("desktop:runtime-snapshot", () => createRuntimeSnapshot()); safeHandle("desktop:bind-publish-account", async (_event, platformId: string) => { const account = (await bindPublishAccount(platformId)) as DesktopAccountInfo; - await refreshRuntimeAccounts(); + noteRuntimeAccountBound(account); + void refreshRuntimeAccounts().catch((error) => { + console.warn("[desktop-bind] background account refresh failed", { + message: error instanceof Error ? error.message : String(error), + }); + }); return account; }); safeHandle("desktop:refresh-runtime-accounts", async () => { diff --git a/apps/desktop-client/src/main/runtime-controller.ts b/apps/desktop-client/src/main/runtime-controller.ts index 57e6e0b..a0e3835 100644 --- a/apps/desktop-client/src/main/runtime-controller.ts +++ b/apps/desktop-client/src/main/runtime-controller.ts @@ -1058,6 +1058,37 @@ export async function refreshRuntimeAccounts(): Promise { await syncAccounts("manual"); } +export function noteRuntimeAccountBound(account: DesktopAccountInfo): void { + const normalizedAccount: DesktopAccountInfo = { + ...account, + platform_uid: normalizeAccountPlatformUid(account.platform_uid) || account.platform_uid, + }; + const existingIndex = state.accounts.findIndex((item) => + item.id === normalizedAccount.id + || ( + item.platform === normalizedAccount.platform + && sameAccountPlatformUid(item.platform_uid, normalizedAccount.platform_uid) + ), + ); + + if (existingIndex >= 0) { + state.accounts = state.accounts.map((item, index) => + index === existingIndex ? normalizedAccount : item, + ); + } else { + state.accounts = [normalizedAccount, ...state.accounts]; + } + + state.accountProfiles.set(normalizedAccount.id, { + platformUid: normalizedAccount.platform_uid, + displayName: normalizedAccount.display_name, + avatarUrl: normalizedAccount.avatar_url, + }); + state.lastAccountsSyncAt = Date.now(); + syncTrackedAccounts(state.accounts.map((item) => accountIdentityFromDesktopAccount(item))); + refreshAccountNames(); +} + export async function unbindRuntimeAccount(accountId: string, syncVersion: number): Promise { const matchedAccount = state.accounts.find((item) => item.id === accountId) ?? null; diff --git a/apps/desktop-client/src/renderer/views/AiPlatformsView.vue b/apps/desktop-client/src/renderer/views/AiPlatformsView.vue index 30fae0a..27d756d 100644 --- a/apps/desktop-client/src/renderer/views/AiPlatformsView.vue +++ b/apps/desktop-client/src/renderer/views/AiPlatformsView.vue @@ -17,7 +17,7 @@ import type { RuntimeAccount } from "../types"; type AccountRow = Readonly> & { tags: readonly string[] }; -const { snapshot, refreshAccounts, loading } = useDesktopRuntime(); +const { snapshot, refresh, refreshAccounts, loading } = useDesktopRuntime(); const bindPendingPlatformId = ref(null); const openPendingAccountId = ref(null); @@ -156,7 +156,7 @@ async function bindPlatform(platformId: string) { const account = await window.desktopBridge.app.bindPublishAccount(platformId); const platformLabel = desktopMonitoringMediaCatalog.find((item) => item.id === platformId)?.label ?? platformId; showActionNotification("success", "绑定成功", `${account.display_name} 已绑定到 ${platformLabel}`); - await refreshAccounts(); + await refresh(); } catch (error) { showClientActionError("bind-account", error); } finally {