92 lines
4.1 KiB
JavaScript
92 lines
4.1 KiB
JavaScript
/**
|
|
* refresh-cookies.mjs — 성인인증 계정 쿠키(ytcookie.txt) 재발급 스크립트
|
|
*
|
|
* 쿠키가 만료되면(19금 재생만 막히고 일반 재생은 계속 됨) 이 스크립트로 새 쿠키를 뽑는다.
|
|
* Chromium을 띄워 구글 로그인 → youtube.com 쿠키를 Netscape 형식으로 저장한다.
|
|
*
|
|
* 사용 전: npm i -D playwright (그리고 최초 1회) npx playwright install chromium
|
|
*
|
|
* 실행 예:
|
|
* GOOGLE_EMAIL=tmdgks040466@gmail.com GOOGLE_PASSWORD='...' \
|
|
* OUT=/root/bot/db/ytcookie.txt node scripts/refresh-cookies.mjs
|
|
*
|
|
* 환경변수:
|
|
* GOOGLE_EMAIL / GOOGLE_PASSWORD : 자동 로그인 시도용(생략 가능 — 그러면 수동 로그인)
|
|
* OUT : 저장 경로 (기본 ./ytcookie.txt). 운영은 /root/bot/db/ytcookie.txt
|
|
* HEADLESS : "1"이면 창 없이(자동 로그인 성공 시에만 권장). 기본은 창 표시(수동 로그인 가능)
|
|
*
|
|
* 구글이 자동 로그인을 막으면(2차인증/캡차/"안전하지 않은 브라우저") 뜬 창에서 직접 로그인하면 된다.
|
|
* 스크립트는 로그인 세션 쿠키(SID)가 잡힐 때까지 최대 5분 기다린 뒤 저장한다.
|
|
*/
|
|
import { chromium } from "playwright";
|
|
import { writeFileSync } from "node:fs";
|
|
|
|
const EMAIL = process.env.GOOGLE_EMAIL;
|
|
const PASSWORD = process.env.GOOGLE_PASSWORD;
|
|
const OUT = process.env.OUT || "./ytcookie.txt";
|
|
const HEADLESS = process.env.HEADLESS === "1";
|
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
|
|
// Playwright 쿠키 배열 -> Netscape cookies.txt (yt-dlp/youtubei.js 호환)
|
|
function toNetscape(cookies) {
|
|
const lines = ["# Netscape HTTP Cookie File", "# music_bot_v2 refresh-cookies.mjs"];
|
|
for (const c of cookies) {
|
|
if (!/(^|\.)youtube\.com$|(^|\.)google\.com$/.test(c.domain)) continue;
|
|
const domain = c.domain.startsWith(".") ? c.domain : "." + c.domain;
|
|
const expires = c.expires && c.expires > 0 ? Math.floor(c.expires) : 2000000000;
|
|
lines.push([
|
|
domain, "TRUE", c.path || "/", c.secure ? "TRUE" : "FALSE",
|
|
expires, c.name, c.value,
|
|
].join("\t"));
|
|
}
|
|
return lines.join("\n") + "\n";
|
|
}
|
|
|
|
async function tryAutoLogin(page) {
|
|
if (!EMAIL || !PASSWORD) return;
|
|
try {
|
|
await page.goto("https://accounts.google.com/ServiceLogin?continue=https://www.youtube.com/", { waitUntil: "domcontentloaded" });
|
|
await page.fill('input[type="email"]', EMAIL, { timeout: 15000 });
|
|
await page.click('#identifierNext, button:has-text("다음"), button:has-text("Next")');
|
|
await page.waitForTimeout(2500);
|
|
await page.fill('input[type="password"]', PASSWORD, { timeout: 15000 });
|
|
await page.click('#passwordNext, button:has-text("다음"), button:has-text("Next")');
|
|
await page.waitForTimeout(3000);
|
|
} catch (e) {
|
|
console.log("[auto-login] 자동 로그인 중단(수동 로그인으로 진행):", String(e).slice(0, 100));
|
|
}
|
|
}
|
|
|
|
async function waitForLogin(context, page, maxMs = 5 * 60 * 1000) {
|
|
const start = Date.now();
|
|
while (Date.now() - start < maxMs) {
|
|
const cookies = await context.cookies("https://www.youtube.com");
|
|
if (cookies.some((c) => c.name === "SID") && cookies.some((c) => c.name === "LOGIN_INFO")) {
|
|
return cookies;
|
|
}
|
|
await sleep(3000);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
(async () => {
|
|
const browser = await chromium.launch({ headless: HEADLESS });
|
|
const context = await browser.newContext();
|
|
const page = await context.newPage();
|
|
await tryAutoLogin(page);
|
|
// youtube를 한번 열어 로그인 세션 쿠키를 확실히 발급
|
|
try { await page.goto("https://www.youtube.com/", { waitUntil: "domcontentloaded" }); } catch {}
|
|
console.log("로그인 완료를 기다리는 중... (자동 로그인이 막혔으면 뜬 창에서 직접 로그인하세요)");
|
|
const cookies = await waitForLogin(context, page);
|
|
if (!cookies) {
|
|
console.error("❌ 로그인 세션 쿠키(SID/LOGIN_INFO)를 못 잡았습니다. 다시 시도하세요.");
|
|
await browser.close();
|
|
process.exit(1);
|
|
}
|
|
const all = await context.cookies();
|
|
writeFileSync(OUT, toNetscape(all));
|
|
console.log(`✅ 쿠키 저장 완료: ${OUT} (youtube/google 쿠키 ${all.length}개 중 관련 항목)`);
|
|
await browser.close();
|
|
process.exit(0);
|
|
})();
|