| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- import { initDatabase, PlatformAccount } from '../models/index.js';
- import { logger } from '../utils/logger.js';
- import { BrowserManager } from '../automation/browser.js';
- import fs from 'node:fs/promises';
- import path from 'node:path';
- type PlaywrightCookie = {
- name: string;
- value: string;
- domain?: string;
- path?: string;
- url?: string;
- expires?: number;
- httpOnly?: boolean;
- secure?: boolean;
- sameSite?: 'Lax' | 'None' | 'Strict';
- };
- function parseCookiesFromAccount(cookieData: string | null): PlaywrightCookie[] {
- if (!cookieData) return [];
- const raw = cookieData.trim();
- if (!raw) return [];
- // 1) JSON array / 对象
- if (raw.startsWith('[') || raw.startsWith('{')) {
- try {
- const parsed = JSON.parse(raw);
- const arr = Array.isArray(parsed) ? parsed : (parsed?.cookies ? parsed.cookies : []);
- if (!Array.isArray(arr)) return [];
- return arr
- .map((c: any) => {
- const name = String(c?.name ?? '').trim();
- const value = String(c?.value ?? '').trim();
- if (!name) return null;
- const domain = c?.domain ? String(c.domain) : undefined;
- const pathVal = c?.path ? String(c.path) : '/';
- const url = !domain ? 'https://channels.weixin.qq.com' : undefined;
- const sameSiteRaw = c?.sameSite;
- const sameSite =
- sameSiteRaw === 'Lax' || sameSiteRaw === 'None' || sameSiteRaw === 'Strict'
- ? sameSiteRaw
- : undefined;
- return {
- name,
- value,
- domain,
- path: pathVal,
- url,
- expires: typeof c?.expires === 'number' ? c.expires : undefined,
- httpOnly: typeof c?.httpOnly === 'boolean' ? c.httpOnly : undefined,
- secure: typeof c?.secure === 'boolean' ? c.secure : undefined,
- sameSite,
- } satisfies PlaywrightCookie;
- })
- .filter(Boolean) as PlaywrightCookie[];
- } catch {
- // fallthrough
- }
- }
- // 2) "a=b; c=d" 拼接
- const pairs = raw.split(';').map((p) => p.trim()).filter(Boolean);
- const cookies: PlaywrightCookie[] = [];
- for (const p of pairs) {
- const idx = p.indexOf('=');
- if (idx <= 0) continue;
- const name = p.slice(0, idx).trim();
- const value = p.slice(idx + 1).trim();
- if (!name) continue;
- cookies.push({ name, value, url: 'https://channels.weixin.qq.com' });
- }
- return cookies;
- }
- async function main() {
- try {
- await initDatabase();
- const accountRepository = (await import('../models/index.js')).AppDataSource.getRepository(
- PlatformAccount
- );
- const accountName = '嗯麦威欧洲古董';
- const account = await accountRepository.findOne({
- where: {
- platform: 'weixin_video' as any,
- accountName,
- },
- });
- if (!account) {
- logger.error(`[WX Video] Account not found for name=${accountName}`);
- process.exit(1);
- return;
- }
- const cookies = parseCookiesFromAccount(account.cookieData);
- if (!cookies.length) {
- logger.error('[WX Video] cookieData 为空或无法解析,无法带登录态打开页面');
- process.exit(1);
- return;
- }
- logger.info(
- `[WX Video] Opening with account. id=${account.id} name=${account.accountName ?? ''}`
- );
- const browser = await BrowserManager.getBrowser({ headless: false });
- const context = await browser.newContext({
- viewport: { width: 1920, height: 1080 },
- locale: 'zh-CN',
- timezoneId: 'Asia/Shanghai',
- });
- await context.addCookies(cookies as any);
- const page = await context.newPage();
- const url = 'https://channels.weixin.qq.com/platform';
- logger.info(`[WX Video] Opening page with cookies: ${url}`);
- await page.goto(url, { waitUntil: 'domcontentloaded' });
- logger.info('[WX Video] Page opened with account cookies. 你可以在浏览器里操作该账号。');
- // 等页面真正进入平台(避免太早保存到“登录页”的 storageState)
- await page
- .waitForFunction(() => {
- const t = document.body?.innerText || '';
- return t.includes('数据中心') || t.includes('视频数据') || t.includes('关注者数据');
- }, { timeout: 60_000 })
- .catch(() => undefined);
- // 保存 storageState,供后台 headless 同步复用(避免 cookie-only 在 headless 下跳登录)
- const stateDir = path.resolve(process.cwd(), 'tmp', 'weixin-video-storage-state');
- await fs.mkdir(stateDir, { recursive: true });
- const statePath = path.join(stateDir, `${account.id}.json`);
- await context.storageState({ path: statePath });
- logger.info(`[WX Video] storageState saved: ${statePath}`);
- // 不主动关闭浏览器,方便你手动操作
- } catch (e) {
- logger.error('[WX Video] Failed to open page with account:', e);
- process.exit(1);
- }
- }
- void main();
|