From 1d1a327a8c089c0227bc78d683447d62c527d15e Mon Sep 17 00:00:00 2001 From: Thomas Dannenberg Date: Thu, 28 Aug 2025 15:23:09 +0000 Subject: [PATCH] Kapitel 13/Tutorial.md aktualisiert --- Kapitel 13/Tutorial.md | 121 +++++++++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 42 deletions(-) diff --git a/Kapitel 13/Tutorial.md b/Kapitel 13/Tutorial.md index fdbf591..8fcdb9b 100644 --- a/Kapitel 13/Tutorial.md +++ b/Kapitel 13/Tutorial.md @@ -1,4 +1,4 @@ - # 🛠️ Kapitel 13 – Clipper (Tutorial) +# 🛠️ Kapitel 13 – Clipper (Tutorial) --- @@ -340,64 +340,101 @@ 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=&type=archive&first=1 ``` -3. **IF „Neu?“ Node:** + +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:** `` (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 - {{ !$workflow.staticData.global.last_vod_id || $json.data[0].id !== $workflow.staticData.global.last_vod_id }} + {{"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=\"${id//[$'\\t\\r\\n ']}\"; [ -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\""}} ``` - → true: weiter, false: Ende -4. **SSH (Download VOD auf Clipper):** + **Beispiele für den Output:** - ```bash - JOBID="{{ $json.data[0].id }}" - URL="{{ $json.data[0].url }}" - DIR="/srv/clipper/inbox/$JOBID" - - mkdir -p "$DIR" - - yt-dlp \ - --download-archive "/srv/clipper/logs/yt-dlp.archive" \ - --no-part --restrict-filenames \ - --abort-on-unavailable-fragment \ - --retries 10 --fragment-retries 10 --retry-sleep 5 \ - -o "$DIR/%(title)s-%(id)s.%(ext)s" \ - "$URL" + ```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. **Nextcloud Upload (HTTP PUT, Basic Auth):** - ``` - https:///remote.php/dav/files//Clips/{{ $json.data[0].id }}/ - ``` -6. **Analyse starten (SSH):** +5. **Set Node – Felder übernehmen** + Direkt nach dem SSH Node fügen wir einen **Edit Fields (Set)** Node ein. + Damit parsen wir das JSON aus `stdout` in echte Felder, die wir später leicht in IF- oder anderen Nodes verwenden können. - ```bash - VIDDIR="/srv/clipper/inbox/{{ $json.data[0].id }}" - MAINFILE="$(find "$VIDDIR" -maxdepth 1 -type f -name '*.mp4' -o -name '*.mkv' | head -n1)" - /srv/clipper/bin/clipper-analyze "$MAINFILE" "vod-{{ $json.data[0].id }}" - ``` -7. **State aktualisieren:** + **Felder (Expressions):** - ```js - $workflow.staticData.global.last_vod_id = $json.data[0].id; - return items; - ``` + * `file_exists` → `={{ JSON.parse($json.stdout).file_exists }}` + * `non_empty` → `={{ JSON.parse($json.stdout).non_empty }}` + * `vods` → `={{ JSON.parse($json.stdout).vods }}` + +```md +## 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=](https://api.twitch.tv/helix/videos?user_id=)\\&type=archive\&first=1 + +```` +### 6. State ermitteln (Set-Node – EIN Feld) + +Wir bewerten **nur den Dateistatus**. `vodId` aus Twitch wird erst später benötigt, wenn die Datei existiert **und** nicht leer ist. + +**Feld:** `state` +**Expression:** + +```js +{{ $json.file_exists === false + ? 'CREATE_AND_DOWNLOAD' + : ($json.non_empty === false + ? 'APPEND_AND_DOWNLOAD' + : 'NEED_CHECK') }} +``` --- -### Kontrolle +### 7. Switch-Node – drei klare Wege -Im Clipper-LXC: +**Switch → Property Name:** `={{ $json.state }}` + +**Cases:** + +* **CREATE\_AND\_DOWNLOAD** → Datei anlegen **und** VOD sofort downloaden. +* **APPEND\_AND\_DOWNLOAD** → Datei ist leer → VOD-ID direkt eintragen und downloaden. +* **NEED\_CHECK** → Datei existiert und ist nicht leer → hier prüfen, ob die aktuelle VOD-ID schon enthalten ist. + +--- + +### Branch `NEED_CHECK` + +1. **Set (kurz)** + + * `currentVod` → `={{ $json.vodId ?? $json.data[0].id }}` + * `contains_vod` → `={{ Array.isArray($json.vods) && $json.vods.includes($json.currentVod) }}` + +2. **IF Node (einmalig in diesem Branch)** + + * **Bedingung:** `={{ $json.contains_vod === true }}` + + * **True:** Pfad beenden (VOD bereits verarbeitet) + * **False:** Download & Analyse starten, danach ID anhängen -```bash -su - clipper -ls -lh /srv/clipper/inbox/ -tail -n 50 /srv/clipper/logs/clipper.log -``` -In Nextcloud: Ordner `Clips/` sollte erscheinen.