Enhance Dockerfile and API for yt-dlp integration
- Install Deno as a JavaScript runtime for yt-dlp in the Dockerfile. - Add configuration for yt-dlp to support cookies and JavaScript runtime selection. - Update API to handle cookies for YouTube bot detection and allow specifying the JavaScript runtime. - Introduce new environment variables for cookie management and JavaScript runtime configuration in README.
This commit is contained in:
14
Dockerfile
14
Dockerfile
@@ -3,15 +3,25 @@ FROM node:20-alpine
|
|||||||
# Set default locale to German
|
# Set default locale to German
|
||||||
ENV LOCALE=de
|
ENV LOCALE=de
|
||||||
|
|
||||||
# yt-dlp und ffmpeg installieren
|
# yt-dlp, ffmpeg und deno (JavaScript Runtime für YouTube) installieren
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
python3 \
|
python3 \
|
||||||
py3-pip \
|
py3-pip \
|
||||||
ffmpeg \
|
ffmpeg \
|
||||||
&& pip3 install --no-cache-dir --break-system-packages yt-dlp
|
curl \
|
||||||
|
unzip \
|
||||||
|
&& pip3 install --no-cache-dir --break-system-packages yt-dlp \
|
||||||
|
&& curl -fsSL https://deno.land/install.sh | sh \
|
||||||
|
&& mv /root/.deno/bin/deno /usr/local/bin/deno \
|
||||||
|
&& chmod +x /usr/local/bin/deno
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# yt-dlp Konfiguration erstellen (für deno als JS-Runtime)
|
||||||
|
RUN mkdir -p /root/.config/yt-dlp && \
|
||||||
|
echo "--js-runtimes deno" > /root/.config/yt-dlp/config && \
|
||||||
|
echo "--no-warnings" >> /root/.config/yt-dlp/config
|
||||||
|
|
||||||
# Package-Dateien kopieren und Dependencies installieren
|
# Package-Dateien kopieren und Dependencies installieren
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -101,6 +101,9 @@ Siehe [BUILD-MACOS.md](./BUILD-MACOS.md) für detaillierte Anleitung.
|
|||||||
- `SESSION_SECRET`: Secret für Session-Cookies (Standard: `default-secret-change-in-production`)
|
- `SESSION_SECRET`: Secret für Session-Cookies (Standard: `default-secret-change-in-production`)
|
||||||
- `STREAM_ONLY`: Wenn auf `true` gesetzt, werden Dateien nicht physisch gespeichert, sondern direkt als Download-Stream angeboten (Standard: `false`)
|
- `STREAM_ONLY`: Wenn auf `true` gesetzt, werden Dateien nicht physisch gespeichert, sondern direkt als Download-Stream angeboten (Standard: `false`)
|
||||||
- `LOCALE`: Sprache der Anwendung - `de` für Deutsch oder `en` für Englisch (Standard: `de`)
|
- `LOCALE`: Sprache der Anwendung - `de` für Deutsch oder `en` für Englisch (Standard: `de`)
|
||||||
|
- `YT_DLP_COOKIES`: Pfad zu einer Cookie-Datei für yt-dlp (z.B. `./cookies.txt`). Wird verwendet, um YouTube Bot-Erkennung zu umgehen. Siehe [yt-dlp Cookie-Dokumentation](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp)
|
||||||
|
- `YT_DLP_COOKIES_FROM_BROWSER`: Browser-Name, aus dem Cookies geladen werden sollen (z.B. `chrome`, `firefox`, `edge`, `safari`). Alternative zu `YT_DLP_COOKIES`. Siehe [yt-dlp Cookie-Dokumentation](https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies)
|
||||||
|
- `YT_DLP_JS_RUNTIME`: JavaScript Runtime für yt-dlp (Standard: `deno`). Andere Optionen: `node`, `d8`, etc.
|
||||||
|
|
||||||
**Beispiel `.env` Datei mit Login:**
|
**Beispiel `.env` Datei mit Login:**
|
||||||
```
|
```
|
||||||
@@ -111,6 +114,7 @@ DOWNLOAD_DIR=./downloaded
|
|||||||
SESSION_SECRET=mein-geheimes-session-secret
|
SESSION_SECRET=mein-geheimes-session-secret
|
||||||
STREAM_ONLY=false
|
STREAM_ONLY=false
|
||||||
LOCALE=de
|
LOCALE=de
|
||||||
|
YT_DLP_COOKIES_FROM_BROWSER=chrome
|
||||||
```
|
```
|
||||||
|
|
||||||
**Beispiel `.env` Datei ohne Login:**
|
**Beispiel `.env` Datei ohne Login:**
|
||||||
@@ -119,8 +123,15 @@ LOGIN=false
|
|||||||
DOWNLOAD_DIR=./downloaded
|
DOWNLOAD_DIR=./downloaded
|
||||||
STREAM_ONLY=false
|
STREAM_ONLY=false
|
||||||
LOCALE=de
|
LOCALE=de
|
||||||
|
YT_DLP_COOKIES_FROM_BROWSER=chrome
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Hinweis zu Cookies:**
|
||||||
|
- Wenn YouTube Bot-Erkennung auftritt, müssen Cookies verwendet werden
|
||||||
|
- `YT_DLP_COOKIES_FROM_BROWSER` ist die einfachste Option: Gibt den Browser-Namen an (z.B. `chrome`, `firefox`, `edge`, `safari`)
|
||||||
|
- Alternativ kann `YT_DLP_COOKIES` mit dem Pfad zu einer Cookie-Datei verwendet werden
|
||||||
|
- Cookie-Dateien können mit Browser-Erweiterungen wie "Get cookies.txt LOCALLY" oder "cookies.txt" exportiert werden
|
||||||
|
|
||||||
**Hinweis zu `LOGIN`:**
|
**Hinweis zu `LOGIN`:**
|
||||||
- Wenn `LOGIN=false`: Keine Login-Seite, alle Seiten sind öffentlich zugänglich. `LOGIN_USERNAME` und `LOGIN_PASSWORD` werden ignoriert.
|
- Wenn `LOGIN=false`: Keine Login-Seite, alle Seiten sind öffentlich zugänglich. `LOGIN_USERNAME` und `LOGIN_PASSWORD` werden ignoriert.
|
||||||
- Wenn `LOGIN=true` oder nicht gesetzt: Login ist aktiviert. `LOGIN_USERNAME` und `LOGIN_PASSWORD` müssen gesetzt sein.
|
- Wenn `LOGIN=true` oder nicht gesetzt: Login ist aktiviert. `LOGIN_USERNAME` und `LOGIN_PASSWORD` müssen gesetzt sein.
|
||||||
|
|||||||
@@ -56,8 +56,23 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
// Format aus Request Header (optional, Standard: MP4)
|
// Format aus Request Header (optional, Standard: MP4)
|
||||||
const format = request.headers.get("x-format") || "mp4";
|
const format = request.headers.get("x-format") || "mp4";
|
||||||
|
|
||||||
|
// Cookie-Unterstützung für YouTube Bot-Erkennung
|
||||||
|
const cookiesFile = process.env.YT_DLP_COOKIES;
|
||||||
|
const cookiesFromBrowser = process.env.YT_DLP_COOKIES_FROM_BROWSER;
|
||||||
|
|
||||||
|
// JavaScript Runtime für yt-dlp (Standard: deno)
|
||||||
|
const jsRuntime = process.env.YT_DLP_JS_RUNTIME || "deno";
|
||||||
|
|
||||||
// Zuerst Video-Informationen abrufen, um den Dateinamen zu erhalten
|
// Zuerst Video-Informationen abrufen, um den Dateinamen zu erhalten
|
||||||
const videoInfo = await ytDlpWrap.getVideoInfo(url);
|
// getVideoInfo verwendet intern yt-dlp mit --dump-json
|
||||||
|
// Deno wird beim eigentlichen Download verwendet
|
||||||
|
const videoInfoOptions: string[] = [];
|
||||||
|
if (cookiesFile) {
|
||||||
|
videoInfoOptions.push("--cookies", cookiesFile);
|
||||||
|
} else if (cookiesFromBrowser) {
|
||||||
|
videoInfoOptions.push("--cookies-from-browser", cookiesFromBrowser);
|
||||||
|
}
|
||||||
|
const videoInfo = await ytDlpWrap.getVideoInfo(url, videoInfoOptions);
|
||||||
const title = videoInfo.title || "Video";
|
const title = videoInfo.title || "Video";
|
||||||
|
|
||||||
// Dateiendung bestimmen
|
// Dateiendung bestimmen
|
||||||
@@ -72,12 +87,13 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
const filename = `${title}.${ext}`;
|
const filename = `${title}.${ext}`;
|
||||||
|
|
||||||
// Format-String für yt-dlp
|
// Format-String für yt-dlp
|
||||||
|
// Für "best": Kein Format-String = yt-dlp wählt automatisch bestes Format und merged
|
||||||
const formatString =
|
const formatString =
|
||||||
format === "mp4"
|
format === "mp4"
|
||||||
? "bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo[ext=mp4]+bestaudio/best[ext=mp4]/best"
|
? "bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo[ext=mp4]+bestaudio/best[ext=mp4]/best"
|
||||||
: format === "audio"
|
: format === "audio"
|
||||||
? "bestaudio[ext=m4a]/bestaudio[ext=mp3]/bestaudio"
|
? "bestaudio[ext=m4a]/bestaudio[ext=mp3]/bestaudio"
|
||||||
: "best";
|
: undefined; // undefined = yt-dlp wählt automatisch bestes Format
|
||||||
|
|
||||||
if (streamOnly) {
|
if (streamOnly) {
|
||||||
// STREAM-MODUS: Datei temporär speichern, streamen, dann löschen
|
// STREAM-MODUS: Datei temporär speichern, streamen, dann löschen
|
||||||
@@ -91,12 +107,24 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
url,
|
url,
|
||||||
"-o",
|
"-o",
|
||||||
tempFilePath,
|
tempFilePath,
|
||||||
"-f",
|
|
||||||
formatString,
|
|
||||||
"--no-mtime",
|
"--no-mtime",
|
||||||
"--no-playlist",
|
"--no-playlist",
|
||||||
|
"--js-runtimes",
|
||||||
|
jsRuntime,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Cookie-Unterstützung hinzufügen
|
||||||
|
if (cookiesFile) {
|
||||||
|
execArgs.push("--cookies", cookiesFile);
|
||||||
|
} else if (cookiesFromBrowser) {
|
||||||
|
execArgs.push("--cookies-from-browser", cookiesFromBrowser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format nur hinzufügen wenn definiert
|
||||||
|
if (formatString) {
|
||||||
|
execArgs.push("-f", formatString);
|
||||||
|
}
|
||||||
|
|
||||||
if (format === "mp4") {
|
if (format === "mp4") {
|
||||||
execArgs.push("--merge-output-format", "mp4");
|
execArgs.push("--merge-output-format", "mp4");
|
||||||
} else if (format === "audio") {
|
} else if (format === "audio") {
|
||||||
@@ -184,12 +212,24 @@ export const POST: APIRoute = async ({ request }) => {
|
|||||||
url,
|
url,
|
||||||
"-o",
|
"-o",
|
||||||
outputPath,
|
outputPath,
|
||||||
"-f",
|
|
||||||
formatString,
|
|
||||||
"--no-mtime",
|
"--no-mtime",
|
||||||
"--no-playlist",
|
"--no-playlist",
|
||||||
|
"--js-runtimes",
|
||||||
|
jsRuntime,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Cookie-Unterstützung hinzufügen
|
||||||
|
if (cookiesFile) {
|
||||||
|
execArgs.push("--cookies", cookiesFile);
|
||||||
|
} else if (cookiesFromBrowser) {
|
||||||
|
execArgs.push("--cookies-from-browser", cookiesFromBrowser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format nur hinzufügen wenn definiert
|
||||||
|
if (formatString) {
|
||||||
|
execArgs.push("-f", formatString);
|
||||||
|
}
|
||||||
|
|
||||||
if (format === "mp4") {
|
if (format === "mp4") {
|
||||||
execArgs.push("--merge-output-format", "mp4");
|
execArgs.push("--merge-output-format", "mp4");
|
||||||
} else if (format === "audio") {
|
} else if (format === "audio") {
|
||||||
|
|||||||
Reference in New Issue
Block a user