26 KiB
🛠️ 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:
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:
timedatectl status
Wenn hier UTC steht und du lieber „Europe/Berlin“ nutzen willst:
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:
mkdir -p /srv/clipper/{watch,out,temp,logs}
watch– Eingangsordner für neue Videos (egal ob von Twitch oder RTMP)out– fertige Clips und Metadatentemp– Zwischenspeicher für Analyselogs– 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/.sshlanden und n8n später per SSH Befehle ausführen. Varianten ohne Home (System‑User) führen beissh-copy-idzu Fehlern.
2.1 Benutzer und Verzeichnisse anlegen (Terminal, als root)
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:
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):
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)
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:
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/clipperbleibt alles übersichtlich getrennt.
Besitzer istroot, die Gruppeclipper. 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:
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
CLIPPER_NC_REMOTE="nc:<DEIN-REMOTE>/<BASISPFAD>"
Dateirechte setzen, damit clipper sie lesen darf:
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:
su - clipper
Erzeuge und fülle eine virtuelle Umgebung für die spätere Analyse:
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:
nano /srv/clipper/bin/clipper-analyze
Inhalt:
#!/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:
nano /srv/clipper/bin/clipper-cut
Inhalt:
#!/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:
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:
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.
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.
Schritt 1: Zugriff zwischen den Containern vorbereiten (Terminal)
Optional: SSH Known-Hosts zurücksetzen (falls Clipper schon einmal erstellt wurde)
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)
- Fingerprint auf dem Clipper prüfen
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
(SHA256-Wert merken und vergleichen)
- Alten Eintrag löschen
ssh-keygen -R "<CLIPPER-IP>"
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.
SSH-Schlüssel für Clipper hinterlegen (zwingend):
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.
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 PEMstellen 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:
- Melde dich in der Nextcloud-Weboberfläche an.
- Gehe zu Persönliche Einstellungen → Sicherheit.
- Ganz nach unten scrollen bis zum Abschnitt App-Passwörter.
- Trage bei App-Name z. B.
n8n Clipperein und klicke auf Neues App-Passwort erstellen. - 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)
-
Gehe auf Twitch Developer Console → Applications → Register Your Application.
-
Felder ausfüllen:
- Name: frei wählbar
- OAuth Redirect URL: z. B.
https://localhost/ - Category: passend wählen
-
App speichern → Manage öffnen.
-
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)
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.
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.
-
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.
-
HTTP Request – Get Videos (Node-Name:
Get Twitch VOD IDs)- 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.1 SSH Credentials in n8n anlegen
- 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
-
Split Out – vods (Node-Name:
Split Out – Twitch VOD)- Node-Typ: Split Out
- Field to Split Out:
data
-
SSH Node – State-Datei prüfen (Node-Name:
SSH – Check State)- Dieser Schritt prüft, ob die Datei
/srv/clipper/state/vod_seen.listbereits existiert und ob VOD-IDs eingetragen sind. - Command (als Expression):
{{`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"`}}- Typische Ergebnisse:
{"file_exists":false,"non_empty":false,"vods":[]} {"file_exists":true,"non_empty":false,"vods":[]} {"file_exists":true,"non_empty":true,"vods":["123456789","987654321"]} - Dieser Schritt prüft, ob die Datei
-
Set – File Information (Node-Name:
Set – File Information)- Node-Typ: Set
- Field: file_exists
- Type: Boolean
- Expression:
{{ JSON.parse($json.stdout).file_exists }}
- Field: non_empty
- Type: Boolean
- Expression:
{{ JSON.parse($json.stdout).non_empty }}
- Field: vods
- Type: Array
- Expression:
{{ JSON.parse($json.stdout).vods }}
- Add Option: Ignore Type Conversion Errors -> "ON"
-
Set – vods in Array (Node-Name:
Set – vods in Array)
- Node-Typ: Set
- Field: vods
- Type: Array
- Expression:
{{ (typeof $json.vods === 'string' ? $json.vods : String($json.vods))
.split(',')
.map(s => s.trim())
.filter(Boolean) }}
- Split Out – vods (Node-Name:
Split Out – vods)
- Node-Typ: Split Out
- Field to Split Out:
vods
-
Vorbereitungen für VOD Download und Speicherung
8.1 Vorbereitung (einmalig) – rclone an Nextcloud anbinden
Ort: Clipper-LXC Shell Öffne hierzu in Proxmox, Putty, oder einer anderen Konsole den Clipper LXC und gebe die folgenden Befehele ein:apt update && apt install -y rcloneHiermit installieren wie rclone, was wir später für den Upload zu Nextcloud nutzen werden
Wechsel dann zu dem vorhin erstellten NUtzer (in diesem Tutorial Clipper) und erstelle eine WebDAV Anbindung an deine Nextcloud. Hierfür verwnedest du die folgenden Befehle:
su - clipper 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') rclone ls nc: --config /home/clipper/.config/rclone/rclone.conf8.2 Download/Upload Skript erstellen
Ort: Clipper-LXC ShellNoch immer in der Konsole des Clipper LXC verlässt du mit
exitden User und bist wieder root User. Im Anschluss erstellst du eine neue Datei mitnano <clipper-ordner>/bin/clipper-vod-getNun befüllst du sie mit:
#!/usr/bin/env bash set -euo pipefail . /etc/clipper/clipper.env ID="${1:?need VOD id}" URL="${2:-https://www.twitch.tv/videos/${ID}}" TMP="${CLIPPER_TMP}" OUT_BASE="${CLIPPER_OUT}/${ID}" LOGDIR="${CLIPPER_LOG}/${ID}" CONF="/home/clipper/.config/rclone/rclone.conf" DST="${CLIPPER_NC_REMOTE}/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" mkdir -p "$TMP" "$LOGDIR" "$OUT_BASE" LOG="$LOGDIR/download.log" log(){ echo "[$(date '+%F %T')] $*"; } exec > >(tee -a "$LOG") 2>&1 # ---- atomarer Lock (kein Race zwischen zwei Starts) exec 9>"$LOCK" if ! flock -n 9; then log "LOCK: $ID wird bereits verarbeitet" exit 0 fi trap 'flock -u 9; rm -f "$LOCK"' EXIT log "=== Start VOD $ID ===" log "URL: $URL" log "DST: $DST" # ---- Prüfe, ob die ZIELDATEI bereits existiert (nicht nur der Ordner) if rclone lsf "$DST" --config "$CONF" | grep -qx "${ID}.mp4"; then log "SKIP: $ID.mp4 bereits in Nextcloud" exit 0 fi # ---- Resume: unvollständigen Download sauber fortsetzen if [[ -s "$TEMP" && ! -s "$FILE" ]]; then log "RESUME: $TEMP -> $FILE" mv -f "$TEMP" "$FILE" fi # ---- Gemeinsame rclone-Flags: Nextcloud-Chunking + robuste Timeouts export RCLONE_WEBDAV_CHUNK_SIZE=100Mi # wirkt bei neueren rclone Versionen rclone move "$FILE" "$DST" \ --config "$CONF" --create-empty-src-dirs \ --transfers 1 --checkers 4 \ --retries 10 --low-level-retries 50 --retries-sleep 30s \ --timeout 1h --contimeout 1m --expect-continue-timeout 10m \ -v # ---- Wenn Datei schon da: nur noch hochschieben if [[ -s "$FILE" ]]; then log "MOVE (resume): $FILE → $DST" rclone move "$FILE" "$DST" "${RCLONE_FLAGS[@]}" rm -f "$PART" "$TEMP" || true log "CLEANUP: $TMP" rm -rf "${TMP:?}/"* log "=== Done VOD $ID (resume path) ===" exit 0 fi # ---- Download + Remux 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 "MOVE: $FILE → $DST" rclone move "$FILE" "$DST" "${RCLONE_FLAGS[@]}" rm -f "$PART" "$TEMP" || true log "CLEANUP: $TMP" rm -rf "${TMP:?}/"* log "=== Done VOD $ID ===" "Mit diesem Skript laden wir die aktuellen VODs herunter, laden sie in die Nextcloud für die weitere Verabeitung und räumen wieder auf. Zusätzlich erzeugen wir logs in
<clipper-ordner>/logs/<ID>.log.Damit die Datei auch ausgeführt werden kann, musst du die folgenden zwei Befehle eingeben:
chmod 755 <clipper-ordner>/bin/clipper-vod-get chown clipper:clipper <clipper-ordner>/bin/clipper-vod-getNote
Pro VOD entsteht ein Logfile in
<clipper-ordner>/logs/<ID>.log. Du kannst es live mittail -f <clipper-ordner>/logs/<ID>.logverfolgen. -
Merge – Combine (Node-Name:
Select VODs to Download)- Node-Typ: Merge
- Mode: Combine
- Combine By: Matching Fields
- Fields To Match Have Different Names: "ON"
- Eingang 1: Split Out – vods
- Eingang 2: Split Out – Twitch VOD
- Input 1 Field: vods
- Input 2 Field: data.id
- Output Type: Keep Non-Matches
- Output Data From: Input 2 Mit diesem Merge Node sorgen wir dafür, dass wir nur die VODs herunter laden, die neu sind und noch nicht von Clipper bearbeitet wurden.
-
Split In Batches (Node-Name:
Einzeldurchlauf)
- Node-Typ: Split In Batches
- Batch Size: 1 Dieser Node sorgt dafür, dass wenn mal mehr wie ein VOD heruntergaladen werden muss dies nicht parallel geschieht. S sparen wir Ressourcen und sind schneller mit der Arbeit fertig.
- SSH Node 1 – State-Datei schreiben (Node-Name:
State Datei schreiben)
- Node-Typ: SSH
- Credentials: SSH Clipper
- Operation: Execute Command
- Command is an Expression: ON
- Command:
{{`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`}}
- SSH Node 2 – Download & Upload (Node-Name:
Down 'n' Up)
- Node-Typ: SSH
- Credentials: SSH Clipper
- Operation: Execute Command
- Command is an Expression: ON
- Command:
<clipper-ordner>/bin/clipper-vod-get "{{$('Merge').item.json.data.id}}" "{{ $json.url || ('https://www.twitch.tv/videos/' + $('Merge').item.json.data.id) }}"
Diese 11 Nodes werden das gesamte Grundgerüst der gesamten Automation sein. Wie aber müssen sie verbudnen werden? Das folgende Schaubild zeigt dir die konkrete Verkabelung
--- *SSH – Check State* --- *Set – File Information* --- *Set – vods in Array* --- *Split Out – vods* ------
| |
*Cron – Alle 10 Min* ---- | *Select VODs to Download* --- *Einzeldurchlauf* --- *State Datei schreiben* --- *Down 'n' Up* --- (Hier folgen später weitere Nodes, aber da der Einzeldurchlauf ein Loop ist wird der letzte Node mit Einzeldurchlauf verbunden)
| |
--- *Get Twitch VOD IDs* --- *Split Out* – *Twitch VOD* --------------------------------------------------
🧪 Abschnitt 4 – Analyse
Note
Wir verwenden in diesem Tutorial keine KI‑Analyse. Hierfür wird es ein eigenes Tutorial geben. Wir legen aber bereits alles so an, dass später keine Umbauten mehr nötig sind.
Schritt 4.1 – Analyse‑Skript anlegen
Ort: Terminal im Clipper‑LXC → als Benutzer clipper
Öffne das Skript und trage den Inhalt ein:
nano /srv/clipper/bin/vod-analyze
Inhalt:
#!/usr/bin/env bash
set -euo pipefail
. /etc/clipper/clipper.env
ID="${1:?need VOD id}"
VOD_IN_MP4="${CLIPPER_IN}/${ID}.mp4"
OUT_BASE="${CLIPPER_OUT}/${ID}"
ANALYSIS="${OUT_BASE}/analysis"
LOGDIR="${CLIPPER_LOG}/${ID}"
mkdir -p "$ANALYSIS" "$LOGDIR"
exec > >(tee -a "${LOGDIR}/analyze.log") 2>&1
echo "== Analyze $ID =="
# 1) Szenenwechsel
ffmpeg -hide_banner -loglevel error -i "${VOD_IN_MP4}" \
-vf "scale=-2:360,select=gt(scene\,0.30),showinfo" -an -f null - \
2> "${LOGDIR}/sceneinfo.log"
# 2) Audio-Statistik
ffmpeg -hide_banner -loglevel error -i "${VOD_IN_MP4}" \
-vn -ac 1 -ar 16000 \
-af "astats=metadata=1:reset=2,ametadata=print:key=lavfi.astats.Overall.RMS_level" \
-f null - \
2> "${LOGDIR}/astats.log" || true
# 3) Logs → candidates.json
ANALYSIS="$ANALYSIS" LOGDIR="$LOGDIR" python3 - <<'PY'
import os,re,json
out=os.environ["ANALYSIS"]; log=os.environ["LOGDIR"]
scene_ts=[]
with open(os.path.join(log,"sceneinfo.log"), errors="ignore") as f:
for line in f:
m=re.search(r"pts_time:([0-9]+(?:\.[0-9]+)?)", line)
if m: scene_ts.append(float(m.group(1)))
has_audio=False
ap=os.path.join(log,"astats.log")
if os.path.exists(ap):
with open(ap, errors="ignore") as f:
has_audio = "RMS_level" in f.read()
cands=[{
"start": max(0.0,t-2.0),
"end": t+6.0,
"score": round(0.6+(0.1 if has_audio else 0),2),
"tags": ["scene-cut"] + (["audio-peak"] if has_audio else [])
} for t in scene_ts]
with open(os.path.join(out,"candidates.json"),"w",encoding="utf-8") as f:
json.dump(cands,f,ensure_ascii=False,indent=2)
print("Wrote", os.path.join(out,"candidates.json"))
PY
echo "== Done $ID =="
Ausführbar machen:
chmod +x /srv/clipper/bin/clipper-analyze
Schritt 4.2 – n8n: Analyse starten
Ort: n8n‑Weboberfläche
SSH Node – Analyze VOD
- Credentials:
SSH Clipper - Working Dir:
/srv/clipper - Command (Expression):
{{`/srv/clipper/bin/vod-analyze ${$json.data.id}`}}
Ergebnis
- Für jedes neue VOD wird automatisch ein eigener Log‑Ordner erstellt.
- Die Analyse erzeugt pro VOD eine
candidates.jsonmit Zeitfenstern. - Abschnitt 5 nutzt diese JSON für den Schnitt.