import { chromium, type BrowserContext } from 'playwright' // A simple singleton manager for a persistent Chromium context with ref-counting. // Prevents concurrent tasks from closing the shared window prematurely. let contextPromise: Promise | null = null let context: BrowserContext | null = null let refCount = 0 let idleCloseTimer: NodeJS.Timeout | null = null const USER_DATA_DIR = 'chrome-profile/douyin' const DEFAULT_OPTIONS = { headless: true } as const async function launchContext(): Promise { const ctx = await chromium.launchPersistentContext(USER_DATA_DIR, DEFAULT_OPTIONS) // When the context is closed externally, reset manager state ctx.on('close', () => { context = null contextPromise = null refCount = 0 if (idleCloseTimer) { clearTimeout(idleCloseTimer) idleCloseTimer = null } }) return ctx } export async function acquireBrowserContext(): Promise { // Cancel any pending idle close if a new consumer arrives if (idleCloseTimer) { clearTimeout(idleCloseTimer) idleCloseTimer = null } if (context) { refCount += 1 return context } if (!contextPromise) { contextPromise = launchContext() } context = await contextPromise refCount += 1 return context } export async function releaseBrowserContext(options?: { idleMillis?: number }): Promise { const idleMillis = options?.idleMillis ?? 15_000 refCount = Math.max(0, refCount - 1) if (refCount > 0 || !context) return // Delay the close to allow bursty workloads to reuse the context if (idleCloseTimer) { clearTimeout(idleCloseTimer) idleCloseTimer = null } idleCloseTimer = setTimeout(async () => { try { if (context && refCount === 0) { await context.close() } } finally { context = null contextPromise = null idleCloseTimer = null } }, idleMillis) }