Add cookie input field in UI for YouTube bot detection bypass
This commit is contained in:
@@ -42,6 +42,28 @@ const streamOnly = process.env.STREAM_ONLY === "true";
|
|||||||
<option value="best">{t(Astro, "downloadForm.formatBest")}</option>
|
<option value="best">{t(Astro, "downloadForm.formatBest")}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="collapse collapse-arrow border border-base-300 bg-base-200">
|
||||||
|
<input type="checkbox" id="cookiesToggle" />
|
||||||
|
<div class="collapse-title text-sm font-medium">
|
||||||
|
{t(Astro, "downloadForm.cookiesLabel")}
|
||||||
|
</div>
|
||||||
|
<div class="collapse-content">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text text-xs"
|
||||||
|
>{t(Astro, "downloadForm.cookiesHelp")}</span
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="cookies"
|
||||||
|
name="cookies"
|
||||||
|
class="textarea textarea-bordered h-32 text-xs font-mono"
|
||||||
|
placeholder={t(Astro, "downloadForm.cookiesPlaceholder")}
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div id="status" class="mt-4 hidden"></div>
|
<div id="status" class="mt-4 hidden"></div>
|
||||||
@@ -102,8 +124,12 @@ const streamOnly = process.env.STREAM_ONLY === "true";
|
|||||||
|
|
||||||
const urlInput = document.getElementById("url") as HTMLInputElement;
|
const urlInput = document.getElementById("url") as HTMLInputElement;
|
||||||
const formatSelect = document.getElementById("format") as HTMLSelectElement;
|
const formatSelect = document.getElementById("format") as HTMLSelectElement;
|
||||||
|
const cookiesInput = document.getElementById(
|
||||||
|
"cookies"
|
||||||
|
) as HTMLTextAreaElement;
|
||||||
const url = urlInput?.value;
|
const url = urlInput?.value;
|
||||||
const format = formatSelect?.value || "mp4";
|
const format = formatSelect?.value || "mp4";
|
||||||
|
const cookies = cookiesInput?.value?.trim() || null;
|
||||||
|
|
||||||
if (!url || !downloadBtn || !status || !loading) return;
|
if (!url || !downloadBtn || !status || !loading) return;
|
||||||
|
|
||||||
@@ -118,7 +144,7 @@ const streamOnly = process.env.STREAM_ONLY === "true";
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"x-format": format,
|
"x-format": format,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ url }),
|
body: JSON.stringify({ url, cookies }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Prüfe ob Response ein Stream ist (Content-Type ist nicht JSON)
|
// Prüfe ob Response ein Stream ist (Content-Type ist nicht JSON)
|
||||||
|
|||||||
@@ -26,7 +26,10 @@
|
|||||||
"downloadSuccessful": "Download erfolgreich!",
|
"downloadSuccessful": "Download erfolgreich!",
|
||||||
"lastFile": "Letzte Datei:",
|
"lastFile": "Letzte Datei:",
|
||||||
"unknownError": "Unbekannter Fehler",
|
"unknownError": "Unbekannter Fehler",
|
||||||
"networkError": "Netzwerkfehler"
|
"networkError": "Netzwerkfehler",
|
||||||
|
"cookiesLabel": "Cookies (optional - für Bot-Erkennung)",
|
||||||
|
"cookiesPlaceholder": "Cookies aus Browser-Erweiterung einfügen (Netscape-Format)",
|
||||||
|
"cookiesHelp": "Cookies helfen bei YouTube Bot-Erkennung. Exportiere sie mit einer Browser-Erweiterung wie 'Get cookies.txt LOCALLY'."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"title": "Heruntergeladene Medien",
|
"title": "Heruntergeladene Medien",
|
||||||
@@ -57,4 +60,3 @@
|
|||||||
"couldNotCreateDirectory": "Konnte Download-Verzeichnis nicht erstellen: {{dir}}. Bitte prüfe die Berechtigungen."
|
"couldNotCreateDirectory": "Konnte Download-Verzeichnis nicht erstellen: {{dir}}. Bitte prüfe die Berechtigungen."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,10 @@
|
|||||||
"downloadSuccessful": "Download successful!",
|
"downloadSuccessful": "Download successful!",
|
||||||
"lastFile": "Last file:",
|
"lastFile": "Last file:",
|
||||||
"unknownError": "Unknown error",
|
"unknownError": "Unknown error",
|
||||||
"networkError": "Network error"
|
"networkError": "Network error",
|
||||||
|
"cookiesLabel": "Cookies (optional - for bot detection)",
|
||||||
|
"cookiesPlaceholder": "Paste cookies from browser extension (Netscape format)",
|
||||||
|
"cookiesHelp": "Cookies help bypass YouTube bot detection. Export them using a browser extension like 'Get cookies.txt LOCALLY'."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"title": "Downloaded Files",
|
"title": "Downloaded Files",
|
||||||
@@ -57,4 +60,3 @@
|
|||||||
"couldNotCreateDirectory": "Could not create download directory: {{dir}}. Please check permissions."
|
"couldNotCreateDirectory": "Could not create download directory: {{dir}}. Please check permissions."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { APIRoute } from "astro";
|
import type { APIRoute } from "astro";
|
||||||
import { getSession, isLoginEnabled } from "../../lib/session";
|
import { getSession, isLoginEnabled } from "../../lib/session";
|
||||||
import { tApi } from "../../lib/i18n";
|
import { tApi } from "../../lib/i18n";
|
||||||
import { mkdir, unlink, readFile, readdir } from "node:fs/promises";
|
import { mkdir, unlink, readFile, readdir, writeFile } from "node:fs/promises";
|
||||||
import { existsSync } from "node:fs";
|
import { existsSync } from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
@@ -26,8 +26,11 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cookie-Unterstützung: Temporäre Datei außerhalb des try-Blocks definieren
|
||||||
|
let tempCookiesFile: string | null = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { url } = await request.json();
|
const { url, cookies } = await request.json();
|
||||||
|
|
||||||
if (!url || typeof url !== "string") {
|
if (!url || typeof url !== "string") {
|
||||||
return new Response(
|
return new Response(
|
||||||
@@ -39,6 +42,20 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cookie-Unterstützung: Wenn Cookies im Request sind, temporäre Datei erstellen
|
||||||
|
if (cookies && typeof cookies === "string" && cookies.trim()) {
|
||||||
|
try {
|
||||||
|
tempCookiesFile = path.join(tmpdir(), `cookies-${Date.now()}.txt`);
|
||||||
|
await writeFile(tempCookiesFile, cookies.trim(), "utf-8");
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
"Fehler beim Erstellen der temporären Cookie-Datei:",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
// Weiter ohne Cookies
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// YouTube URL validieren
|
// YouTube URL validieren
|
||||||
if (!url.includes("youtube.com") && !url.includes("youtu.be")) {
|
if (!url.includes("youtube.com") && !url.includes("youtu.be")) {
|
||||||
return new Response(
|
return new Response(
|
||||||
@@ -57,7 +74,8 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
const format = request.headers.get("x-format") || "mp4";
|
const format = request.headers.get("x-format") || "mp4";
|
||||||
|
|
||||||
// Cookie-Unterstützung für YouTube Bot-Erkennung
|
// Cookie-Unterstützung für YouTube Bot-Erkennung
|
||||||
const cookiesFile = process.env.YT_DLP_COOKIES;
|
// Priorität: 1. Cookies aus Request, 2. Umgebungsvariable, 3. Browser-Cookies
|
||||||
|
const cookiesFile = tempCookiesFile || process.env.YT_DLP_COOKIES;
|
||||||
const cookiesFromBrowser = process.env.YT_DLP_COOKIES_FROM_BROWSER;
|
const cookiesFromBrowser = process.env.YT_DLP_COOKIES_FROM_BROWSER;
|
||||||
|
|
||||||
// JavaScript Runtime für yt-dlp (Standard: deno)
|
// JavaScript Runtime für yt-dlp (Standard: deno)
|
||||||
@@ -312,5 +330,12 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
}),
|
}),
|
||||||
{ status: 500, headers: { "Content-Type": "application/json" } }
|
{ status: 500, headers: { "Content-Type": "application/json" } }
|
||||||
);
|
);
|
||||||
|
} finally {
|
||||||
|
// Temporäre Cookie-Datei löschen falls vorhanden
|
||||||
|
if (tempCookiesFile && existsSync(tempCookiesFile)) {
|
||||||
|
await unlink(tempCookiesFile).catch((err) => {
|
||||||
|
console.error("Fehler beim Löschen der temporären Cookie-Datei:", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user