561 lines
20 KiB
Markdown
561 lines
20 KiB
Markdown
# 🛠️ Kapitel 13 – Clipper (Tutorial)
|
||
|
||
---
|
||
|
||
## Einleitung
|
||
|
||
Clips sind der beste Weg, lange Streams in kurze, teilbare Highlights zu verwandeln. Unser Ziel in diesem Kapitel: Wir bauen ein System, das neue Videos automatisch erkennt, sinnvolle Stellen analysiert, passende Highlights schneidet und die Ergebnisse in Nextcloud ablegt – inklusive Titeln und Hashtags für jede Plattform. Der Clipper selbst übernimmt dabei die technische Verarbeitung, während **n8n** für Steuerung, Analyse und Benachrichtigungen sorgt. Das System bleibt dadurch flexibel, ressourcenschonend und jederzeit erweiterbar.
|
||
|
||
---
|
||
|
||
## Voraussetzungen
|
||
|
||
- **Proxmox LXC** mit Debian 12 (Bookworm)
|
||
- **Nextcloud** (Pflicht, Zielort für Clips & Metadaten)
|
||
- **n8n-Instanz** (Automatisierung, Steuerung Clipper, Analyse, Metadaten-Erzeugung)
|
||
- **Twitch-Entwickler-Account** inkl. API-Key (für VOD- und Clip-Zugriff)
|
||
- **Optional**: RTMP-Server, falls VODs lokal aufgezeichnet werden
|
||
- **Ressourcen für den LXC**: 1 vCPU, 1–2 GB RAM, 10 GB Speicher reichen aus
|
||
- **Grundwissen**: SSH-Verbindung, Nano-Editor, Basiskenntnisse in n8n
|
||
|
||
---
|
||
|
||
## Vorbereitung
|
||
|
||
Wir beginnen mit einem frischen Debian‑12‑LXC in Proxmox, benennen ihn `clipper` und vergeben die im Abschnitt oben genannten Ressourcen. Danach bringen wir das System auf Stand und installieren die Grundwerkzeuge:
|
||
```bash
|
||
apt update && apt upgrade -y
|
||
apt install -y curl unzip ffmpeg inotify-tools
|
||
```
|
||
|
||
Eine korrekte Systemzeit ist entscheidend, da Schnittmarken später auf exakten Sekunden basieren. Prüfe die Zeit mit:
|
||
```bash
|
||
timedatectl status
|
||
```
|
||
Wenn hier UTC steht und du lieber „Europe/Berlin“ nutzen willst:
|
||
```bash
|
||
timedatectl list-timezones | grep Europe
|
||
timedatectl set-timezone Europe/Berlin
|
||
timedatectl status
|
||
```
|
||
Die Zeit wird sofort angepasst, Logs und Schnittzeiten passen damit zur lokalen Umgebung.
|
||
|
||
Zum Schluss legen wir die Arbeitsordner an:
|
||
```bash
|
||
mkdir -p /srv/clipper/{watch,out,temp,logs}
|
||
```
|
||
- `watch` – Eingangsordner für neue Videos (egal ob von Twitch oder RTMP)
|
||
- `out` – fertige Clips und Metadaten
|
||
- `temp` – Zwischenspeicher für Analyse
|
||
- `logs` – Protokolle aller Abläufe
|
||
|
||
Damit ist das Fundament gelegt.
|
||
|
||
---
|
||
|
||
## Abschnitt 2 – Clipper‑LXC einrichten (Benutzer, Verzeichnisse, Pakete, Skripte)
|
||
|
||
In diesem Abschnitt richten wir den **Clipper‑Container** so ein, dass **SSH‑Schlüssel**, **Downloads** und **n8n‑Aufrufe** ohne Berechtigungsfehler funktionieren. Wir arbeiten jetzt **im Terminal deines Clipper‑LXC als root**.
|
||
|
||
> **Entscheidung & Begründung – Benutzer mit Home & Bash**
|
||
> Der Benutzer **clipper** bekommt ein **Homeverzeichnis** (`/home/clipper`) und eine **Login‑Shell**. So können SSH‑Schlüssel sauber in `~clipper/.ssh` landen und n8n später per SSH Befehle ausführen. Varianten ohne Home (System‑User) führen bei `ssh-copy-id` zu Fehlern.
|
||
|
||
### 2.1 Benutzer und Verzeichnisse anlegen (Terminal, als root)
|
||
|
||
```bash
|
||
adduser --home /home/clipper --shell /bin/bash clipper
|
||
```
|
||
Vergib ein Passwort und bestätige die Abfragen. Danach legst du die Arbeitsordner an und überträgst den Besitz an `clipper`:
|
||
```bash
|
||
mkdir -p /srv/clipper/{inbox,watch,out,temp,logs,bin}
|
||
chown -R clipper:clipper /srv/clipper
|
||
chmod 750 /srv/clipper
|
||
```
|
||
(optional, aber hilfreich für `ssh-copy-id` später):
|
||
```bash
|
||
install -d -m 700 -o clipper -g clipper /home/clipper/.ssh
|
||
```
|
||
|
||
> **Falls du den Benutzer bereits ohne Home angelegt hast:**
|
||
> Richte ihn so nach:
|
||
> `mkdir -p /home/clipper/.ssh && chown -R clipper:clipper /home/clipper && chmod 700 /home/clipper/.ssh`
|
||
|
||
### 2.2 Pakete installieren (Terminal, als root)
|
||
|
||
```bash
|
||
apt update && apt install -y yt-dlp jq python3 python3-venv curl unzip inotify-tools sudo
|
||
```
|
||
- **ffmpeg**: Analyse & Schnitt
|
||
- **yt-dlp**: Twitch‑VOD/Clip‑Downloads (HLS)
|
||
- **jq**: JSON‑Handling
|
||
- **python3/venv**: spätere Analyse‑Tools
|
||
- **inotify-tools**: Dateisystem‑Events (optional)
|
||
- **sudo**: für gezielte Rechteerhöhungen falls nötig
|
||
|
||
### 2.3 Zentrale Konfiguration (Terminal, als root)
|
||
|
||
Bevor wir die Umgebungsdatei anlegen, brauchen wir ein eigenes Konfigurationsverzeichnis. Das existiert standardmäßig nicht, daher legen wir es einmalig an:
|
||
|
||
```bash
|
||
mkdir -p /etc/clipper
|
||
chown root:clipper /etc/clipper
|
||
chmod 750 /etc/clipper
|
||
```
|
||
|
||
> **Entscheidung & Begründung – eigenes /etc/clipper**
|
||
> Konfiguration gehört nach `/etc`. Mit einem eigenen Ordner `/etc/clipper` bleibt alles übersichtlich getrennt.
|
||
> Besitzer ist `root`, die Gruppe `clipper`. So kann der Clipper-User die Datei lesen, aber nicht verändern – genau die Balance zwischen Sicherheit und Funktion.
|
||
|
||
|
||
|
||
Entscheidung & Begründung – eigenes /etc/clipper
|
||
Konfiguration gehört nach /etc. Mit einem eigenen Ordner /etc/clipper bleibt alles übersichtlich getrennt.
|
||
Besitzer ist root, die Gruppe clipper. So kann der Clipper-User die Datei lesen, aber nicht verändern – genau die Balance zwischen Sicherheit und Funktion.
|
||
|
||
Lege eine Umgebungsdatei an, die beide Skripte laden:
|
||
```bash
|
||
nano /etc/clipper/clipper.env
|
||
```
|
||
Inhalt:
|
||
```
|
||
CLIPPER_INBOX=/srv/clipper/inbox
|
||
CLIPPER_IN=/srv/clipper/watch
|
||
CLIPPER_OUT=/srv/clipper/out
|
||
CLIPPER_TMP=/srv/clipper/temp
|
||
CLIPPER_LOG=/srv/clipper/logs/clipper.log
|
||
```
|
||
Dateirechte setzen, damit `clipper` sie lesen darf:
|
||
```bash
|
||
chown root:clipper /etc/clipper/clipper.env
|
||
chmod 640 /etc/clipper/clipper.env
|
||
```
|
||
|
||
### 2.4 Python‑Umgebung vorbereiten (Wechsel zu Benutzer *clipper*)
|
||
|
||
Wechsle jetzt **zum Benutzer clipper**:
|
||
```bash
|
||
su - clipper
|
||
```
|
||
Erzeuge und fülle eine virtuelle Umgebung für die spätere Analyse:
|
||
```bash
|
||
python3 -m venv /srv/clipper/.venv
|
||
source /srv/clipper/.venv/bin/activate
|
||
pip install --upgrade pip
|
||
pip install numpy opencv-python-headless
|
||
deactivate
|
||
```
|
||
Wechsle für die nächsten Schritte **im Benutzer clipper** weiter.
|
||
|
||
### 2.5 Einstiegsskripte erstellen (im Benutzer *clipper*)
|
||
|
||
**Analyse‑Stub** – prüft Eingaben, schreibt Logs, erzeugt leere Kandidatenliste:
|
||
```bash
|
||
nano /srv/clipper/bin/clipper-analyze
|
||
```
|
||
Inhalt:
|
||
```bash
|
||
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
ENV_FILE="/etc/clipper/clipper.env"; [ -r "$ENV_FILE" ] || { echo "ENV nicht lesbar: $ENV_FILE" >&2; exit 1; }; source "$ENV_FILE"
|
||
IN="$1" # absolute Datei
|
||
JOBID="${2:-manual}"
|
||
mkdir -p "$CLIPPER_TMP/$JOBID"
|
||
echo "$(date '+%F %T') [ANALYZE] job=$JOBID file=$IN" | tee -a "$CLIPPER_LOG"
|
||
OUT_JSON="$CLIPPER_TMP/$JOBID/candidates.json"
|
||
echo '[]' > "$OUT_JSON"
|
||
echo "$OUT_JSON"
|
||
```
|
||
|
||
**Schneid‑Stub** – protokolliert Schnittaufrufe, echte Logik folgt in Abschnitt 5:
|
||
```bash
|
||
nano /srv/clipper/bin/clipper-cut
|
||
```
|
||
Inhalt:
|
||
```bash
|
||
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
ENV_FILE="/etc/clipper/clipper.env"; [ -r "$ENV_FILE" ] || { echo "ENV nicht lesbar: $ENV_FILE" >&2; exit 1; }; source "$ENV_FILE"
|
||
IN="$1" # absolute Datei
|
||
RANGES_JSON="$2" # Zeitbereiche (kommt später aus Abschnitt 4)
|
||
JOBID="${3:-manual}"
|
||
mkdir -p "$CLIPPER_OUT/$JOBID"
|
||
echo "$(date '+%F %T') [CUT] job=$JOBID file=$IN ranges=$RANGES_JSON" | tee -a "$CLIPPER_LOG"
|
||
exit 0
|
||
```
|
||
|
||
Rechte setzen und Eigentümer korrigieren:
|
||
```bash
|
||
chmod +x /srv/clipper/bin/clipper-*
|
||
chown -R clipper:clipper /srv/clipper/bin
|
||
```
|
||
|
||
### 2.6 Logrotation (zurück zu root)
|
||
|
||
Beende die Session (`exit`) und kehre zu **root** zurück. Richte Logrotation ein:
|
||
```bash
|
||
nano /etc/logrotate.d/clipper
|
||
```
|
||
Inhalt:
|
||
```
|
||
/srv/clipper/logs/*.log {
|
||
rotate 14
|
||
daily
|
||
missingok
|
||
notifempty
|
||
compress
|
||
delaycompress
|
||
copytruncate
|
||
}
|
||
```
|
||
|
||
> **Schnelltest (optional):**
|
||
> Zurück im **Benutzer clipper**:
|
||
> `/srv/clipper/bin/clipper-analyze /srv/clipper/watch/demo.mp4 job-001`
|
||
> `/srv/clipper/bin/clipper-cut /srv/clipper/watch/demo.mp4 /srv/clipper/temp/job-001/ranges.json job-001`
|
||
> `tail -n 50 /srv/clipper/logs/clipper.log`
|
||
|
||
Mit dieser Einrichtung sind **SSH‑Schlüssel**, **Berechtigungen** und **Pfade** konsistent. `ssh-copy-id` aus Abschnitt 3 funktioniert dadurch ohne Fehlermeldungen – und n8n kann die Skripte stabil starten.
|
||
|
||
---
|
||
|
||
## Abschnitt 3 – n8n ↔ Twitch: VOD & Clips importieren, in Nextcloud ablegen, Clipper starten
|
||
|
||
In diesem Abschnitt verbinden wir n8n mit Twitch, Nextcloud und dem Clipper. Das Ziel: n8n erkennt automatisch neue VODs auf Twitch, lädt sie zusammen mit Clips herunter, legt sie in Nextcloud ab und startet dann die Analyse auf dem Clipper. Wir gehen Schritt für Schritt vor – immer mit klaren Hinweisen, ob wir uns gerade in der **n8n-Weboberfläche**, im **Terminal** oder in **Nextcloud** befinden.
|
||
|
||
> **Entscheidung & Begründung – Rollenverteilung**
|
||
> **n8n** steuert (APIs, Logik, Benachrichtigungen). **Clipper** arbeitet (Download, Analyse, Schnitt). **Nextcloud** speichert (Archiv & Übergabe). So bleibt n8n schlank und ausfallsicher, während Clipper CPU/IO für Medienjobs bekommt.
|
||
|
||
---
|
||
|
||
### Schritt 1: Zugriff zwischen den Containern vorbereiten (Terminal)
|
||
|
||
<details>
|
||
<summary>Optional: SSH Known-Hosts zurücksetzen (falls Clipper schon einmal erstellt wurde)</summary>
|
||
|
||
Wenn du den Clipper-LXC bereits früher erstellt und neu aufgesetzt hast, kann es zu einem SSH-Fehler kommen:
|
||
|
||
```
|
||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
|
||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||
```
|
||
|
||
Das bedeutet, dass sich der **Server-Hostkey** geändert hat. SSH blockiert dann aus Sicherheitsgründen.
|
||
|
||
#### Lösung Schritt für Schritt (im n8n-LXC als root)
|
||
|
||
1. **Fingerprint auf dem Clipper prüfen**
|
||
|
||
```bash
|
||
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
|
||
```
|
||
|
||
(SHA256-Wert merken und vergleichen)
|
||
|
||
2. **Alten Eintrag löschen**
|
||
|
||
```bash
|
||
ssh-keygen -R "<CLIPPER-IP>"
|
||
```
|
||
|
||
> **Entscheidung & Begründung – Sicherheitsprinzip**
|
||
> SSH schützt vor Man-in-the-Middle-Angriffen, indem es Hostkeys prüft. Wenn ein Container neu erstellt wird, ist ein neuer Hostkey normal. Wir löschen den alten Eintrag bewusst, prüfen den neuen Fingerprint und akzeptieren ihn erst danach. So bleibt die Verbindung sicher **und** stabil.
|
||
|
||
</details>
|
||
|
||
**SSH-Schlüssel für Clipper hinterlegen (zwingend):**
|
||
```bash
|
||
ssh-keygen -t rsa -b 4096 -m PEM -f ~/.ssh/id_n8n_clipper -N ""
|
||
ssh-copy-id -i ~/.ssh/id_n8n_clipper.pub clipper@<CLIPPER-IP> # << unbedingt ausführen
|
||
ssh -i ~/.ssh/id_n8n_clipper clipper@<CLIPPER-IP> "echo OK"
|
||
```
|
||
|
||
Ersetze `<CLIPPER-IP>` durch die IP/den Hostnamen deines Clipper-LXC (z. B. `10.0.0.42`). Wenn **OK** erscheint, kann n8n ohne Passwort auf den Clipper zugreifen.
|
||
|
||
> **Entscheidung & Begründung – RSA (PEM) statt ed25519**
|
||
> n8n akzeptiert nur PEM-Schlüssel zuverlässig. Ed25519 erzeugt oft OpenSSH-Keys, die von n8n nicht geparst werden können. Mit `-m PEM` stellen wir sicher, dass das Format passt.
|
||
|
||
---
|
||
|
||
### Zugangsdaten für Nextcloud-WebDAV erstellen (Weboberfläche)
|
||
|
||
> **Ort in Nextcloud**: Avatar (oben rechts) → **Persönliche Einstellungen** → **Sicherheit** → **ganz nach unten** zum Bereich **App-Passwörter**.
|
||
|
||
**Anleitung:**
|
||
|
||
1. Melde dich in der **Nextcloud-Weboberfläche** an.
|
||
2. Gehe zu **Persönliche Einstellungen** → **Sicherheit**.
|
||
3. **Ganz nach unten scrollen** bis zum Abschnitt **App-Passwörter**.
|
||
4. Trage bei **App-Name** z. B. `n8n Clipper` ein und klicke auf **Neues App-Passwort erstellen**.
|
||
5. Kopiere das **einmalig angezeigte App-Passwort** sofort und notiere zusätzlich deinen **Benutzernamen**.
|
||
|
||
**WebDAV-URL für n8n/Uploads:**
|
||
|
||
```
|
||
https://<DEINE_NEXTCLOUD_DOMAIN>/remote.php/dav/files/<DEIN_NC_BENUTZER>/
|
||
```
|
||
|
||
---
|
||
|
||
### Twitch-API Zugang (Developer Console)
|
||
|
||
1. Gehe auf [Twitch Developer Console](https://dev.twitch.tv/console/apps) → **Applications** → **Register Your Application**.
|
||
2. Felder ausfüllen:
|
||
|
||
* **Name:** frei wählbar
|
||
* **OAuth Redirect URL:** z. B. `https://localhost/`
|
||
* **Category:** passend wählen
|
||
3. App speichern → **Manage** öffnen.
|
||
4. **Client ID** notieren, **New Secret** klicken und **Client Secret** sichern.
|
||
|
||
### Twitch OAuth2 Credential in n8n (Client Credentials Flow)
|
||
|
||
* **Name:** Twitch API
|
||
* **Grant Type:** `Client Credentials`
|
||
* **Authorization URL:** `https://id.twitch.tv/oauth2/authorize`
|
||
* **Access Token URL:** `https://id.twitch.tv/oauth2/token`
|
||
* **Client ID / Secret:** aus Twitch Developer Console
|
||
* **Scope:** leer lassen
|
||
* **Authentication:** `Body`
|
||
|
||
---
|
||
|
||
### Schritt 2: Twitch-User-ID herausfinden (n8n-Weboberfläche)
|
||
|
||
HTTP Request Node:
|
||
|
||
* Methode: GET
|
||
* URL:
|
||
|
||
```
|
||
https://api.twitch.tv/helix/users?login=<DEIN_LOGIN>
|
||
```
|
||
* Auth: OAuth2 Credential
|
||
* Header: `Client-Id: <DEINE_CLIENT_ID>`
|
||
|
||
Im Ergebnis findest du im Feld `data[0].id` deine **User-ID** (z. B. `123456789`).
|
||
|
||
---
|
||
|
||
### Schritt 3: Workflow bauen (n8n-Weboberfläche)
|
||
|
||
1. **Cron-Trigger:** alle 10 Minuten
|
||
|
||
2. **HTTP Request (Get Videos):**
|
||
|
||
```
|
||
https://api.twitch.tv/helix/videos?user_id=<DEINE_TWITCH_USER_ID>&type=archive
|
||
```
|
||
|
||
3. **SSH Credentials in n8n anlegen**
|
||
Damit n8n mit dem Clipper arbeiten kann, legen wir zunächst ein SSH Credential an:
|
||
|
||
* **Name:** SSH Clipper
|
||
* **Host:** `<CLIPPER-IP>` (z. B. `10.0.0.42`)
|
||
* **Port:** 22
|
||
* **Username:** `clipper`
|
||
* **Private Key:** Inhalt von `~/.ssh/id_n8n_clipper` (PEM-Format)
|
||
* **Working Directory:** `/srv/clipper`
|
||
|
||
4. **SSH Node – State-Datei prüfen**
|
||
Jetzt prüfen wir, ob die Datei `/srv/clipper/state/vod_seen.list` existiert und ob bereits VOD-IDs darin stehen.
|
||
|
||
**Command (als Expression):**
|
||
|
||
```js
|
||
{{`set -euo pipefail; STATE_FILE="/srv/clipper/state/vod_seen.list"; fe=false; ne=false; arr='[]'; if [ -f "$STATE_FILE" ]; then fe=true; if [ -s "$STATE_FILE" ]; then ne=true; mapfile -t L < "$STATE_FILE"; json='['; sep=''; for id in "\${L[@]}"; do id_trim="$(printf '%s' "$id" | tr -d '\r' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"; [ -n "$id_trim" ] || continue; json+="$sep\"$id_trim\""; sep=','; done; json+=']'; arr="$json"; fi; fi; printf '{"file_exists":%s,"non_empty":%s,"vods":%s}\n' "$fe" "$ne" "$arr"`}}
|
||
|
||
```
|
||
|
||
**Beispiele für den Output:**
|
||
|
||
```json
|
||
{"file_exists":false,"non_empty":false,"vods":[]}
|
||
{"file_exists":true,"non_empty":false,"vods":[]}
|
||
{"file_exists":true,"non_empty":true,"vods":["123456789","987654321"]}
|
||
```
|
||
5. Set Node – Felder übernehmen
|
||
|
||
### Set Node – Felder übernehmen
|
||
|
||
file_exists → ```json {{ JSON.parse($json.stdout).file_exists }} ```
|
||
non_empty → ```json {{ JSON.parse($json.stdout).non_empty }} ```
|
||
vods → ```json {{ JSON.parse($json.stdout).vods }} ```
|
||
|
||
> [!IMPORTANT]
|
||
> Stelle die Felder auf den Typ Array bzw. Boolean um.
|
||
> Aktiviere die Option: Add Option → Ignore Type Conversion Errors → einschalten.
|
||
|
||
6. State ermitteln (Set-Node – EIN Feld)
|
||
|
||
### State ermitteln
|
||
state →
|
||
```json
|
||
{{ $json.file_exists === false
|
||
? 'CREATE_AND_DOWNLOAD'
|
||
: ($json.non_empty === false
|
||
? 'APPEND_AND_DOWNLOAD'
|
||
: 'NEED_CHECK') }}
|
||
```
|
||
> [!IMPORTANT]
|
||
> Aktiviere die Option: Include Other Input Fields → ALL.
|
||
|
||
7. Switch-Node – drei klare Wege
|
||
|
||
In diesem Schritt legen wir die Entscheidungspfade in einem **Switch-Node** an. Dafür werden drei Regeln hinzugefügt, die jeweils einen klar benannten Output erzeugen.
|
||
|
||
### Switch-Node Einstellungen
|
||
Mode: Rules
|
||
Property: {{ $json.state_expression }}
|
||
|
||
### Regeln
|
||
```git
|
||
1. Regel:
|
||
- Bedingung: {{ $json.state_expression }} is equal to CREATE_AND_DOWNLOAD
|
||
- Rename Output: ON
|
||
- Output Name: CREATE_AND_DOWNLOAD
|
||
|
||
2. Regel:
|
||
- Bedingung: {{ $json.state_expression }} is equal to APPEND_AND_DOWNLOAD
|
||
- Rename Output: ON
|
||
- Output Name: APPEND_AND_DOWNLOAD
|
||
|
||
3. Regel:
|
||
- Bedingung: {{ $json.state_expression }} is equal to NEED_CHECK
|
||
- Rename Output: ON
|
||
- Output Name: NEED_CHECK
|
||
```
|
||
Damit hat der Switch-Node drei klar benannte Ausgänge, die die weitere Logik steuern.
|
||
|
||
8. Pfad 1 - CREATE_AND_DOWNLOAD
|
||
|
||
> [!IMPORTANT]
|
||
> Nextcloud-Verbindung einrichten (einmalig im Clipper-LXC)
|
||
> Damit VODs nach dem Download nicht den lokalen Speicher füllen, verschieben wir sie direkt in die Nextcloud. Dazu nutzen wir **rclone**.
|
||
|
||
|
||
Schritt für Schritt:
|
||
- Öffne die Shell deines Clipper-LXC (z. B. über Proxmox oder per `ssh clipper@<CLIPPER-IP>`).
|
||
- Installiere rclone:
|
||
```bash
|
||
sudo apt update && sudo apt install -y rclone
|
||
```
|
||
- Erstelle den Konfigurationsordner:
|
||
```bash
|
||
mkdir -p /home/clipper/.config/rclone
|
||
```
|
||
- Öffne die Konfigurationsdatei:
|
||
```bash
|
||
nano /home/clipper/.config/rclone/rclone.conf
|
||
```
|
||
- Trage Folgendes ein (passe Werte an):
|
||
```
|
||
[nc]
|
||
type = webdav
|
||
url = https://DEINE_NEXTCLOUD_DOMAIN/remote.php/dav/files/DEIN_BENUTZERNAME/
|
||
vendor = nextcloud
|
||
user = DEIN_BENUTZERNAME
|
||
pass = DEIN_APP_PASSWORT_OBFUSCATED
|
||
```
|
||
- Rechte anpassen:
|
||
```bash
|
||
chown -R clipper:clipper /home/clipper/.config/rclone
|
||
chmod 600 /home/clipper/.config/rclone/rclone.conf
|
||
```
|
||
- Teste die Verbindung:
|
||
```bash
|
||
rclone ls nc:
|
||
```
|
||
Wenn Dateien angezeigt werden, ist alles korrekt.
|
||
|
||
|
||
> **Entscheidung & Begründung**
|
||
> Wir nutzen rclone statt dauerhaften Mounts, weil es einfacher und robuster ist. rclone lädt Dateien hoch, kann Verbindungen wiederholen und löscht lokale Kopien automatisch.
|
||
|
||
|
||
---
|
||
|
||
|
||
Verkabelung (Switch-GO **und** Split-Daten zusammenführen):
|
||
- **HTTP Request: VODs abrufen** → **Split Out** (Field to Split Out: `data`) → (liefert N VOD-Items)
|
||
- **Split Out** → **Merge (Combine → All Possible Combinations)** (Eingang 2)
|
||
- **Switch (Regeln aus Punkt 7)** → **Output CREATE_AND_DOWNLOAD** → **Merge (Combine → All Possible Combinations)** (Eingang 1)
|
||
- **Merge (Combine → All Possible Combinations)** → **SSH: State-Datei anlegen** → **SSH: VOD herunterladen (yt-dlp)**
|
||
|
||
|
||
Merge – Einstellungen:
|
||
- Node: **Merge**
|
||
- Mode: **Combine**
|
||
- Combine Mode: **All Possible Combinations**
|
||
- Eingang 1: **Switch → CREATE_AND_DOWNLOAD** (liefert das „GO“)
|
||
- Eingang 2: **Split Out** (liefert VOD-Daten)
|
||
- Ergebnis: **1×N** Kombination pro VOD-Item → ab hier sind **GO** und **VOD-Felder** im selben Item vorhanden.
|
||
|
||
|
||
Split Out – Einstellungen:
|
||
- Node: **Split Out**
|
||
- Operation: **Split Out Items**
|
||
- **Field to Split Out:** `data`
|
||
|
||
|
||
SSH – State-Datei anlegen (robust für mehrere Items):
|
||
- Typ: SSH • Credentials: SSH Clipper • Operation: Execute Command • Command is an Expression: ON
|
||
Command (Expression):
|
||
```
|
||
{{`set -euo pipefail; \
|
||
STATE="/srv/clipper/state/vod_seen.list"; \
|
||
mkdir -p "$(dirname "$STATE")"; \
|
||
if [ -s "$STATE" ]; then printf "%s
|
||
" "${$json.id}" >> "$STATE"; else printf "%s
|
||
" "${$json.id}" > "$STATE"; fi`}}
|
||
```
|
||
|
||
|
||
Vorbereitung – Nextcloud-Anbindung (einmalig im Clipper-LXC, als Benutzer *clipper*):
|
||
- `sudo apt install -y rclone`
|
||
- Konfigurationsdatei: `/home/clipper/.config/rclone/rclone.conf`
|
||
```
|
||
[nc]
|
||
type = webdav
|
||
url = https://DEINE_NEXTCLOUD_DOMAIN/remote.php/dav/files/DEIN_USER/
|
||
vendor = nextcloud
|
||
user = DEIN_USER
|
||
pass = DEIN_APP_PASSWORT_OBFUSCATED
|
||
```
|
||
> [!NOTE]
|
||
> Passwort aus Nextcloud **App-Passwort** (haben wir bereits erstellt). `rclone config` kann das auch interaktiv einrichten.
|
||
|
||
|
||
SSH – VOD herunterladen nach temp und nach Nextcloud verschieben (yt-dlp + rclone):
|
||
- Typ: SSH • Credentials: SSH Clipper • Operation: Execute Command • Command is an Expression: ON
|
||
Command (Expression):
|
||
```
|
||
{{`set -euo pipefail; \
|
||
TMP="/srv/clipper/temp"; \
|
||
mkdir -p "$TMP"; \
|
||
URL="${$json.url || ("https://www.twitch.tv/videos/" + $json.id)}"; \
|
||
yt-dlp --no-progress --remux-video mp4 -o "$TMP/%(id)s.%(ext)s" "$URL"; \
|
||
FILE="$TMP/${$json.id}.mp4"; \
|
||
rclone move "$FILE" "nc:Clipper/VODs/${$json.id}/" --create-empty-src-dirs -v`}}
|
||
```
|
||
|
||
|
||
Ergebnis:
|
||
- Download läuft lokal nach `/srv/clipper/temp`.
|
||
- Upload nach Nextcloud (`nc:`) mit automatischem Löschen.
|
||
- Kein Speicherstau, auch wenn viele VODs anstehen.
|
||
- Empfehlung: **Split In Batches (Batch Size = 1)** in n8n, damit die Items nacheinander laufen und der LXC nicht überlastet wird.
|
||
{{`set -euo pipefail; \
|
||
TMP="/srv/clipper/temp"; \
|
||
mkdir -p "$TMP"; \
|
||
URL="${$json.url || ("https://www.twitch.tv/videos/" + $json.id)}"; \
|
||
yt-dlp --no-progress --remux-video mp4 -o "$TMP/%(id)s.%(ext)s" "$URL"; \
|
||
FILE="$TMP/${$json.id}.mp4"; \
|
||
rclone move "$FILE" "nc:Clipper/VODs/${$json.id}/" --create-empty-src-dirs -v`}}
|
||
```
|
||
|
||
|
||
Ergebnis:
|
||
- `/srv/clipper/state/vod_seen.list` existiert und enthält die **erste** VOD-ID (bei Regel 1).
|
||
- Für **jedes VOD** entsteht unter `/srv/clipper/watch/<VOD_ID>.mp4` eine MP4.
|
||
- Durch den **Merge (Combine → All Possible Combinations)** liegen **Switch-GO** und **VOD-Daten** zusammen vor; die SSH-Nodes haben alles, was sie brauchen. |