文件预览

cookie.mjs

查看 WeRead Import 技能包中的文件内容。

文件内容

src/cookie.mjs

import { chromium } from 'playwright';
import { isBrowserCookieMode, isManagedBrowserMode } from './browser-mode.mjs';

export const WEREAD_COOKIE_URLS = [
  'https://weread.qq.com/',
  'https://weread.qq.com/api/user/notebook',
  'https://weread.qq.com/web/book/bookmarklist?bookId=1',
  'https://weread.qq.com/web/review/list?bookId=1&listType=4&syncKey=0&mine=1',
];

export const CDP_CONNECT_OPTIONS = {
  acceptDownloads: 'internal-browser-default',
};

export function cookieMatchesHost(cookie, host = 'weread.qq.com') {
  const domain = String(cookie?.domain || '').replace(/^\./, '');
  return Boolean(domain) && (host === domain || host.endsWith(`.${domain}`));
}

export function buildCookieHeader(cookies, host = 'weread.qq.com') {
  return (cookies || [])
    .filter((cookie) => cookieMatchesHost(cookie, host) && cookie.name && cookie.value)
    .map((cookie) => `${cookie.name}=${cookie.value}`)
    .join('; ');
}

export function normalizeBrowserCookieError(error, { profileSyncMode = process.env.WEREAD_PROFILE_SYNC_MODE || 'isolated', cookieFrom = process.env.WEREAD_COOKIE_FROM || 'browser-managed' } = {}) {
  if (!isManagedBrowserMode(cookieFrom)) {
    return error;
  }
  const isolatedMode = profileSyncMode === 'isolated';
  if (isolatedMode && /未找到 weread\.qq\.com 的 cookie/.test(String(error?.message || ''))) {
    return new Error('隔离浏览器中尚未登录微信读书。请在自动打开的独立 Chrome 窗口中登录微信读书后再重试。');
  }
  return error;
}

async function closeBrowser(browser, primaryError) {
  if (!browser) return;
  try {
    if (typeof browser.close === 'function') {
      await browser.close();
    }
  } catch (closeError) {
    if (!primaryError) throw closeError;
  }
}

export async function extractCookieFromBrowserWithConnector(cdpUrl, connectOverCDP = chromium.connectOverCDP.bind(chromium)) {
  const browser = await connectOverCDP(cdpUrl, CDP_CONNECT_OPTIONS);
  let primaryError = null;
  try {
    const context = browser.contexts()[0];
    if (!context) throw new Error('无可用浏览器上下文,请确认已启动带远程调试的 Chrome');
    const cookieHeader = buildCookieHeader(await context.cookies(...WEREAD_COOKIE_URLS));
    if (!cookieHeader) throw new Error('浏览器中未找到 weread.qq.com 的 cookie,请先在该浏览器中登录微信读书');
    return cookieHeader;
  } catch (error) {
    primaryError = error;
    throw error;
  } finally {
    await closeBrowser(browser, primaryError);
  }
}

export async function extractCookieFromBrowser(cdpUrl) {
  return extractCookieFromBrowserWithConnector(cdpUrl);
}

export async function getCookieForApi(args) {
  if (args.cookie) return args.cookie;
  if (isBrowserCookieMode(args.cookieFrom)) {
    try {
      return extractCookieFromBrowser(args.cdp);
    } catch (error) {
      throw normalizeBrowserCookieError(error, { cookieFrom: args.cookieFrom });
    }
  }
  throw new Error('API 模式需要 cookie,请通过 --cookie、WEREAD_COOKIE 或 --cookie-from browser-live/browser-managed 提供');
}