From ff2879f102da1f66bc45548bc50407be54ae0905 Mon Sep 17 00:00:00 2001 From: songkx Date: Wed, 23 Sep 2026 18:15:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8C=89=E4=BB=BB=E5=8A=A1=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=AF=94=E7=89=B9=E6=B5=8F=E8=A7=88=E5=99=A8=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + public/app.js | 69 +---- public/index.html | 10 +- src/core/bit_api.js | 43 ++-- src/pipeline/browser_lifecycle.js | 4 +- src/routes/operations.js | 45 +++- src/services/task_browser_lifecycle.js | 238 ++++++++++++++++++ src/utils/concurrent_runner.js | 11 +- src/workers/task_runner.js | 212 +++++++--------- tests/bit_api_open_concurrency.test.js | 12 +- tests/concurrent_runner_resilience.test.js | 20 ++ tests/google_account_ag_feature.test.js | 19 +- tests/import_browser_batch_service.test.js | 10 +- .../staging_restore_browser_creation.test.js | 17 +- tests/task_browser_lifecycle.test.js | 91 +++++++ 15 files changed, 577 insertions(+), 226 deletions(-) create mode 100644 src/services/task_browser_lifecycle.js create mode 100644 tests/task_browser_lifecycle.test.js diff --git a/README.md b/README.md index 7540074..262f7a1 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,8 @@ node server.js > 浏览器自动化功能依赖本机运行的「比特浏览器」(本地接口 `127.0.0.1:54345`)。服务器本身不需要它即可启动,但执行"打开浏览器"等任务前必须先启动比特浏览器,否则日志会出现 `ECONNREFUSED 127.0.0.1:54345`。 +账号导入和暂存恢复只写入数据库,不预创建比特浏览器窗口。执行登录、改密、获取凭证、打开浏览器或打开网址等浏览器任务时,系统会为当前邮箱创建或复用临时比特窗口并同步代理;单账号任务结束后立即关闭、删除窗口并清空本地浏览器编号,然后再处理下一个邮箱。 + ## 主要依赖 | 包 | 用途 | diff --git a/public/app.js b/public/app.js index 104ef3b..033a3c3 100644 --- a/public/app.js +++ b/public/app.js @@ -177,7 +177,6 @@ function geminiApp() { inlineEditRechargeStatusEmail: null, inlineEditAccountRefundEmail: null, inlineEditRefundProcessEmail: null, - importAutoSetup: true, exportFields: { email: true, password: true, recovery_email: true, secret_key: true, country: false, sheerid_link: false, status: false, message: false, customer_name: false, @@ -1316,17 +1315,8 @@ function geminiApp() { this.accountPage = 1; await this.loadAccounts(); - // 自动初始化:测速 → 创建浏览器 → 设置代理 - if (this.importAutoSetup && importedEmails.length > 0) { - const importedEmailSet = new Set(importedEmails); - const setupAccounts = this.accounts.filter(a => importedEmailSet.has(a.email)); - if (setupAccounts.length > 0) { - await new Promise(resolve => { - if (typeof requestAnimationFrame === 'function') requestAnimationFrame(() => resolve()); - else setTimeout(resolve, 0); - }); - await this._runImportSetup(setupAccounts); - } + if (importedEmails.length > 0) { + this.addLog('账号已入库;执行具体任务时会自动创建临时比特浏览器,任务结束后自动删除', 'info'); } } else { this.addLog(`导入失败: ${data.msg}`, 'error'); @@ -1336,44 +1326,6 @@ function geminiApp() { } }, - async _runImportSetup(accounts) { - if (this.isRunning) { - this.addLog('⚠️ 有任务正在运行,跳过自动初始化', 'warn'); - return; - } - // 大批量任务默认收起日志,避免数百条日志同时参与 DOM 更新。 - this.logDrawerOpen = accounts.length <= 200; - this.clearLogs(); - this.addLog(`🚀 开始初始化 ${accounts.length} 个账号(测速 / 创建浏览器 / 设置代理)...`, 'info'); - try { - const res = await fetch('/api/operations/run', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - taskType: 'import_setup', - accounts, - params: { threadCount: parseInt(this.threadCount) }, - }), - }); - const data = await res.json(); - if (!data.success) { - this.addLog(`❌ 启动失败: ${data.msg}`, 'error'); - return; - } - this.currentTaskId = data.taskId; - this._rememberTaskBatch('import_setup', accounts, data.taskId); - this._activeTaskType = 'import_setup'; - this._setActiveTaskEmails(this._lastTaskEmails); - this._activeTaskStartedAt = this._lastTaskStartedAt; - this.isRunning = true; - this.isPaused = false; - this._rebuildDashboardStats(); - this.startSSEListener(data.taskId); - } catch (e) { - this.addLog(`❌ 网络错误: ${e.message}`, 'error'); - } - }, - async deleteSelectedAccounts() { if (this.selectedEmails.size === 0) return; if (this.isDeletingAccounts) { @@ -1564,18 +1516,8 @@ function geminiApp() { this.stagedBatchDetail = null; await Promise.all([this.loadStagingBatches(), this.loadAccounts()]); const restoredAccounts = Array.isArray(data.accounts) ? data.accounts : []; - if (restoredAccounts.length === 0) { - this.addLog('⚠️ 账号已恢复,但没有取得创建窗口所需的账号数据', 'warn'); - return; - } - this.addLog(`正在为恢复的 ${restoredAccounts.length} 个账号自动创建比特浏览器窗口`, 'info'); - const started = await this.runTask( - 'create_accounts', - { reuseExistingBrowsers: true }, - restoredAccounts, - ); - if (!started) { - this.addLog('⚠️ 账号已回到主列表,但自动创建窗口任务启动失败,可勾选“刚刚运行”后点击创建浏览器重试', 'warn'); + if (restoredAccounts.length > 0) { + this.addLog('恢复完成;执行具体任务时会自动创建临时比特浏览器', 'info'); } } catch (e) { this.addLog(`恢复失败: ${e.message}`, 'error'); @@ -2947,7 +2889,6 @@ function geminiApp() { open: '等待打开浏览器...', open_url: '等待打开网页...', delete: '等待删除浏览器...', - import_setup: '等待初始化...', custom_pipeline: '等待组合任务...', }; return messages[taskType] || '等待处理...'; @@ -2972,7 +2913,6 @@ function geminiApp() { ag_get_credential: '获取凭证', aistudio_combo: 'AI Studio 一键组合', aistudio_sync_key: '同步人工AI Key', gemini_cli_get_credential: '获取Cli凭证', ag_revoke_authorization: '取消授权', google_account_ag_credential: '链接提取+获取凭证', open: '打开浏览器', open_manual_aistudio: '打开浏览器(自动保存人工 Key)', open_url: '打开网页', delete: '删除浏览器', - import_setup: '账号初始化', }; return labels[taskType] || taskType || '任务'; }, @@ -3429,7 +3369,6 @@ function geminiApp() { }, // 各操作快捷方法 - runCreateAccounts() { this.runTask('create_accounts'); }, runChangeProxy() { this.runTask('change_proxy'); }, runOpenBrowsers() { this.runTask('open_manual_aistudio', { watchTimeoutMs: 30 * 60 * 1000 }); diff --git a/public/index.html b/public/index.html index af70252..4e4c44e 100644 --- a/public/index.html +++ b/public/index.html @@ -204,7 +204,6 @@
操作 - @@ -2082,6 +2081,9 @@ 跳过重复邮箱(已有账号不做任何修改) +
+ 导入只保存账号;执行具体任务时才创建临时比特浏览器窗口,单个账号处理结束后自动删除。 +