feat(youtube): youtube çerez yönetimi ekle

YouTube cookies.txt dosyasını yönetmek için ayarlar arayüzü ve API uç noktaları eklendi.
- Kullanıcı arayüzünde çerez yükleme/kaydetme fonksiyonalitesi
- Cookies.txt dosyası için GET/POST API uç noktaları
- YouTube indirme işlemlerinde çerez desteği
- Çerez dosyası boyutu ve karakter validasyonu
- Ayarlar sayfasında sekme tabanlı arayüz
This commit is contained in:
2025-12-14 15:33:56 +03:00
parent de97b49dfa
commit 2f58ef5ef9
2 changed files with 376 additions and 8 deletions

View File

@@ -72,6 +72,10 @@ const generatingThumbnails = new Set();
const INFO_FILENAME = "info.json";
const YT_ID_REGEX = /^[A-Za-z0-9_-]{11}$/;
const YT_DLP_BIN = process.env.YT_DLP_BIN || null;
const YT_COOKIES_PATH =
process.env.YT_DLP_COOKIES ||
process.env.YT_DLP_COOKIE_FILE ||
path.join(CACHE_DIR, "yt_cookies.txt");
let resolvedYtDlpBinary = null;
const TMDB_API_KEY = process.env.TMDB_API_KEY;
const TMDB_BASE_URL = "https://api.themoviedb.org/3";
@@ -734,10 +738,22 @@ function appendYoutubeLog(job, line) {
function launchYoutubeJob(job) {
const binary = getYtDlpBinary();
const jsRuntime =
const jsRuntimeValue =
process.env.YT_DLP_JS_RUNTIME ||
process.env.NODE_BIN ||
"/usr/bin/node";
let jsRuntimeArg = jsRuntimeValue;
if (jsRuntimeValue && jsRuntimeValue.includes("=")) {
jsRuntimeArg = jsRuntimeValue;
} else if (jsRuntimeValue && jsRuntimeValue.includes(path.sep)) {
// Eğer yol verilmişse node=<path> formatına çevir
jsRuntimeArg = `node=${jsRuntimeValue}`;
}
const cookieFile =
(YT_COOKIES_PATH && fs.existsSync(YT_COOKIES_PATH) && YT_COOKIES_PATH) ||
null;
const args = [
"-f",
"bv+ba/b",
@@ -746,10 +762,13 @@ function launchYoutubeJob(job) {
"jpg",
"--write-info-json",
"--js-runtime",
jsRuntime,
jsRuntimeArg,
...(cookieFile && fs.existsSync(cookieFile)
? ["--cookies", cookieFile]
: []),
job.url
];
job.debug = { binary, args, logs: [] };
job.debug = { binary, args, logs: [], jsRuntime: jsRuntimeArg, cookies: cookieFile };
const child = spawn(binary, args, {
cwd: job.savePath,
env: process.env
@@ -5852,6 +5871,94 @@ app.post("/api/youtube/download", requireAuth, async (req, res) => {
}
});
// --- 🎫 YouTube cookies yönetimi ---
app.get("/api/youtube/cookies", requireAuth, (req, res) => {
try {
if (!YT_COOKIES_PATH || !fs.existsSync(YT_COOKIES_PATH)) {
return res.json({ hasCookies: false, cookies: null, updatedAt: null });
}
const stat = fs.statSync(YT_COOKIES_PATH);
const size = stat.size;
if (size > 20000) {
return res.json({ hasCookies: true, cookies: "", updatedAt: stat.mtimeMs });
}
const content = fs.readFileSync(YT_COOKIES_PATH, "utf-8");
res.json({ hasCookies: true, cookies: content, updatedAt: stat.mtimeMs });
} catch (err) {
console.warn("⚠️ YouTube cookies okunamadı:", err.message);
res.status(500).json({ error: "Cookies okunamadı" });
}
});
app.post("/api/youtube/cookies", requireAuth, (req, res) => {
try {
let cookies = req.body?.cookies;
if (typeof cookies !== "string") {
return res.status(400).json({ error: "cookies alanı metin olmalı" });
}
cookies = cookies.replace(/\r\n/g, "\n");
if (cookies.length > 20000) {
return res.status(400).json({ error: "Cookie içeriği çok büyük (20KB sınırı)." });
}
if (/[^\x09\x0a\x0d\x20-\x7e]/.test(cookies)) {
return res.status(400).json({ error: "Cookie içeriğinde desteklenmeyen karakterler var." });
}
if (!YT_COOKIES_PATH) {
return res.status(500).json({ error: "Cookie yolu tanımlı değil." });
}
ensureDirForFile(YT_COOKIES_PATH);
fs.writeFileSync(YT_COOKIES_PATH, cookies, "utf-8");
res.json({ ok: true, updatedAt: Date.now() });
} catch (err) {
console.error("❌ YouTube cookies yazılamadı:", err.message);
res.status(500).json({ error: "Cookies kaydedilemedi" });
}
});
// --- 🎫 YouTube cookies yönetimi ---
app.get("/api/youtube/cookies", requireAuth, (req, res) => {
try {
if (!YT_COOKIES_PATH || !fs.existsSync(YT_COOKIES_PATH)) {
return res.json({ hasCookies: false, cookies: null, updatedAt: null });
}
const stat = fs.statSync(YT_COOKIES_PATH);
const size = stat.size;
if (size > 20000) {
return res.json({ hasCookies: true, cookies: "", updatedAt: stat.mtimeMs });
}
const content = fs.readFileSync(YT_COOKIES_PATH, "utf-8");
res.json({ hasCookies: true, cookies: content, updatedAt: stat.mtimeMs });
} catch (err) {
console.warn("⚠️ YouTube cookies okunamadı:", err.message);
res.status(500).json({ error: "Cookies okunamadı" });
}
});
app.post("/api/youtube/cookies", requireAuth, (req, res) => {
try {
let cookies = req.body?.cookies;
if (typeof cookies !== "string") {
return res.status(400).json({ error: "cookies alanı metin olmalı" });
}
cookies = cookies.replace(/\r\n/g, "\n");
if (cookies.length > 20000) {
return res.status(400).json({ error: "Cookie içeriği çok büyük (20KB sınırı)." });
}
if (/[^\x09\x0a\x0d\x20-\x7e]/.test(cookies)) {
return res.status(400).json({ error: "Cookie içeriğinde desteklenmeyen karakterler var." });
}
if (!YT_COOKIES_PATH) {
return res.status(500).json({ error: "Cookie yolu tanımlı değil." });
}
ensureDirForFile(YT_COOKIES_PATH);
fs.writeFileSync(YT_COOKIES_PATH, cookies, "utf-8");
res.json({ ok: true, updatedAt: Date.now() });
} catch (err) {
console.error("❌ YouTube cookies yazılamadı:", err.message);
res.status(500).json({ error: "Cookies kaydedilemedi" });
}
});
// --- 📺 TV dizileri listesi ---
app.get("/api/tvshows", requireAuth, (req, res) => {
try {