Kapitel 13/Tutorial.md aktualisiert
This commit is contained in:
@@ -222,7 +222,7 @@ Mit dieser Einrichtung sind **SSH‑Schlüssel**, **Berechtigungen** und **Pfade
|
||||
|
||||
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.
|
||||
|
||||
> [!HINWEIS]
|
||||
> [!NOTE]
|
||||
> **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.
|
||||
|
||||
@@ -259,7 +259,7 @@ ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
|
||||
ssh-keygen -R "<CLIPPER-IP>"
|
||||
```
|
||||
|
||||
> **Entscheidung & Begründung – Sicherheitsprinzip**
|
||||
> [!NOTE]
|
||||
> 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>
|
||||
@@ -273,8 +273,8 @@ 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.
|
||||
> [!NOTE]
|
||||
> 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.
|
||||
|
||||
---
|
||||
|
||||
@@ -319,6 +319,7 @@ https://<DEINE_NEXTCLOUD_DOMAIN>/remote.php/dav/files/<DEIN_NC_BENUTZER>/
|
||||
* **Scope:** leer lassen
|
||||
* **Authentication:** `Body`
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Schritt 2: Twitch-User-ID herausfinden (n8n-Weboberfläche)
|
||||
@@ -340,315 +341,221 @@ 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
|
||||
In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**. Er sorgt dafür, dass regelmäßig neue VODs bei Twitch abgefragt, geprüft und anschließend verarbeitet werden.
|
||||
|
||||
2. **HTTP Request (Get Videos):**
|
||||
> [!NOTE]
|
||||
> **Ziel dieses Schrittes**
|
||||
> Wir bauen den Ablauf in n8n: Cron-Trigger → Twitch API → Prüfung der State-Datei → Entscheidung über neue VODs → Download und Upload in Nextcloud.
|
||||
|
||||
---
|
||||
|
||||
1. **Cron-Trigger – Zeitplan festlegen** (Node-Name: `Cron – Alle 10 Min`)
|
||||
- Dieser Node löst den Workflow regelmäßig aus.
|
||||
- Stelle ein: alle **10 Minuten** ausführen.
|
||||
|
||||
2. **HTTP Request – Twitch Videos abfragen** (Node-Name: `HTTP – Get Videos`)
|
||||
- Dieser Node ruft über die Twitch-API alle VODs deines Accounts ab.
|
||||
- URL:
|
||||
```
|
||||
https://api.twitch.tv/helix/videos?user_id=<DEINE_TWITCH_USER_ID>&type=archive
|
||||
```
|
||||
- Authentifizierung: OAuth2 (Credential „Twitch API“)
|
||||
- Header: `Client-Id: <DEINE_CLIENT_ID>`
|
||||
|
||||
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):**
|
||||
- Damit n8n mit dem Clipper kommunizieren kann, brauchst du SSH-Zugangsdaten.
|
||||
- Trage in n8n ein:
|
||||
* Name: `SSH Clipper`
|
||||
* Host: `<CLIPPER-IP>` (z. B. `10.0.0.42`)
|
||||
* Port: `22`
|
||||
* Username: `clipper`
|
||||
* Private Key: Inhalt von `~/.ssh/id_n8n_clipper`
|
||||
* Working Directory: `/srv/clipper`
|
||||
|
||||
4. **SSH Node – State-Datei prüfen** (Node-Name: `SSH – Check State`)
|
||||
- Dieser Schritt prüft, ob die Datei `/srv/clipper/state/vod_seen.list` bereits existiert und ob VOD-IDs eingetragen sind.
|
||||
- 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:**
|
||||
|
||||
- Typische Ergebnisse:
|
||||
```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 }} ```
|
||||
5. **Set Node – Ergebnisse übernehmen** (Node-Name: `Set – State Ergebnis`)
|
||||
- Ziel: die Ausgabe aus dem vorherigen Schritt in Felder umwandeln, die n8n versteht.
|
||||
- Expressions:
|
||||
* file_exists → `{{ JSON.parse($json.stdout).file_exists }}`
|
||||
* non_empty → `{{ JSON.parse($json.stdout).non_empty }}`
|
||||
* vods → `{{ 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.
|
||||
> Hier nur die Expressions eintragen, keine Typ-Konvertierungen vornehmen.
|
||||
|
||||
|
||||
6. ** If-Node – zwei klare Wege **
|
||||
|
||||
In diesem Schritt legen wir die Entscheidungspfade in einem **If-Node** an. Dafür werden zwei Bedigungen hinzugefügt, die jeweils einen klar benannten Output erzeugen.
|
||||
|
||||
### If-Node Einstellungen
|
||||
```git
|
||||
1. Bedingung: {{ $json.file_exists }} is true
|
||||
- Field type: Boolean
|
||||
|
||||
2. Bedingung: {{ $json.non_empty }} is true
|
||||
- Field type: Boolean
|
||||
|
||||
3. Operator: AND
|
||||
6. **If-Node – Entscheidung** (Node-Name: `If – State Prüfung`)
|
||||
- Dieser Node entscheidet, ob neue VODs heruntergeladen werden müssen.
|
||||
- Bedingungen:
|
||||
```
|
||||
Damit hat der if-Node zwei klar angesprochene Ausgänge, die die weitere Logik steuern.
|
||||
1. Bedingung: {{ $json.file_exists }} is true (Boolean)
|
||||
2. Bedingung: {{ $json.non_empty }} is true (Boolean)
|
||||
Operator: AND
|
||||
```
|
||||
- Ergebnis: zwei mögliche Pfade → False = neu anlegen, True = prüfen auf neue VODs.
|
||||
|
||||
7. ** False - Download **
|
||||
Ziel: n8n erkennt neue VODs, erstellt/aktualisiert die State-Datei und lädt jedes VOD **sequenziell** im Clipper herunter und direkt in **Nextcloud** hoch (mit automatischem Aufräumen und Logfiles). Alles wird von n8n gesteuert, die Dateiübertragung übernimmt **rclone** im Clipper.
|
||||
---
|
||||
|
||||
---
|
||||
7. **False-Pfad – VODs herunterladen und hochladen**
|
||||
|
||||
**A. Vorbereitung (einmalig) – rclone an Nextcloud anbinden**
|
||||
Ort: *Clipper‑LXC Shell*
|
||||
> [!NOTE]
|
||||
> Dieser Pfad läuft, wenn die State-Datei nicht existiert oder leer ist. Es werden alle VODs heruntergeladen und in Nextcloud hochgeladen.
|
||||
|
||||
1) rclone installieren (als root)
|
||||
**A. Vorbereitung (einmalig) – rclone an Nextcloud anbinden**
|
||||
**Ort:** Clipper-LXC Shell
|
||||
```bash
|
||||
apt update && apt install -y rclone
|
||||
```
|
||||
2) Zum Benutzer **clipper** wechseln
|
||||
```bash
|
||||
su - clipper
|
||||
```
|
||||
3) Remote **nc** anlegen (Passwort wird automatisch obskuriert)
|
||||
```bash
|
||||
rclone config create nc webdav \
|
||||
url=https://DEINE_DOMAIN/remote.php/dav/files/DEIN_BENUTZERNAME/ \
|
||||
vendor=nextcloud \
|
||||
user=DEIN_BENUTZERNAME \
|
||||
pass=$(rclone obscure 'DEIN_APP_PASSWORT')
|
||||
```
|
||||
4) Verbindung testen
|
||||
```bash
|
||||
url=https://DEINE_DOMAIN/remote.php/dav/files/DEIN_BENUTZERNAME/ \
|
||||
vendor=nextcloud \
|
||||
user=DEIN_BENUTZERNAME \
|
||||
pass=$(rclone obscure 'DEIN_APP_PASSWORT')
|
||||
rclone ls nc: --config /home/clipper/.config/rclone/rclone.conf
|
||||
```
|
||||
> **Entscheidung & Begründung**
|
||||
> Uploads laufen im Clipper mit rclone (WebDAV). Das ist robuster als Upload‑Nodes in n8n, vermeidet Binary‑Fehler und räumt lokal automatisch auf.
|
||||
> [!NOTE]
|
||||
> Uploads laufen im Clipper mit rclone. Das ist robuster als Upload-Nodes in n8n, vermeidet Fehler und räumt lokale Dateien auf.
|
||||
|
||||
---
|
||||
|
||||
**B. Download/Upload als Skript (übersichtlich & mit Logs)**
|
||||
Ort: *Clipper‑LXC Shell*
|
||||
|
||||
1) Skript anlegen
|
||||
**B. Download/Upload Skript erstellen**
|
||||
**Ort:** Clipper-LXC Shell
|
||||
```bash
|
||||
nano <clipper-ordner>/bin/clipper-vod-get
|
||||
```
|
||||
|
||||
2) Inhalt einfügen → speichern (**Ctrl+O**, Enter) → schließen (**Ctrl+X**)
|
||||
```js
|
||||
Inhalt:
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ID="${1:?need VOD id}"
|
||||
URL="${2:-https://www.twitch.tv/videos/${ID}}"
|
||||
|
||||
TMP="<clipper-ordner>/temp"
|
||||
LOGDIR="<clipper-ordner>/logs"
|
||||
CONF="/home/clipper/.config/rclone/rclone.conf"
|
||||
DST="nc:<gewünschter Ordner>/VODs/${ID}/"
|
||||
|
||||
OUT="$TMP/${ID}.%(ext)s"
|
||||
FILE="$TMP/${ID}.mp4"
|
||||
TEMP="$TMP/${ID}.temp.mp4"
|
||||
PART="$TMP/${ID}.mp4.part"
|
||||
LOCK="$TMP/${ID}.lock"
|
||||
LOG="$LOGDIR/${ID}.log"
|
||||
|
||||
mkdir -p "$TMP" "$LOGDIR"
|
||||
|
||||
log() {
|
||||
echo "[$(date '+%F %T')] $*" | tee -a "$LOG"
|
||||
}
|
||||
|
||||
log() { echo "[$(date '+%F %T')] $*" | tee -a "$LOG"; }
|
||||
log "=== Start VOD $ID ==="
|
||||
log "URL: $URL"
|
||||
|
||||
if rclone lsf "$DST" --config "$CONF" >/dev/null 2>&1; then
|
||||
log "SKIP: $ID bereits in Nextcloud"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -e "$LOCK" ]]; then
|
||||
log "LOCK: $ID wird bereits verarbeitet"
|
||||
exit 0
|
||||
fi
|
||||
trap 'rm -f "$LOCK"' EXIT
|
||||
: > "$LOCK"
|
||||
|
||||
if [[ -s "$TEMP" && ! -s "$FILE" ]]; then
|
||||
log "RESUME: TEMP gefunden → umbenennen"
|
||||
mv -f "$TEMP" "$FILE"
|
||||
fi
|
||||
if [[ -s "$FILE" ]]; then
|
||||
log "RESUME: fertige Datei gefunden → hochladen"
|
||||
rclone move "$FILE" "$DST" --config "$CONF" --create-empty-src-dirs -v
|
||||
rm -f "$PART" "$TEMP" || true
|
||||
log "OK: $ID hochgeladen (Resume-Pfad)"
|
||||
log "=== Done VOD $ID ==="
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "START: Download mit yt-dlp"
|
||||
yt-dlp -q --no-progress \
|
||||
--retries 20 --fragment-retries 50 --retry-sleep 5 --socket-timeout 30 \
|
||||
--hls-prefer-ffmpeg --remux-video mp4 \
|
||||
-o "$OUT" "$URL"
|
||||
|
||||
if rclone lsf "$DST" --config "$CONF" >/dev/null 2>&1; then log "SKIP: $ID bereits in Nextcloud"; exit 0; fi
|
||||
if [[ -e "$LOCK" ]]; then log "LOCK: $ID wird bereits verarbeitet"; exit 0; fi
|
||||
trap 'rm -f "$LOCK"' EXIT; : > "$LOCK"
|
||||
if [[ -s "$TEMP" && ! -s "$FILE" ]]; then mv -f "$TEMP" "$FILE"; fi
|
||||
if [[ -s "$FILE" ]]; then rclone move "$FILE" "$DST" --config "$CONF" --create-empty-src-dirs -v; rm -f "$PART" "$TEMP" || true; exit 0; fi
|
||||
yt-dlp -q --no-progress --retries 20 --fragment-retries 50 --retry-sleep 5 --socket-timeout 30 --hls-prefer-ffmpeg --remux-video mp4 -o "$OUT" "$URL"
|
||||
[[ -s "$FILE" ]] || { [[ -s "$TEMP" ]] && mv -f "$TEMP" "$FILE"; }
|
||||
if [[ ! -s "$FILE" ]]; then
|
||||
log "ERROR: Download fehlgeschlagen ($FILE fehlt/leer)"
|
||||
exit 2
|
||||
fi
|
||||
log "OK: Download abgeschlossen ($(du -h "$FILE" | awk '{print $1}'))"
|
||||
|
||||
log "START: Upload nach Nextcloud"
|
||||
if [[ ! -s "$FILE" ]]; then log "ERROR: Download fehlgeschlagen ($FILE fehlt/leer)"; exit 2; fi
|
||||
rclone move "$FILE" "$DST" --config "$CONF" --create-empty-src-dirs -v
|
||||
log "OK: Upload abgeschlossen"
|
||||
|
||||
rm -f "$PART" "$TEMP" || true
|
||||
log "CLEANUP: temporäre Dateien entfernt"
|
||||
log "=== Done VOD $ID ==="
|
||||
```
|
||||
|
||||
3) Rechte setzen
|
||||
Rechte setzen:
|
||||
```bash
|
||||
chmod 755 <clipper-ordner>/bin <clipper-ordner>/bin/clipper-vod-get
|
||||
chmod 755 <clipper-ordner>/bin/clipper-vod-get
|
||||
chown clipper:clipper <clipper-ordner>/bin/clipper-vod-get
|
||||
```
|
||||
> [!NOTE]
|
||||
> Pro VOD entsteht ein Logfile in `<clipper-ordner>/logs/<ID>.log`. Du kannst es live mit `tail -f <clipper-ordner>/logs/<ID>.log` verfolgen.
|
||||
|
||||
---
|
||||
|
||||
Mit diesem Aufbau ist der **False-Pfad** fertig: Wenn die State-Datei fehlt oder leer ist, werden alle VODs verarbeitet und in Nextcloud hochgeladen. Der True-Pfad folgt im nächsten Abschnitt.
|
||||
|
||||
> **Hinweis**
|
||||
> Pro VOD entsteht ein Logfile in `<clipper-ordner>/logs/<ID>.log`. Live-Ansicht mit `tail -f <clipper-ordner>/logs/<ID>.log`
|
||||
|
||||
---
|
||||
|
||||
**C. n8n‑Verkabelung (Überblick)**
|
||||
Ort: *n8n Weboberfläche*
|
||||
### Schritt 8: True-Pfad – Check und ggf. Download
|
||||
|
||||
**Verkabelung (Kurzüberblick):**
|
||||
1) HTTP Request →
|
||||
2) Split Out: →
|
||||
3) Merge →
|
||||
4) Split In Batches →
|
||||
5) SSH Node 1 (State-Datei schreiben) →
|
||||
6) SSH Node 2 (Download & Upload)
|
||||
|
||||
---
|
||||
> [!NOTE]
|
||||
> Der **False-Pfad** wurde bereits im vorherigen Abschnitt vollständig erklärt. Viele Nodes überschneiden sich mit dem True-Pfad. Damit du nicht alles doppelt anlegen musst, verweisen wir hier auf die bereits erstellten und konfigurierten Nodes.
|
||||
|
||||
** Node-Einstellungen (1:1 in n8n eintragen)**
|
||||
|
||||
**1) HTTP Request – Get Videos**
|
||||
- **Node-Typ:** HTTP Request
|
||||
- **Methode:** GET
|
||||
- **URL:**
|
||||
```
|
||||
https://api.twitch.tv/helix/videos?user_id=<DEINE_TWITCH_USER_ID>&type=archive&first=20
|
||||
```
|
||||
- **Authentifizierung:** OAuth2 (Credential: *Twitch API*)
|
||||
- **Header:** `Client-Id: <DEINE_CLIENT_ID>`
|
||||
- **Response Format:** JSON
|
||||
---
|
||||
|
||||
**2) Item Lists – Split Out**
|
||||
- **Node-Typ:** Split Out
|
||||
- **Field to Split Out:** `data`
|
||||
|
||||
**3) Merge – Combine**
|
||||
- **Node-Typ:** Merge
|
||||
- **Mode:** Combine
|
||||
- **Combine Mode:** All Possible Combinations
|
||||
- **Eingang 1:** Switch (Ausgang: CREATE_AND_DOWNLOAD)
|
||||
- **Eingang 2:** Item Lists: Split Out
|
||||
**Verkabelung (Kurzüberblick):**
|
||||
1) HTTP Request →
|
||||
2) Split Out →
|
||||
3) Set – vods in Array →
|
||||
4) Split Out Array →
|
||||
5) Merge →
|
||||
6) Split In Batches →
|
||||
7) SSH – Write State →
|
||||
8) SSH – Download VOD
|
||||
|
||||
**4) Split In Batches**
|
||||
- **Node-Typ:** Split In Batches
|
||||
- **Batch Size:** `1`
|
||||
|
||||
**5) SSH Node 1 – State-Datei schreiben**
|
||||
- **Node-Typ:** SSH
|
||||
- **Credentials:** *SSH Clipper* (User = `clipper`)
|
||||
- **Operation:** Execute Command
|
||||
- **Command is an Expression:** **ON**
|
||||
- **Command:**
|
||||
```bash
|
||||
{{`set -euo pipefail; STATE="/srv/clipper/state/vod_seen.list"; mkdir -p "$(dirname "$STATE")"; if [ -s "$STATE" ]; then printf "%s\n" "${$json.data.id}" >> "$STATE"; else printf "%s\n" "${$json.data.id}" > "$STATE"; fi`}}
|
||||
```
|
||||
---
|
||||
|
||||
**6) SSH Node 2 – Download & Upload (Skript)**
|
||||
- **Node-Typ:** SSH
|
||||
- **Credentials:** *SSH Clipper* (User = `clipper`)
|
||||
- **Operation:** Execute Command
|
||||
- **Command is an Expression:** **ON**
|
||||
- **Command:**
|
||||
```bash
|
||||
<clipper-ordner>/bin/clipper-vod-get "{{$('Merge').item.json.data.id}}" "{{ $json.url || ('https://www.twitch.tv/videos/' + $('Merge').item.json.data.id) }}"
|
||||
```
|
||||
- **Hinweis:** Keine Binary-Nodes hinter diesem Schritt – Upload erfolgt im Skript via rclone.
|
||||
|
||||
---
|
||||
### Node-Einstellungen (1:1 in n8n eintragen)
|
||||
|
||||
**Ergebnis**
|
||||
- n8n steuert den gesamten Prozess, Upload erfolgt zuverlässig im Clipper via rclone.
|
||||
- Pro VOD entsteht **eine** MP4 in Nextcloud: `<gewünschter Ordner>/VODs/<ID>/`.
|
||||
- Pro VOD gibt es ein eigenes Logfile unter `<clipper-ordner>/logs/<ID>.log`.
|
||||
- Lokaler Speicher bleibt frei (automatisches Löschen nach Upload).
|
||||
- Logs der Schritte findest du im SSH‑Node‑Output und persistent im Logfile.
|
||||
|
||||
8. ** True-Pfad - Check und ggf. Download
|
||||
|
||||
**Verkabelung (Kurzüberblick):**
|
||||
1) HTTP Request →
|
||||
2) Split Out→
|
||||
3) Set – vods in Array →
|
||||
4) Split Arry Out →
|
||||
5) Merge →
|
||||
6) Split In Batches →
|
||||
7) SSH Node 1 (State-Datei schreiben) →
|
||||
8) SSH Node 2 (Download & Upload)
|
||||
> [!IMPORTANT]
|
||||
> Die folgenden Nodes haben wir im vorherigen Schritt (False-Pfad) bereits erstellt und konfiguriert. Wenn du dem Tutorial bis hierhin gefolgt bist, musst du an diesen Nodes nichts mehr verändern:
|
||||
> - **HTTP Request – Get Videos**
|
||||
> - **Split Out – data**
|
||||
> - **Split In Batches**
|
||||
> - **SSH – Write State**
|
||||
> - **SSH – Download VOD**
|
||||
|
||||
** Node-Einstellungen (1:1 in n8n eintragen)**
|
||||
**1) HTTP Request – Get Videos**
|
||||
- **Node-Typ:** HTTP Request
|
||||
- **Methode:** GET
|
||||
- **URL:**
|
||||
```
|
||||
https://api.twitch.tv/helix/videos?user_id=<DEINE_TWITCH_USER_ID>&type=archive&first=20
|
||||
```
|
||||
- **Authentifizierung:** OAuth2 (Credential: *Twitch API*)
|
||||
- **Header:** `Client-Id: <DEINE_CLIENT_ID>`
|
||||
- **Response Format:** JSON
|
||||
|
||||
**2) Item Lists – Split Out**
|
||||
- **Node-Typ:** Split Out
|
||||
- **Field to Split Out:** `data`
|
||||
---
|
||||
|
||||
**3) Set – vods in Array**
|
||||
- **Node-Typ:** Edit Fields (set)
|
||||
- **Field:** vods
|
||||
- **Type:** Arry
|
||||
- **Expression** `{{ (typeof $json.vods === 'string' ? $json.vods : String($json.vods)) .split(',') .map(s => s.trim()) .filter(Boolean) }}`
|
||||
|
||||
**4) Item Lists – Split Out**
|
||||
- **Node-Typ:** Split Out
|
||||
- **Field to Split Out:** `vods`
|
||||
**Neu im True-Pfad:**
|
||||
|
||||
**5) Merge – Combine**
|
||||
- **Node-Typ:** Merge
|
||||
- **Mode:** Combine
|
||||
- **Combine Mode:** Matching Fields
|
||||
- **Fields To Match Have Different Names:** ON
|
||||
- **Field 1:** vods
|
||||
- **Field 2:** data.id
|
||||
- **Output Type:** Keep Non-Matches
|
||||
- **Output Data From:** Input 2
|
||||
- **Eingang 1:** Split Out Array VODs
|
||||
- **Eingang 2:** Split Out Twitch VODs
|
||||
|
||||
**3) Set – vods in Array** (Node-Name: `Set – vods in Array`)
|
||||
- Node-Typ: Set
|
||||
- Field: vods
|
||||
- Expression:
|
||||
```js
|
||||
{{ (typeof $json.vods === 'string' ? $json.vods : String($json.vods))
|
||||
.split(',')
|
||||
.map(s => s.trim())
|
||||
.filter(Boolean) }}
|
||||
```
|
||||
|
||||
|
||||
**4) Split Out – vods** (Node-Name: `Split Out – vods`)
|
||||
- Node-Typ: Split Out
|
||||
- Field to Split Out: vods
|
||||
|
||||
|
||||
**5) Merge – Combine** (Node-Name: `Merge – Combine`)
|
||||
- Node-Typ: Merge
|
||||
- Mode: Combine
|
||||
- Combine Mode: Matching Fields
|
||||
- Fields To Match Have Different Names: ON
|
||||
- Field 1: vods
|
||||
- Field 2: data.id
|
||||
- Output Type: Keep Non-Matches
|
||||
- Output Data From: Input 2
|
||||
- Eingang 1: Split Out Array VODs
|
||||
- Eingang 2: Split Out Twitch VODs
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Ergebnis
|
||||
- Es werden nur **neue VODs** heruntergeladen und hochgeladen.
|
||||
- Die State-Datei wird erweitert, ohne bestehende IDs zu überschreiben.
|
||||
- Logs bleiben konsistent, Doppel-Downloads werden vermieden.
|
||||
- Jeder Node ist eindeutig benannt, was die Übersicht verbessert.
|
||||
Reference in New Issue
Block a user