"use strict"; /** * 发布用 Puppeteer 浏览器(按平台/账号隔离 userDataDir) */ const fs = require("fs"); const path = require("path"); const os = require("os"); const { COMMON_BROWSER_ARGS, BROWSER_IGNORE_DEFAULT_ARGS, STEALTH_INIT_SCRIPT, DEFAULT_USER_AGENT, } = require("./douyin_browser_constants.js"); const browsers = new Map(); function getRuntimeDataPath(...parts) { const base = process.env.AICLIENT_DATA_DIR || path.join(os.homedir(), ".aiclient"); return path.join(base, ...parts); } function getChromiumExecutablePath() { const fromEnv = process.env.AICLIENT_CHROMIUM_PATH || process.env.PUPPETEER_EXECUTABLE_PATH; if (fromEnv && fs.existsSync(fromEnv)) return fromEnv; const candidates = []; if (process.platform === "win32") { const pf = process.env.ProgramFiles || "C:\\Program Files"; const local = process.env.LOCALAPPDATA || ""; candidates.push( path.join(pf, "Google", "Chrome", "Application", "chrome.exe"), path.join(local, "Google", "Chrome", "Application", "chrome.exe"), path.join(pf, "Microsoft", "Edge", "Application", "msedge.exe"), ); } return candidates.find((p) => p && fs.existsSync(p)); } function loadPuppeteer() { try { return require("puppeteer-core"); } catch { return require("puppeteer"); } } function contextKey(platform, accountId) { return accountId ? `publish_${platform}_${accountId}` : `publish_${platform}`; } function userDataDir(platform, accountId) { const sub = accountId ? `${platform}_${accountId}` : platform; return getRuntimeDataPath("browser-data", "publish", sub); } function delay(ms) { return new Promise((r) => setTimeout(r, ms)); } async function getPublishBrowser(platform, accountId) { const key = contextKey(platform, accountId); const existing = browsers.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 }); 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, ignoreDefaultArgs: BROWSER_IGNORE_DEFAULT_ARGS, defaultViewport: { width: 1280, height: 900 }, }); browser.on("disconnected", () => browsers.delete(key)); browsers.set(key, browser); return browser; } async function newPublishPage(platform, accountId, cookies) { const browser = await getPublishBrowser(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); } } return page; } const LOGIN_URLS = { douyin: "https://creator.douyin.com/", kuaishou: "https://cp.kuaishou.com/", shipin: "https://channels.weixin.qq.com/", xiaohongshu: "https://creator.xiaohongshu.com/", }; module.exports = { delay, getPublishBrowser, newPublishPage, userDataDir, LOGIN_URLS, getChromiumExecutablePath, };