From 0b93813b680693b83db243b690855259e433323d Mon Sep 17 00:00:00 2001 From: "949036910@qq.com" <> Date: Wed, 3 Jun 2026 22:12:20 +0800 Subject: [PATCH] 11 --- scripts/nodejs/publish_browser.js | 114 +++++++++++++++++++++++++++++- scripts/nodejs/publish_open.js | 7 +- 2 files changed, 118 insertions(+), 3 deletions(-) diff --git a/scripts/nodejs/publish_browser.js b/scripts/nodejs/publish_browser.js index 19f1880..389645b 100644 --- a/scripts/nodejs/publish_browser.js +++ b/scripts/nodejs/publish_browser.js @@ -352,6 +352,110 @@ async function newLoginPage(platform, accountId, cookies = [], startUrl) { return page; } +/** + * 打开账号页:detached Chrome + connect,脚本结束后可保留窗口 + * @param {string} [startUrl] + */ +async function newLoginPageKeepOpen(platform, accountId, cookies = [], startUrl) { + const key = `login_${contextKey(platform, accountId)}`; + const existing = loginBrowsers.get(key); + if (existing && existing.isConnected()) { + const pages = await existing.pages(); + let page = + pages.find((p) => { + try { + const u = p.url(); + return u && u !== "about:blank" && u !== "chrome://newtab/"; + } catch { + return false; + } + }) || pages[0]; + if (page) { + await bringPageToFront(page); + if (startUrl) { + try { + const cur = page.url(); + if (!cur || cur === "about:blank" || !cur.includes("://")) { + await page.goto(startUrl, { + waitUntil: "domcontentloaded", + timeout: 60000, + }); + } + } catch { + /* ignore */ + } + } + return page; + } + } + + const publishKey = contextKey(platform, accountId); + const publishPort = debugPortForKey(publishKey); + const loginPort = debugPortForKey(key); + await closeLoginBrowser(platform, accountId); + await closePublishBrowser(platform, accountId); + await forceCloseChromeOnPort(loginPort); + await forceCloseChromeOnPort(publishPort); + + const puppeteer = loadPuppeteer(); + const dir = userDataDir(platform, accountId); + if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + cleanupProfileLocks(dir); + + const executablePath = getChromiumExecutablePath(); + if (!executablePath) { + throw new Error( + "未找到 Chrome/Edge,请安装 Google Chrome 或 Microsoft Edge,或设置 AICLIENT_CHROMIUM_PATH", + ); + } + + const openUrl = + startUrl && String(startUrl).trim() ? String(startUrl).trim() : "about:blank"; + + globalThis.__native?.emitProgress?.("正在打开 Chrome…"); + await spawnDetachedChrome(executablePath, dir, loginPort, openUrl, { force: true }); + const browser = await connectPublishBrowser(puppeteer, loginPort); + browser.on("disconnected", () => loginBrowsers.delete(key)); + loginBrowsers.set(key, browser); + + const pages = await browser.pages(); + let page = + pages.find((p) => { + try { + const u = p.url(); + return u && u !== "about:blank" && u !== "chrome://newtab/"; + } catch { + return false; + } + }) || pages[0] || null; + + if (!page) { + page = await browser.newPage(); + if (startUrl) { + await page.goto(startUrl, { + waitUntil: "domcontentloaded", + timeout: 60000, + }); + } + } + + await page.setUserAgent(DEFAULT_USER_AGENT); + await page.evaluateOnNewDocument(STEALTH_INIT_SCRIPT); + page.setDefaultNavigationTimeout(60000); + page.setDefaultTimeout(60000); + + if (Array.isArray(cookies) && cookies.length) { + try { + await page.setCookie(...cookies); + } catch (e) { + console.warn("setCookie 失败:", e.message); + } + } + + await bringPageToFront(page); + return page; +} + async function closeLoginBrowser(platform, accountId) { const key = `login_${contextKey(platform, accountId)}`; const port = debugPortForKey(key); @@ -381,9 +485,15 @@ async function detachLoginBrowser(platform, accountId) { if (!browser) return; loginBrowsers.delete(key); try { + if (!browser.isConnected()) return; + // puppeteer.connect:disconnect 后 Chrome 独立进程继续运行 + if (typeof browser.disconnect === "function") { + await browser.disconnect(); + return; + } + // puppeteer.launch:仅 unref 子进程,勿 close/disconnect const proc = typeof browser.process === "function" ? browser.process() : null; if (proc && typeof proc.unref === "function") proc.unref(); - if (browser.isConnected()) await browser.disconnect(); } catch (e) { console.warn("detachLoginBrowser:", e.message); } @@ -465,6 +575,7 @@ module.exports = { getLoginBrowser, newPublishPage, newLoginPage, + newLoginPageKeepOpen, userDataDir, LOGIN_URLS, getChromiumExecutablePath, @@ -472,6 +583,7 @@ module.exports = { closeLoginBrowser, detachLoginBrowser, detachPublishBrowser, + bringPageToFront, debugPortForKey, contextKey, }; diff --git a/scripts/nodejs/publish_open.js b/scripts/nodejs/publish_open.js index a3ab912..93142fd 100644 --- a/scripts/nodejs/publish_open.js +++ b/scripts/nodejs/publish_open.js @@ -1,8 +1,9 @@ "use strict"; const { - newLoginPage, + newLoginPageKeepOpen, detachLoginBrowser, + bringPageToFront, LOGIN_URLS, } = require("./publish_browser.js"); @@ -25,11 +26,13 @@ globalThis.__nodejsMain = async function main(params) { } globalThis.__native?.emitProgress?.("正在打开浏览器…"); - const page = await newLoginPage(platform, accountId, cookies, targetUrl); + const page = await newLoginPageKeepOpen(platform, accountId, cookies, targetUrl); const cur = page.url(); if (!cur || cur === "about:blank" || !cur.includes("://")) { await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 60000 }); } + await bringPageToFront(page); + // 断开 Puppeteer,保留 detached Chrome 窗口(Node 退出后不关浏览器) await detachLoginBrowser(platform, accountId); return {