1
This commit is contained in:
@@ -19,6 +19,8 @@ const {
|
||||
} = require("./douyin_browser_constants.js");
|
||||
|
||||
const browsers = new Map();
|
||||
/** 扫码登录 / 打开账号:需可见窗口,使用 puppeteer.launch(Node 等待登录期间保持存活) */
|
||||
const loginBrowsers = new Map();
|
||||
|
||||
function getRuntimeDataPath(...parts) {
|
||||
const base = process.env.AICLIENT_DATA_DIR || path.join(os.homedir(), ".aiclient");
|
||||
@@ -38,7 +40,7 @@ function getChromiumExecutablePath() {
|
||||
path.join(pf, "Google", "Chrome", "Application", "chrome.exe"),
|
||||
path.join(local, "Google", "Chrome", "Application", "chrome.exe"),
|
||||
path.join(pf, "Microsoft", "Edge", "Application", "msedge.exe"),
|
||||
path.join(administrator_appdata, "Google", "Chrome", "bin","chrome.exe"),
|
||||
// path.join(administrator_appdata, "Google", "Chrome", "bin","chrome.exe"),
|
||||
);
|
||||
}
|
||||
return candidates.find((p) => p && fs.existsSync(p));
|
||||
@@ -145,6 +147,61 @@ async function connectPublishBrowser(puppeteer, port) {
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupProfileLocks(dir) {
|
||||
for (const name of [
|
||||
"SingletonLock",
|
||||
"SingletonSocket",
|
||||
"SingletonCookie",
|
||||
"Lock",
|
||||
]) {
|
||||
try {
|
||||
const p = path.join(dir, name);
|
||||
if (fs.existsSync(p)) fs.unlinkSync(p);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码登录专用:可见 Chrome(对齐 Electron launchPersistentContext headless:false)
|
||||
*/
|
||||
async function getLoginBrowser(platform, accountId) {
|
||||
const key = `login_${contextKey(platform, accountId)}`;
|
||||
const existing = loginBrowsers.get(key);
|
||||
if (existing && existing.isConnected()) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
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,请安装浏览器或设置 AICLIENT_CHROMIUM_PATH",
|
||||
);
|
||||
}
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
executablePath,
|
||||
headless: false,
|
||||
userDataDir: dir,
|
||||
args: [...COMMON_BROWSER_ARGS, "--start-maximized"],
|
||||
ignoreDefaultArgs: BROWSER_IGNORE_DEFAULT_ARGS,
|
||||
defaultViewport: { width: 1280, height: 900 },
|
||||
handleSIGINT: false,
|
||||
handleSIGTERM: false,
|
||||
handleSIGHUP: false,
|
||||
});
|
||||
|
||||
browser.on("disconnected", () => loginBrowsers.delete(key));
|
||||
loginBrowsers.set(key, browser);
|
||||
return browser;
|
||||
}
|
||||
|
||||
async function getPublishBrowser(platform, accountId) {
|
||||
const key = contextKey(platform, accountId);
|
||||
const existing = browsers.get(key);
|
||||
@@ -194,6 +251,57 @@ async function closeBlankPages(browser, keepPage) {
|
||||
}
|
||||
}
|
||||
|
||||
async function newLoginPage(platform, accountId, cookies = []) {
|
||||
const browser = await getLoginBrowser(platform, accountId);
|
||||
const page = await browser.newPage();
|
||||
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);
|
||||
}
|
||||
}
|
||||
try {
|
||||
await page.bringToFront();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
async function closeLoginBrowser(platform, accountId) {
|
||||
const key = `login_${contextKey(platform, accountId)}`;
|
||||
const browser = loginBrowsers.get(key);
|
||||
if (!browser) return;
|
||||
loginBrowsers.delete(key);
|
||||
try {
|
||||
await browser.close();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开账号页后保留窗口(disconnect,避免 Node 退出时关窗)
|
||||
*/
|
||||
async function detachLoginBrowser(platform, accountId) {
|
||||
const key = `login_${contextKey(platform, accountId)}`;
|
||||
const browser = loginBrowsers.get(key);
|
||||
if (!browser) return;
|
||||
loginBrowsers.delete(key);
|
||||
try {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
async function newPublishPage(platform, accountId, cookies) {
|
||||
const browser = await getPublishBrowser(platform, accountId);
|
||||
const pages = await browser.pages();
|
||||
@@ -267,11 +375,15 @@ const LOGIN_URLS = {
|
||||
module.exports = {
|
||||
delay,
|
||||
getPublishBrowser,
|
||||
getLoginBrowser,
|
||||
newPublishPage,
|
||||
newLoginPage,
|
||||
userDataDir,
|
||||
LOGIN_URLS,
|
||||
getChromiumExecutablePath,
|
||||
closePublishBrowser,
|
||||
closeLoginBrowser,
|
||||
detachLoginBrowser,
|
||||
detachPublishBrowser,
|
||||
debugPortForKey,
|
||||
contextKey,
|
||||
|
||||
Reference in New Issue
Block a user