import { chmodSync, mkdirSync, writeFileSync } from "node:fs"; import { dirname } from "node:path"; import type { Cookie } from "playwright"; function cookieField(value: string): string { return value.replace(/[\t\r\n]/g, ""); } /** Serialize Playwright cookies in the Netscape cookies.txt format used by yt-dlp. */ export function serializeNetscapeCookies(cookies: readonly Cookie[]): string { const lines = ["# Netscape HTTP Cookie File", "# Generated by harn browse. Keep private.", ""]; for (const cookie of [...cookies].sort((a, b) => `${a.domain}\0${a.path}\0${a.name}`.localeCompare(`${b.domain}\0${b.path}\0${b.name}`), )) { const domain = `${cookie.httpOnly ? "#HttpOnly_" : ""}${cookieField(cookie.domain)}`; const includeSubdomains = cookie.domain.startsWith(".") ? "TRUE" : "FALSE"; const secure = cookie.secure ? "TRUE" : "FALSE"; const expires = cookie.expires > 0 ? String(Math.floor(cookie.expires)) : "0"; lines.push( [ domain, includeSubdomains, cookieField(cookie.path || "/"), secure, expires, cookieField(cookie.name), cookieField(cookie.value), ].join("\t"), ); } return `${lines.join("\n")}\n`; } /** Write a credential-bearing cookie file with owner-only permissions. */ export function writeNetscapeCookieFile(path: string, cookies: readonly Cookie[]): void { mkdirSync(dirname(path), { recursive: true }); writeFileSync(path, serializeNetscapeCookies(cookies), { mode: 0o600 }); chmodSync(path, 0o600); }