Ethanfly hai 10 horas
pai
achega
92c3494f4c

+ 4 - 4
client/src/api/accounts.ts

@@ -57,7 +57,7 @@ export const accountsApi = {
   },
 
   refreshAccount(id: number): Promise<{ account: PlatformAccount; needReLogin: boolean }> {
-    return request.post(`/api/accounts/${id}/refresh`).then((data: PlatformAccount & { needReLogin?: boolean }) => {
+    return request.post(`/api/accounts/${id}/refresh`, {}, { timeout: 120000 }).then((data: PlatformAccount & { needReLogin?: boolean }) => {
       const { needReLogin, ...account } = data as PlatformAccount & { needReLogin?: boolean };
       return { account: account as PlatformAccount, needReLogin: needReLogin || false };
     });
@@ -65,12 +65,12 @@ export const accountsApi = {
 
   // 批量刷新所有账号状态
   refreshAllAccounts(): Promise<{ refreshed: number; failed: number }> {
-    return request.post('/api/accounts/refresh-all');
+    return request.post('/api/accounts/refresh-all', {}, { timeout: 300000 }); // 5分钟超时
   },
 
   // 检查账号 Cookie 是否有效
   checkAccountStatus(id: number): Promise<{ isValid: boolean; needReLogin: boolean }> {
-    return request.get(`/api/accounts/${id}/check-status`);
+    return request.get(`/api/accounts/${id}/check-status`, { timeout: 120000 }); // 2分钟超时
   },
 
   // 扫码登录
@@ -122,7 +122,7 @@ export const accountsApi = {
       worksCount: number;
     };
   }> {
-    return request.post('/api/accounts/verify-cookie', { platform, cookieData });
+    return request.post('/api/accounts/verify-cookie', { platform, cookieData }, { timeout: 120000 }); // 2分钟超时
   },
 
   // 获取账号 Cookie(用于打开后台)

+ 225 - 185
client/src/components/BrowserTab.vue

@@ -59,13 +59,19 @@
         <div class="success-content">
           <el-icon class="success-icon"><CircleCheck /></el-icon>
           <h3>登录成功!</h3>
-          <div v-if="accountInfo" class="account-preview">
-            <el-avatar :size="56" :src="accountInfo.avatarUrl || undefined">
-              {{ accountInfo.accountName?.[0] }}
+          <!-- 正在获取账号信息 -->
+          <div v-if="fetchingAccountInfo" class="account-fetching">
+            <el-icon class="fetching-icon"><Loading /></el-icon>
+            <span>正在获取账号信息...</span>
+          </div>
+          <!-- 已获取到账号信息 -->
+          <div v-else-if="hasValidAccountInfo" class="account-preview">
+            <el-avatar :size="56" :src="accountInfo?.avatarUrl || undefined">
+              {{ accountInfo?.accountName?.[0] }}
             </el-avatar>
             <div class="account-preview-info">
-              <div class="account-preview-name">{{ accountInfo.accountName }}</div>
-              <div class="account-preview-id">{{ accountInfo.accountId }}</div>
+              <div class="account-preview-name">{{ accountInfo?.accountName }}</div>
+              <div class="account-preview-id">{{ accountInfo?.accountId }}</div>
             </div>
           </div>
           <p>点击"保存账号"完成添加</p>
@@ -117,6 +123,7 @@ const accountInfo = ref<{
   worksCount: number;
 } | null>(null);
 const cookieData = ref('');
+const fetchingAccountInfo = ref(false); // 是否正在获取账号信息
 
 // 计时器和标志位
 let checkTimer: ReturnType<typeof setInterval> | null = null;
@@ -129,6 +136,16 @@ const platform = computed(() => props.tab.browserData?.platform as PlatformType)
 // 是否是管理后台模式(从后台按钮打开,不需要登录检测和保存账号)
 const isAdminMode = computed(() => !!props.tab.browserData?.isAdminMode);
 
+// 是否已获取到有效的账号信息(排除默认值)
+const hasValidAccountInfo = computed(() => {
+  if (!accountInfo.value) return false;
+  const defaultNames = [
+    '抖音账号', '小红书账号', '快手账号', '视频号账号', 'B站账号', 
+    '头条账号', '百家号账号', '企鹅号账号', '大鱼号账号'
+  ];
+  return accountInfo.value.accountName && !defaultNames.includes(accountInfo.value.accountName);
+});
+
 const initialUrl = computed(() => {
   // 优先使用 browserData 中指定的 URL
   if (props.tab.browserData?.url) {
@@ -191,20 +208,6 @@ function handleNavigate(event: Electron.DidNavigateEvent) {
   if (!isAdminMode.value && loginStatus.value !== 'success') {
     setTimeout(() => checkLoginSilently(), 500);
   }
-  
-  // 百家号特殊处理:如果已经登录成功但账号信息是默认值,尝试重新获取
-  if (platform.value === 'baijiahao' && 
-      loginStatus.value === 'success' && 
-      accountInfo.value?.accountName === '百家号账号' &&
-      event.url.includes('baijiahao.baidu.com/builder')) {
-    console.log('[BrowserTab] 百家号跳转到后台页面,尝试重新获取账号信息');
-    setTimeout(async () => {
-      const info = await fetchBaijiahaoAccountInfo();
-      if (info && info.accountName !== '百家号账号') {
-        accountInfo.value = info;
-      }
-    }, 1500);
-  }
 }
 
 function handleNavigateInPage(event: Electron.DidNavigateInPageEvent) {
@@ -277,7 +280,7 @@ function isLoggedInByUrl(): boolean {
     xiaohongshu: [/passport/, /login/i],
     bilibili: [/passport/, /login/i],
     toutiao: [/passport/, /login/i],
-    baijiahao: [/passport/, /login/i],
+    baijiahao: [/passport/, /login/i, /bjh\/login/],  // 包含 /builder/theme/bjh/login
   };
   
   // 如果在登录页面,返回 false
@@ -311,7 +314,10 @@ function isLoggedInByUrl(): boolean {
       /mp\.toutiao\.com\/profile/,
     ],
     baijiahao: [
-      /baijiahao\.baidu\.com\/builder/,           // 任何后台页面(builder 目录下)
+      /baijiahao\.baidu\.com\/builder\/rc/,       // 创作中心首页
+      /baijiahao\.baidu\.com\/builder\/app/,      // 应用页面
+      /baijiahao\.baidu\.com\/builder\/content/,  // 内容管理
+      // 注意:排除 /builder/theme/bjh/login 登录页面
     ],
   };
   
@@ -332,158 +338,184 @@ async function checkLoginSilently() {
       // 简单判断是否有登录相关的 cookie
       const hasLoginCookie = checkHasLoginCookie(cookies);
       
-      // 调试日志
-      if (platform.value === 'baijiahao') {
-        console.log('[BrowserTab] 百家号检测 - URL:', currentUrl.value);
-        console.log('[BrowserTab] 百家号检测 - hasLoginCookie:', hasLoginCookie);
-        console.log('[BrowserTab] 百家号检测 - cookies 数量:', cookies.length);
-        const bduss = cookies.find(c => c.name === 'BDUSS');
-        console.log('[BrowserTab] 百家号检测 - BDUSS:', bduss ? '存在' : '不存在');
-      }
-      
       if (hasLoginCookie && loginStatus.value !== 'success') {
         // 检查 URL 是否已经在登录后的页面
         const urlIndicatesLoggedIn = isLoggedInByUrl();
         
-        if (platform.value === 'baijiahao') {
-          console.log('[BrowserTab] 百家号检测 - urlIndicatesLoggedIn:', urlIndicatesLoggedIn);
-        }
-        
         if (urlIndicatesLoggedIn) {
           // URL 表明已登录,快速响应:先显示成功,再异步获取详情
-          console.log('[BrowserTab] URL 表明已登录,调用 quickLoginSuccess');
           await quickLoginSuccess(cookies);
         } else {
           // 还在登录页面,通过服务器验证
-          console.log('[BrowserTab] 通过服务器验证登录');
           await verifyLoginWithServer(cookies, true);
         }
       }
     }
   } catch (error) {
     // 静默失败,不处理
-    console.error('[BrowserTab] checkLoginSilently 异常:', error);
   }
 }
 
-// 通过 webview 执行脚本获取百家号账号信息
-async function fetchBaijiahaoAccountInfo(retryCount = 0): Promise<{
+// 从页面直接提取账号信息
+async function extractAccountInfoFromPage(): Promise<{
   accountId: string;
   accountName: string;
   avatarUrl: string;
   fansCount: number;
   worksCount: number;
 } | null> {
-  console.log('[BrowserTab] fetchBaijiahaoAccountInfo 开始, retryCount:', retryCount);
-  
-  if (!webviewRef.value) {
-    console.log('[BrowserTab] webviewRef 不存在');
-    return null;
-  }
-  
-  // 等待页面加载完成
-  console.log('[BrowserTab] 等待1秒让页面加载...');
-  await new Promise(resolve => setTimeout(resolve, 1000));
-  
+  const webview = document.querySelector(`webview[partition="${webviewPartition.value}"]`) as Electron.WebviewTag | null;
+  if (!webview) return null;
+
   try {
-    // 先获取当前页面的 URL
-    const currentPageUrl = await webviewRef.value.executeJavaScript('window.location.href');
-    console.log('[BrowserTab] 当前页面 URL:', currentPageUrl);
-    
-    // 检查是否在百家号域名下
-    if (!currentPageUrl.includes('baijiahao.baidu.com')) {
-      console.log('[BrowserTab] 当前页面不在百家号域名下,跳过获取');
-      return null;
-    }
-    
-    console.log('[BrowserTab] 正在获取百家号账号信息...');
-    const script = `
-      (async () => {
-        try {
-          console.log('[Baijiahao] 当前 URL:', window.location.href);
-          console.log('[Baijiahao] 当前 Cookie:', document.cookie.substring(0, 100));
-          console.log('[Baijiahao] Fetching settingInfo...');
+    // 根据不同平台使用不同的提取脚本
+    const extractScripts: Record<string, string> = {
+      douyin: `
+        (function() {
+          const result = { accountId: '', accountName: '', avatarUrl: '', fansCount: 0, worksCount: 0 };
           
-          const response = await fetch('https://baijiahao.baidu.com/user-ui/cms/settingInfo', {
-            method: 'GET',
-            credentials: 'include',
-            headers: {
-              'Accept': 'application/json, text/plain, */*',
-              'Referer': 'https://baijiahao.baidu.com/'
-            }
-          });
+          // 从页面元素提取
+          // 头像
+          const avatarEl = document.querySelector('img[class*="avatar"], .user-avatar img, [class*="userAvatar"] img');
+          if (avatarEl) result.avatarUrl = avatarEl.src || '';
           
-          console.log('[Baijiahao] Response status:', response.status);
+          // 昵称 - 多种选择器
+          const nameSelectors = [
+            '.user-name', '.userName', '[class*="userName"]', '[class*="nickname"]',
+            '.user-info .name', '.user-info h3', '.user-info h4',
+            '[class*="userInfo"] [class*="name"]', '.creator-name'
+          ];
+          for (const sel of nameSelectors) {
+            const el = document.querySelector(sel);
+            if (el && el.textContent?.trim()) {
+              result.accountName = el.textContent.trim();
+              break;
+            }
+          }
           
-          if (!response.ok) {
-            return { success: false, error: 'HTTP ' + response.status };
+          // 从 URL 或 Cookie 提取 UID
+          const uidMatch = document.cookie.match(/passport_uid=([^;]+)/) || 
+                          document.cookie.match(/uid=([^;]+)/) ||
+                          document.cookie.match(/x-uuid=([^;]+)/);
+          if (uidMatch) {
+            result.accountId = 'douyin_' + uidMatch[1];
           }
           
-          const text = await response.text();
-          console.log('[Baijiahao] Response text (first 300):', text.substring(0, 300));
+          // 尝试从 window 对象获取
+          if (window.__INITIAL_STATE__) {
+            const state = window.__INITIAL_STATE__;
+            if (state.user) {
+              result.accountName = result.accountName || state.user.nickname || state.user.name || '';
+              result.avatarUrl = result.avatarUrl || state.user.avatar || state.user.avatarUrl || '';
+              result.accountId = result.accountId || ('douyin_' + (state.user.uid || state.user.userId || ''));
+            }
+          }
           
-          let data;
-          try {
-            data = JSON.parse(text);
-          } catch (e) {
-            return { success: false, error: 'JSON parse error: ' + e.message };
+          // 尝试从 SSR 数据获取
+          const ssrScript = document.querySelector('script[id*="RENDER_DATA"], script[type="application/json"]');
+          if (ssrScript) {
+            try {
+              const data = JSON.parse(decodeURIComponent(ssrScript.textContent || ''));
+              const user = data.user || data.userInfo || data.creator || {};
+              result.accountName = result.accountName || user.nickname || user.name || '';
+              result.avatarUrl = result.avatarUrl || user.avatar || user.avatarUrl || '';
+              result.accountId = result.accountId || ('douyin_' + (user.uid || user.userId || ''));
+            } catch {}
           }
           
-          console.log('[Baijiahao] settingInfo response:', JSON.stringify(data).substring(0, 300));
+          return result;
+        })()
+      `,
+      xiaohongshu: `
+        (function() {
+          const result = { accountId: '', accountName: '', avatarUrl: '', fansCount: 0, worksCount: 0 };
           
-          if (data.errno === 0 && data.data) {
-            const accountId = data.data.new_uc_id ? String(data.data.new_uc_id) : 'baijiahao_' + Date.now();
-            const accountName = data.data.name || '百家号账号';
-            const avatarUrl = data.data.avatar || '';
-            console.log('[Baijiahao] 获取成功: id=' + accountId + ', name=' + accountName);
-            return {
-              success: true,
-              accountId: accountId,
-              accountName: accountName,
-              avatarUrl: avatarUrl,
-            };
-          }
+          const avatarEl = document.querySelector('.user-avatar img, [class*="avatar"] img');
+          if (avatarEl) result.avatarUrl = avatarEl.src || '';
           
-          return { success: false, errno: data.errno, errmsg: data.errmsg || 'Unknown error' };
-        } catch (e) {
-          console.error('[Baijiahao] Error:', e);
-          return { success: false, error: e.message || String(e) };
-        }
-      })()
-    `;
-    
-    console.log('[BrowserTab] 执行 JavaScript 脚本...');
-    const result = await webviewRef.value.executeJavaScript(script);
-    console.log('[BrowserTab] 百家号账号信息结果:', JSON.stringify(result));
+          const nameEl = document.querySelector('.user-name, [class*="userName"], [class*="nickname"]');
+          if (nameEl) result.accountName = nameEl.textContent?.trim() || '';
+          
+          const uidMatch = document.cookie.match(/customerClientId=([^;]+)/) || 
+                          document.cookie.match(/web_session=([^;]+)/);
+          if (uidMatch) result.accountId = 'xiaohongshu_' + uidMatch[1].slice(0, 16);
+          
+          return result;
+        })()
+      `,
+      kuaishou: `
+        (function() {
+          const result = { accountId: '', accountName: '', avatarUrl: '', fansCount: 0, worksCount: 0 };
+          
+          const avatarEl = document.querySelector('.user-avatar img, [class*="avatar"] img');
+          if (avatarEl) result.avatarUrl = avatarEl.src || '';
+          
+          const nameEl = document.querySelector('.user-name, [class*="userName"], [class*="nickname"]');
+          if (nameEl) result.accountName = nameEl.textContent?.trim() || '';
+          
+          const uidMatch = document.cookie.match(/userId=([^;]+)/);
+          if (uidMatch) result.accountId = 'kuaishou_' + uidMatch[1];
+          
+          return result;
+        })()
+      `,
+      baijiahao: `
+        (function() {
+          const result = { accountId: '', accountName: '', avatarUrl: '', fansCount: 0, worksCount: 0 };
+          
+          const avatarEl = document.querySelector('.user-avatar img, [class*="avatar"] img, .header-avatar img');
+          if (avatarEl) result.avatarUrl = avatarEl.src || '';
+          
+          const nameEl = document.querySelector('.user-name, [class*="userName"], [class*="nickname"], .header-name');
+          if (nameEl) result.accountName = nameEl.textContent?.trim() || '';
+          
+          // 从 cookie 获取
+          const uidMatch = document.cookie.match(/BAIDUID=([^:;]+)/);
+          if (uidMatch) result.accountId = 'baijiahao_' + uidMatch[1];
+          
+          return result;
+        })()
+      `,
+      bilibili: `
+        (function() {
+          const result = { accountId: '', accountName: '', avatarUrl: '', fansCount: 0, worksCount: 0 };
+          
+          const avatarEl = document.querySelector('.user-avatar img, [class*="avatar"] img');
+          if (avatarEl) result.avatarUrl = avatarEl.src || '';
+          
+          const nameEl = document.querySelector('.user-name, [class*="userName"], [class*="nickname"]');
+          if (nameEl) result.accountName = nameEl.textContent?.trim() || '';
+          
+          const uidMatch = document.cookie.match(/DedeUserID=([^;]+)/);
+          if (uidMatch) result.accountId = 'bilibili_' + uidMatch[1];
+          
+          return result;
+        })()
+      `,
+    };
+
+    const script = extractScripts[platform.value];
+    if (!script) return null;
+
+    const info = await webview.executeJavaScript(script);
+    console.log(`[${platform.value}] Extracted account info from page:`, info);
     
-    if (result?.success) {
-      console.log('[BrowserTab] 获取百家号账号信息成功:', result.accountName);
+    // 验证提取结果
+    if (info && (info.accountName || info.accountId)) {
       return {
-        accountId: result.accountId,
-        accountName: result.accountName,
-        avatarUrl: result.avatarUrl,
-        fansCount: 0,
-        worksCount: 0,
+        accountId: info.accountId || `${platform.value}_${Date.now()}`,
+        accountName: info.accountName || `${PLATFORMS[platform.value]?.name || platform.value}账号`,
+        avatarUrl: info.avatarUrl || '',
+        fansCount: info.fansCount || 0,
+        worksCount: info.worksCount || 0,
       };
     }
     
-    console.log('[BrowserTab] 获取百家号账号信息失败:', result?.error || result?.errmsg);
-    
-    // 如果失败且重试次数少于3次,等待后重试
-    if (retryCount < 3) {
-      console.log(`[BrowserTab] 获取百家号账号信息失败,${retryCount + 1}/3 次重试...`);
-      await new Promise(resolve => setTimeout(resolve, 2000));
-      return fetchBaijiahaoAccountInfo(retryCount + 1);
-    }
+    return null;
   } catch (error) {
-    console.error('[BrowserTab] 获取百家号账号信息异常:', error);
-    // 失败时重试
-    if (retryCount < 3) {
-      await new Promise(resolve => setTimeout(resolve, 2000));
-      return fetchBaijiahaoAccountInfo(retryCount + 1);
-    }
+    console.error('Failed to extract account info from page:', error);
+    return null;
   }
-  return null;
 }
 
 // 快速登录成功(URL 已表明登录成功时使用)
@@ -505,44 +537,50 @@ async function quickLoginSuccess(cookies: Electron.Cookie[]) {
     ElMessage.success('检测到登录成功!');
   }
   
-  // 异步获取账号详细信息
+  // 设置正在获取账号信息状态
+  fetchingAccountInfo.value = true;
+  accountInfo.value = null;
+  
+  // 第一步:尝试从当前页面直接提取账号信息(快速)
   try {
-    // 百家号使用特殊方式获取账号信息(通过 webview 执行脚本)
-    if (platform.value === 'baijiahao') {
-      const baijiahaoInfo = await fetchBaijiahaoAccountInfo();
-      if (baijiahaoInfo) {
-        accountInfo.value = baijiahaoInfo;
-        isVerifying = false;
-        return;
-      }
-    }
-    
-    // 其他平台通过服务器 API 验证
-    const result = await accountsApi.verifyLoginCookie(platform.value, cookieString);
-    if (result.success && result.accountInfo) {
-      accountInfo.value = result.accountInfo;
-    } else {
-      // 即使获取详情失败,也保持登录成功状态
-      accountInfo.value = {
-        accountId: `${platform.value}_${Date.now()}`,
-        accountName: `${PLATFORMS[platform.value]?.name || platform.value}账号`,
-        avatarUrl: '',
-        fansCount: 0,
-        worksCount: 0,
-      };
+    const pageInfo = await extractAccountInfoFromPage();
+    if (pageInfo && pageInfo.accountName && pageInfo.accountName !== `${PLATFORMS[platform.value]?.name || platform.value}账号`) {
+      console.log('[quickLoginSuccess] Got account info from page:', pageInfo);
+      accountInfo.value = pageInfo;
+      fetchingAccountInfo.value = false;
+      isVerifying = false;
+      return; // 成功从页面提取,无需调用后端 API
     }
   } catch (error) {
-    // 获取详情失败,使用默认值
-    accountInfo.value = {
-      accountId: `${platform.value}_${Date.now()}`,
-      accountName: `${PLATFORMS[platform.value]?.name || platform.value}账号`,
-      avatarUrl: '',
-      fansCount: 0,
-      worksCount: 0,
-    };
-  } finally {
-    isVerifying = false;
+    console.warn('[quickLoginSuccess] Failed to extract from page:', error);
   }
+  
+  // 第二步:如果页面提取失败,后台异步获取
+  accountsApi.verifyLoginCookie(platform.value, cookieString)
+    .then(result => {
+      if (result.success && result.accountInfo) {
+        // 只有在用户还没保存时才更新
+        if (loginStatus.value === 'success') {
+          accountInfo.value = result.accountInfo;
+        }
+      }
+    })
+    .catch(() => {
+      // 静默失败,使用默认值
+      if (loginStatus.value === 'success' && !accountInfo.value) {
+        accountInfo.value = {
+          accountId: `${platform.value}_${Date.now()}`,
+          accountName: `${PLATFORMS[platform.value]?.name || platform.value}账号`,
+          avatarUrl: '',
+          fansCount: 0,
+          worksCount: 0,
+        };
+      }
+    })
+    .finally(() => {
+      fetchingAccountInfo.value = false;
+      isVerifying = false;
+    });
 }
 
 // 检查是否有登录 cookie
@@ -619,26 +657,7 @@ async function verifyLoginWithServer(cookies: Electron.Cookie[], silent = false)
   cookieData.value = cookieString;
   
   try {
-    // 百家号使用特殊方式获取账号信息(通过 webview 执行脚本)
-    if (platform.value === 'baijiahao') {
-      const baijiahaoInfo = await fetchBaijiahaoAccountInfo();
-      if (baijiahaoInfo) {
-        if (loginStatus.value !== 'success') {
-          loginStatus.value = 'success';
-          accountInfo.value = baijiahaoInfo;
-          stopAutoCheck();
-          
-          if (!hasShownSuccessMessage) {
-            hasShownSuccessMessage = true;
-            ElMessage.success('检测到登录成功!');
-          }
-        }
-        isVerifying = false;
-        return;
-      }
-    }
-    
-    // 其他平台调用服务器 API 验证并获取账号信息
+    // 所有平台统一调用服务器 API 验证并获取账号信息
     const result = await accountsApi.verifyLoginCookie(platform.value, cookieString);
     
     if (result.success && result.accountInfo) {
@@ -646,6 +665,7 @@ async function verifyLoginWithServer(cookies: Electron.Cookie[], silent = false)
       if (loginStatus.value !== 'success') {
         loginStatus.value = 'success';
         accountInfo.value = result.accountInfo;
+        fetchingAccountInfo.value = false;
         stopAutoCheck();
         
         // 只显示一次成功消息
@@ -1042,6 +1062,26 @@ watch(() => props.tab.id, () => {
   }
 }
 
+.account-fetching {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 10px;
+  padding: 16px 24px;
+  background: $primary-color-light;
+  border-radius: $radius-lg;
+  margin: 24px 0;
+  border: 1px solid $border-light;
+  color: $text-secondary;
+  font-size: 14px;
+  
+  .fetching-icon {
+    font-size: 18px;
+    color: $primary-color;
+    animation: spin 1s linear infinite;
+  }
+}
+
 .account-preview {
   display: flex;
   align-items: center;

+ 13 - 9
client/src/stores/auth.ts

@@ -54,15 +54,19 @@ export const useAuthStore = defineStore('auth', () => {
     return result;
   }
   
-  // 后台刷新所有账号状态
-  async function refreshAllAccountsInBackground() {
-    try {
-      console.log('[Auth] Starting background account refresh...');
-      await accountsApi.refreshAllAccounts();
-      console.log('[Auth] Background account refresh completed');
-    } catch (error) {
-      console.warn('[Auth] Background account refresh failed:', error);
-    }
+  // 后台刷新所有账号状态(延迟执行,避免服务启动时网络不稳定导致误判)
+  async function refreshAllAccountsInBackground(delay = 5000) {
+    // 延迟执行,给后端服务足够的启动时间
+    setTimeout(async () => {
+      try {
+        console.log('[Auth] Starting background account refresh...');
+        await accountsApi.refreshAllAccounts();
+        console.log('[Auth] Background account refresh completed');
+      } catch (error) {
+        // 刷新失败不应影响用户体验,静默处理
+        console.warn('[Auth] Background account refresh failed:', error);
+      }
+    }, delay);
   }
 
   // 注册

+ 4 - 6
client/src/views/Accounts/index.vue

@@ -476,8 +476,8 @@ function getPlatformName(platform: PlatformType) {
   return PLATFORMS[platform]?.name || platform;
 }
 
-function getStatusType(status: string) {
-  const types: Record<string, string> = {
+function getStatusType(status: string): 'success' | 'danger' | 'info' | 'primary' | 'warning' {
+  const types: Record<string, 'success' | 'danger' | 'info' | 'primary' | 'warning'> = {
     active: 'success',
     expired: 'danger',
     disabled: 'info',
@@ -838,10 +838,8 @@ async function verifyAccountStatus(account: PlatformAccount) {
 
 onMounted(async () => {
   await loadAccounts();
-  // 页面加载后检查是否有过期账号
-  setTimeout(() => {
-    checkExpiredAccounts();
-  }, 1000);
+  // 页面加载后不自动检查过期账号,避免服务启动时网络不稳定导致误判
+  // 过期账号会在定时任务刷新后或用户手动刷新后提示
 });
 
 onUnmounted(() => {

+ 60 - 0
server/python/app.py

@@ -610,6 +610,66 @@ def check_login():
         }), 500
 
 
+# ==================== 获取账号信息接口 ====================
+
+@app.route("/account_info", methods=["POST"])
+def get_account_info():
+    """
+    获取账号信息
+    
+    请求体:
+    {
+        "platform": "baijiahao",          # 平台
+        "cookie": "cookie字符串或JSON"
+    }
+    
+    响应:
+    {
+        "success": true,
+        "account_id": "xxx",
+        "account_name": "用户名",
+        "avatar_url": "头像URL",
+        "fans_count": 0,
+        "works_count": 0
+    }
+    """
+    try:
+        data = request.json
+        
+        platform = data.get("platform", "").lower()
+        cookie_str = data.get("cookie", "")
+        
+        print(f"[AccountInfo] 收到请求: platform={platform}")
+        
+        if not platform:
+            return jsonify({"success": False, "error": "缺少 platform 参数"}), 400
+        if platform not in PLATFORM_MAP:
+            return jsonify({
+                "success": False,
+                "error": f"不支持的平台: {platform},支持: {list(PLATFORM_MAP.keys())}"
+            }), 400
+        if not cookie_str:
+            return jsonify({"success": False, "error": "缺少 cookie 参数"}), 400
+        
+        # 获取对应平台的发布器
+        PublisherClass = get_publisher(platform)
+        publisher = PublisherClass(headless=HEADLESS_MODE)
+        
+        # 检查是否有 get_account_info 方法
+        if hasattr(publisher, 'get_account_info'):
+            result = asyncio.run(publisher.get_account_info(cookie_str))
+            return jsonify(result)
+        else:
+            return jsonify({
+                "success": False,
+                "error": f"平台 {platform} 不支持获取账号信息"
+            }), 400
+        
+    except Exception as e:
+        traceback.print_exc()
+        return jsonify({"success": False, "error": str(e)}), 500
+
+
 # ==================== 健康检查 ====================
 
 @app.route("/health", methods=["GET"])

+ 4 - 1
server/python/platforms/__init__.py

@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """
 平台发布模块
-支持: 抖音、小红书、视频号、快手
+支持: 抖音、小红书、视频号、快手、百家号
 """
 
 from .base import BasePublisher
@@ -9,6 +9,7 @@ from .douyin import DouyinPublisher
 from .xiaohongshu import XiaohongshuPublisher
 from .weixin import WeixinPublisher
 from .kuaishou import KuaishouPublisher
+from .baijiahao import BaijiahaoPublisher
 
 __all__ = [
     'BasePublisher',
@@ -16,6 +17,7 @@ __all__ = [
     'XiaohongshuPublisher',
     'WeixinPublisher',
     'KuaishouPublisher',
+    'BaijiahaoPublisher',
 ]
 
 # 平台映射
@@ -25,6 +27,7 @@ PLATFORM_MAP = {
     'weixin': WeixinPublisher,
     'weixin_video': WeixinPublisher,  # 别名
     'kuaishou': KuaishouPublisher,
+    'baijiahao': BaijiahaoPublisher,
 }
 
 

BIN=BIN
server/python/platforms/__pycache__/__init__.cpython-313.pyc


BIN=BIN
server/python/platforms/__pycache__/baijiahao.cpython-313.pyc


+ 251 - 0
server/python/platforms/baijiahao.py

@@ -0,0 +1,251 @@
+# -*- coding: utf-8 -*-
+"""
+百家号视频发布器
+"""
+
+import asyncio
+import json
+from typing import List
+from datetime import datetime
+from .base import (
+    BasePublisher, PublishParams, PublishResult,
+    WorkItem, WorksResult, CommentItem, CommentsResult
+)
+
+
+class BaijiahaoPublisher(BasePublisher):
+    """
+    百家号视频发布器
+    使用 Playwright 自动化操作百家号创作者中心
+    """
+    
+    platform_name = "baijiahao"
+    login_url = "https://baijiahao.baidu.com/"
+    publish_url = "https://baijiahao.baidu.com/builder/rc/edit?type=video"
+    cookie_domain = ".baidu.com"
+    
+    # 登录检测配置
+    login_check_url = "https://baijiahao.baidu.com/builder/rc/home"
+    login_indicators = ["passport.baidu.com", "/login", "wappass.baidu.com"]
+    login_selectors = ['text="登录"', 'text="请登录"', '[class*="login-btn"]']
+    
+    async def get_account_info(self, cookies: str) -> dict:
+        """
+        获取百家号账号信息
+        通过调用 settingInfo API 获取用户信息
+        """
+        print(f"\n{'='*60}")
+        print(f"[{self.platform_name}] 获取账号信息")
+        print(f"{'='*60}")
+        
+        try:
+            await self.init_browser()
+            cookie_list = self.parse_cookies(cookies)
+            await self.set_cookies(cookie_list)
+            
+            if not self.page:
+                raise Exception("Page not initialized")
+            
+            # 访问百家号后台首页
+            print(f"[{self.platform_name}] 访问后台首页...")
+            await self.page.goto(self.login_check_url, wait_until="domcontentloaded", timeout=30000)
+            await asyncio.sleep(3)
+            
+            # 检查登录状态
+            current_url = self.page.url
+            print(f"[{self.platform_name}] 当前 URL: {current_url}")
+            
+            for indicator in self.login_indicators:
+                if indicator in current_url:
+                    print(f"[{self.platform_name}] 检测到登录页面,Cookie 已失效")
+                    return {
+                        "success": False,
+                        "error": "Cookie 已失效,需要重新登录",
+                        "need_login": True
+                    }
+            
+            # 调用 settingInfo API 获取用户信息
+            print(f"[{self.platform_name}] 调用 settingInfo API...")
+            api_result = await self.page.evaluate('''
+                async () => {
+                    try {
+                        const response = await fetch('https://baijiahao.baidu.com/user-ui/cms/settingInfo', {
+                            method: 'GET',
+                            credentials: 'include',
+                            headers: {
+                                'Accept': 'application/json, text/plain, */*'
+                            }
+                        });
+                        return await response.json();
+                    } catch (e) {
+                        return { error: e.message };
+                    }
+                }
+            ''')
+            
+            print(f"[{self.platform_name}] API 响应: errno={api_result.get('errno')}")
+            
+            if api_result.get('error'):
+                return {
+                    "success": False,
+                    "error": api_result.get('error')
+                }
+            
+            if api_result.get('errno') == 0 and api_result.get('data'):
+                data = api_result['data']
+                account_info = {
+                    "success": True,
+                    "account_id": str(data.get('new_uc_id', '')) or f"baijiahao_{int(datetime.now().timestamp() * 1000)}",
+                    "account_name": data.get('name', '') or '百家号账号',
+                    "avatar_url": data.get('avatar', ''),
+                    "fans_count": 0,  # 百家号 API 不直接返回粉丝数
+                    "works_count": 0,
+                }
+                print(f"[{self.platform_name}] 获取成功: {account_info['account_name']}")
+                return account_info
+            else:
+                error_msg = api_result.get('errmsg', '未知错误')
+                print(f"[{self.platform_name}] API 返回错误: {error_msg}")
+                
+                # 如果是登录相关错误,标记需要重新登录
+                if api_result.get('errno') in [10000010, 10001401]:
+                    return {
+                        "success": False,
+                        "error": error_msg,
+                        "need_login": True
+                    }
+                
+                return {
+                    "success": False,
+                    "error": error_msg
+                }
+            
+        except Exception as e:
+            import traceback
+            traceback.print_exc()
+            return {
+                "success": False,
+                "error": str(e)
+            }
+        finally:
+            await self.close_browser()
+    
+    async def publish(self, cookies: str, params: PublishParams) -> PublishResult:
+        """发布视频到百家号"""
+        print(f"\n{'='*60}")
+        print(f"[{self.platform_name}] 开始发布视频")
+        print(f"[{self.platform_name}] 视频路径: {params.video_path}")
+        print(f"[{self.platform_name}] 标题: {params.title}")
+        print(f"{'='*60}")
+        
+        # TODO: 实现百家号视频发布逻辑
+        return PublishResult(
+            success=False,
+            platform=self.platform_name,
+            error="百家号发布功能暂未实现"
+        )
+    
+    async def get_works(self, cookies: str, page: int = 0, page_size: int = 20) -> WorksResult:
+        """获取百家号作品列表"""
+        print(f"\n{'='*60}")
+        print(f"[{self.platform_name}] 获取作品列表")
+        print(f"[{self.platform_name}] page={page}, page_size={page_size}")
+        print(f"{'='*60}")
+        
+        works: List[WorkItem] = []
+        total = 0
+        has_more = False
+        
+        try:
+            await self.init_browser()
+            cookie_list = self.parse_cookies(cookies)
+            await self.set_cookies(cookie_list)
+            
+            if not self.page:
+                raise Exception("Page not initialized")
+            
+            # 访问内容管理页面
+            await self.page.goto("https://baijiahao.baidu.com/builder/rc/content", wait_until="domcontentloaded", timeout=30000)
+            await asyncio.sleep(3)
+            
+            # 检查登录状态
+            current_url = self.page.url
+            for indicator in self.login_indicators:
+                if indicator in current_url:
+                    raise Exception("Cookie 已过期,请重新登录")
+            
+            # 调用作品列表 API
+            cursor = page * page_size
+            api_result = await self.page.evaluate(f'''
+                async () => {{
+                    try {{
+                        const response = await fetch('https://baijiahao.baidu.com/pcui/article/lists?start={cursor}&count={page_size}&article_type=video', {{
+                            method: 'GET',
+                            credentials: 'include',
+                            headers: {{
+                                'Accept': 'application/json'
+                            }}
+                        }});
+                        return await response.json();
+                    }} catch (e) {{
+                        return {{ error: e.message }};
+                    }}
+                }}
+            ''')
+            
+            print(f"[{self.platform_name}] API 响应: {json.dumps(api_result, ensure_ascii=False)[:200]}")
+            
+            if api_result.get('errno') == 0:
+                article_list = api_result.get('data', {}).get('article_list', [])
+                has_more = api_result.get('data', {}).get('has_more', False)
+                
+                for article in article_list:
+                    work_id = str(article.get('article_id', ''))
+                    if not work_id:
+                        continue
+                    
+                    works.append(WorkItem(
+                        work_id=work_id,
+                        title=article.get('title', ''),
+                        cover_url=article.get('cover_images', [''])[0] if article.get('cover_images') else '',
+                        duration=0,
+                        status='published',
+                        publish_time=article.get('publish_time', ''),
+                        play_count=int(article.get('read_count', 0)),
+                        like_count=int(article.get('like_count', 0)),
+                        comment_count=int(article.get('comment_count', 0)),
+                        share_count=int(article.get('share_count', 0)),
+                    ))
+                
+                total = len(works)
+            
+            print(f"[{self.platform_name}] 获取到 {total} 个作品")
+            
+        except Exception as e:
+            import traceback
+            traceback.print_exc()
+            return WorksResult(
+                success=False,
+                platform=self.platform_name,
+                error=str(e)
+            )
+        finally:
+            await self.close_browser()
+        
+        return WorksResult(
+            success=True,
+            platform=self.platform_name,
+            works=works,
+            total=total,
+            has_more=has_more
+        )
+    
+    async def get_comments(self, cookies: str, work_id: str, cursor: str = "") -> CommentsResult:
+        """获取百家号作品评论"""
+        # TODO: 实现评论获取逻辑
+        return CommentsResult(
+            success=False,
+            platform=self.platform_name,
+            work_id=work_id,
+            error="百家号评论功能暂未实现"
+        )

+ 15 - 22
server/src/services/AccountService.ts

@@ -494,14 +494,8 @@ export class AccountService {
         return { success: false, message: 'Cookie 格式无效' };
       }
 
-      // 验证 Cookie 是否有效
-      const isValid = await headlessBrowserService.checkCookieValid(platform, cookieList);
-      
-      if (!isValid) {
-        return { success: false, message: '登录状态无效或已过期' };
-      }
-
-      // 获取账号信息
+      // 先尝试获取账号信息(可以同时验证登录状态)
+      // 如果能成功获取到有效信息,说明登录是有效的
       try {
         const profile = await headlessBrowserService.fetchAccountInfo(platform, cookieList);
         
@@ -523,23 +517,19 @@ export class AccountService {
               worksCount: profile.worksCount || 0,
             },
           };
-        } else {
-          // Cookie 有效但未能获取账号信息,返回基本成功
-          return {
-            success: true,
-            message: '登录成功,但无法获取详细信息',
-            accountInfo: {
-              accountId: `${platform}_${Date.now()}`,
-              accountName: `${platform}账号`,
-              avatarUrl: '',
-              fansCount: 0,
-              worksCount: 0,
-            },
-          };
         }
+        
+        // 未能获取有效信息,再验证 Cookie 是否有效
+        logger.info(`[verifyCookieAndGetInfo] Could not get valid profile for ${platform}, checking cookie validity...`);
       } catch (infoError) {
         logger.warn(`Failed to fetch account info for ${platform}:`, infoError);
-        // Cookie 有效但获取信息失败
+      }
+      
+      // 账号信息获取失败或无效,检查 Cookie 是否有效
+      const isValid = await headlessBrowserService.checkCookieValid(platform, cookieList);
+      
+      if (isValid) {
+        // Cookie 有效但未能获取账号信息,返回基本成功
         return {
           success: true,
           message: '登录成功,但无法获取详细信息',
@@ -551,6 +541,9 @@ export class AccountService {
             worksCount: 0,
           },
         };
+      } else {
+        // Cookie 无效
+        return { success: false, message: '登录状态无效或已过期' };
       }
     } catch (error) {
       logger.error(`Failed to verify cookie for ${platform}:`, error);

+ 94 - 78
server/src/services/HeadlessBrowserService.ts

@@ -166,6 +166,7 @@ class HeadlessBrowserService {
 
   /**
    * 通过 API 检查 Cookie 是否有效
+   * 注意:API 返回不确定状态时会回退到浏览器检查,避免误判
    */
   private async checkCookieValidByApi(
     platform: PlatformType,
@@ -202,10 +203,28 @@ class HeadlessBrowserService {
 
       const data = await response.json();
       const isValid = apiConfig.isValidResponse(data);
+      const statusCode = (data as { status_code?: number })?.status_code;
 
-      logger.info(`API check cookie for ${platform}: valid=${isValid}, status_code=${(data as { status_code?: number })?.status_code}`);
+      logger.info(`API check cookie for ${platform}: valid=${isValid}, status_code=${statusCode}`);
 
-      return isValid;
+      // 如果 API 明确返回有效,直接返回 true
+      if (isValid) {
+        return true;
+      }
+
+      // API 返回无效时,检查是否是明确的"未登录"状态
+      // status_code 为 2 或 8 通常表示未登录/登录过期
+      // 其他状态码可能是临时错误,需要进一步确认
+      const clearlyNotLoggedIn = statusCode === 2 || statusCode === 8;
+
+      if (clearlyNotLoggedIn) {
+        logger.info(`[API] Platform ${platform} clearly not logged in (status_code=${statusCode})`);
+        return false;
+      }
+
+      // 不确定的状态(如 status_code=7),回退到浏览器检查
+      logger.info(`[API] Uncertain status for ${platform} (status_code=${statusCode}), falling back to browser check`);
+      return this.checkCookieValidByBrowser(platform, cookies);
     } catch (error) {
       logger.error(`API check cookie error for ${platform}:`, error);
       // API 检查失败时,回退到浏览器检查
@@ -228,6 +247,7 @@ class HeadlessBrowserService {
 
   /**
    * 通过浏览器检查 Cookie 是否有效(检查是否被重定向到登录页)
+   * 注意:网络错误或服务不可用时返回 true(保持原状态),避免误判为过期
    */
   private async checkCookieValidByBrowser(platform: PlatformType, cookies: CookieData[]): Promise<boolean> {
     // 对于抖音平台,使用 check/user 接口检查
@@ -272,7 +292,9 @@ class HeadlessBrowserService {
     } catch (error) {
       logger.error(`Browser check cookie error for ${platform}:`, error);
       await browser.close();
-      return false;
+      // 网络错误或服务不可用时返回 true,避免误判为过期
+      logger.warn(`[Browser] Check failed due to error, assuming valid to avoid false expiration`);
+      return true;
     }
   }
 
@@ -341,7 +363,9 @@ class HeadlessBrowserService {
       try {
         await browser.close();
       } catch { }
-      return false;
+      // 网络错误或服务不可用时返回 true,避免误判为过期
+      logger.warn(`[Douyin] Check failed due to error, assuming valid to avoid false expiration`);
+      return true;
     }
   }
 
@@ -428,12 +452,12 @@ class HeadlessBrowserService {
    * 获取账号信息(优先使用 Python API,回退到无头浏览器)
    */
   async fetchAccountInfo(platform: PlatformType, cookies: CookieData[]): Promise<AccountInfo> {
-    // 百家号使用特殊的 API 方式获取账号信息
+    // 百家号使用 Python API 获取账号信息
     if (platform === 'baijiahao') {
-      return this.fetchBaijiahaoAccountInfo(cookies);
+      return this.fetchAccountInfoViaPython(platform, cookies);
     }
 
-    // 对于支持的平台,优先尝试使用 Python API 获取作品列表
+    // 对于支持的平台,尝试使用 Python API 获取作品列表和账号信息
     const supportedPlatforms: PlatformType[] = ['douyin', 'xiaohongshu', 'kuaishou', 'weixin_video'];
 
     if (supportedPlatforms.includes(platform)) {
@@ -443,39 +467,37 @@ class HeadlessBrowserService {
         try {
           const worksList = await this.fetchWorksViaPython(platform, cookies);
 
-          // 如果成功获取到作品,构建基本的账号信息
+          // 如果成功获取到作品,使用 Playwright 获取账号基本信息
           if (worksList.length > 0) {
             logger.info(`[Python API] Successfully fetched ${worksList.length} works for ${platform}`);
 
-            // [临时注释] 不再使用 Playwright 获取账号基本信息,直接使用默认信息
-            // 原代码:const accountInfo = await this.fetchAccountInfoWithPlaywright(platform, cookies);
-            const accountInfo = this.getDefaultAccountInfo(platform);
-            accountInfo.worksList = worksList;
-            accountInfo.worksCount = worksList.length;
-            return accountInfo;
+            try {
+              const accountInfo = await this.fetchAccountInfoWithPlaywright(platform, cookies);
+              accountInfo.worksList = worksList;
+              accountInfo.worksCount = worksList.length;
+              return accountInfo;
+            } catch (playwrightError) {
+              logger.warn(`[Playwright] Failed to get account info for ${platform}:`, playwrightError);
+              const accountInfo = this.getDefaultAccountInfo(platform);
+              accountInfo.worksList = worksList;
+              accountInfo.worksCount = worksList.length;
+              return accountInfo;
+            }
           }
 
-          // 即使作品列表为空,也直接返回默认账号信息,不走 Playwright
-          logger.info(`[Python API] Got empty works list for ${platform}, returning default info`);
-          return this.getDefaultAccountInfo(platform);
+          // 作品列表为空,尝试用 Playwright 获取账号信息
+          logger.info(`[Python API] Got empty works list for ${platform}, trying Playwright`);
         } catch (pythonError) {
-          // [临时注释] 不再回退到 Playwright,直接返回默认信息
           logger.warn(`[Python API] Failed to fetch works for ${platform}:`, pythonError);
-          return this.getDefaultAccountInfo(platform);
-          // 原代码:logger.warn(`[Python API] Failed to fetch works for ${platform}, falling back to Playwright:`, pythonError);
         }
       } else {
-        // [临时注释] Python 服务不可用时,也不走 Playwright,直接返回默认信息
-        logger.info(`[Python API] Service not available for ${platform}, returning default info`);
-        return this.getDefaultAccountInfo(platform);
-        // 原代码:logger.info(`[Python API] Service not available, using Playwright for ${platform}`);
+        logger.info(`[Python API] Service not available for ${platform}`);
       }
     }
 
-    // [临时注释] 不支持的平台也不走 Playwright,直接返回默认信息
-    // 原代码:return this.fetchAccountInfoWithPlaywright(platform, cookies);
-    logger.info(`[API Only] Platform ${platform} not in supported list, returning default info`);
-    return this.getDefaultAccountInfo(platform);
+    // 使用 Playwright 获取账号信息
+    logger.info(`[Playwright] Fetching account info for ${platform}`);
+    return this.fetchAccountInfoWithPlaywright(platform, cookies);
   }
 
   /**
@@ -1574,77 +1596,71 @@ class HeadlessBrowserService {
   }
 
   /**
-   * 获取百家号账号信息 - 通过 API 获取
+   * 通过 Python API 获取账号信息
    */
-  private async fetchBaijiahaoAccountInfo(cookies: CookieData[]): Promise<AccountInfo> {
-    logger.info('[Baijiahao] Fetching account info via API...');
-    logger.info(`[Baijiahao] Cookie count: ${cookies.length}`);
+  private async fetchAccountInfoViaPython(platform: PlatformType, cookies: CookieData[]): Promise<AccountInfo> {
+    logger.info(`[Python API] Fetching account info for ${platform}...`);
 
     try {
+      // 检查 Python 服务是否可用
+      const pythonAvailable = await this.checkPythonServiceAvailable();
+      if (!pythonAvailable) {
+        logger.warn(`[Python API] Service not available, returning default info`);
+        return this.getDefaultAccountInfo(platform);
+      }
+
       // 构建 Cookie 字符串
       const cookieString = cookies.map(c => `${c.name}=${c.value}`).join('; ');
-      logger.info(`[Baijiahao] Cookie string length: ${cookieString.length}`);
 
-      // 调用百家号设置信息 API
-      const response = await fetch('https://baijiahao.baidu.com/user-ui/cms/settingInfo', {
-        method: 'GET',
+      // 调用 Python API
+      const response = await fetch(`${PYTHON_SERVICE_URL}/account_info`, {
+        method: 'POST',
         headers: {
-          'Cookie': cookieString,
-          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
-          'Accept': 'application/json, text/plain, */*',
-          'Referer': 'https://baijiahao.baidu.com/',
-          'Origin': 'https://baijiahao.baidu.com',
+          'Content-Type': 'application/json',
         },
+        body: JSON.stringify({
+          platform,
+          cookie: cookieString,
+        }),
       });
 
-      logger.info(`[Baijiahao] API response status: ${response.status}`);
-
       if (!response.ok) {
-        logger.warn(`[Baijiahao] API returned ${response.status}`);
-        return this.getDefaultAccountInfo('baijiahao');
+        logger.warn(`[Python API] account_info returned ${response.status}`);
+        return this.getDefaultAccountInfo(platform);
       }
 
-      const text = await response.text();
-      logger.info(`[Baijiahao] API response (first 500 chars): ${text.substring(0, 500)}`);
-
-      let result: {
-        errno: number;
-        errmsg: string;
-        data?: {
-          name?: string;
-          avatar?: string;
-          new_uc_id?: number;
-          wish?: string;
-        };
+      const result = await response.json() as {
+        success: boolean;
+        account_id?: string;
+        account_name?: string;
+        avatar_url?: string;
+        fans_count?: number;
+        works_count?: number;
+        error?: string;
+        need_login?: boolean;
       };
 
-      try {
-        result = JSON.parse(text);
-      } catch (parseError) {
-        logger.error('[Baijiahao] Failed to parse JSON response:', parseError);
-        return this.getDefaultAccountInfo('baijiahao');
-      }
-
-      logger.info(`[Baijiahao] API result: errno=${result.errno}, errmsg=${result.errmsg}, has data=${!!result.data}`);
+      logger.info(`[Python API] account_info result: success=${result.success}, name=${result.account_name}`);
 
-      if (result.errno === 0 && result.data) {
-        const accountInfo: AccountInfo = {
-          accountId: result.data.new_uc_id ? String(result.data.new_uc_id) : `baijiahao_${Date.now()}`,
-          accountName: result.data.name || '百家号账号',
-          avatarUrl: result.data.avatar || '',
-          fansCount: 0,
-          worksCount: 0,
+      if (result.success && result.account_name) {
+        return {
+          accountId: result.account_id || `${platform}_${Date.now()}`,
+          accountName: result.account_name,
+          avatarUrl: result.avatar_url || '',
+          fansCount: result.fans_count || 0,
+          worksCount: result.works_count || 0,
         };
+      }
 
-        logger.info(`[Baijiahao] Successfully fetched account info: ${accountInfo.accountName}, avatar: ${accountInfo.avatarUrl?.substring(0, 50)}`);
-        return accountInfo;
+      if (result.need_login) {
+        logger.warn(`[Python API] Account needs re-login`);
       }
 
-      logger.warn(`[Baijiahao] API returned error: ${result.errmsg}`);
-      return this.getDefaultAccountInfo('baijiahao');
+      logger.warn(`[Python API] Failed to get account info: ${result.error}`);
+      return this.getDefaultAccountInfo(platform);
     } catch (error) {
-      logger.error('[Baijiahao] Failed to fetch account info:', error);
-      return this.getDefaultAccountInfo('baijiahao');
+      logger.error(`[Python API] Failed to fetch account info for ${platform}:`, error);
+      return this.getDefaultAccountInfo(platform);
     }
   }