Kapitel 13/Tutorial.md aktualisiert

This commit is contained in:
2025-09-03 15:03:44 +00:00
parent 680997f693
commit 1336f58040

View File

@@ -118,12 +118,11 @@ 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>"
SFTP_HOST=192.168.51.2
SFTP_PORT=22
SFTP_USER=sftp_uploader
SFTP_KEY=/home/clipper/.ssh/nc_sftp_ed25519
SFTP_DROP_BASE=incoming
```
Dateirechte setzen, damit `clipper` sie lesen darf:
```bash
@@ -603,32 +602,27 @@ In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**. Er sorgt d
8. **Vorbereitungen für VOD Download und Speicherung**
**8.1 Vorbereitung (einmalig) rclone an Nextcloud anbinden**
**8.1 Vorbereitung (einmalig) SFTP-Verbindung testen
Ort: Clipper-LXC Shell
Öffne hierzu in Proxmox, Putty, oder einer anderen Konsole den Clipper LXC und gebe die folgenden Befehele ein:
```bash
apt update && apt install -y rclone
```
Hiermit 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:
Wir prüfen, ob Clipper mit dem Key des sftp_uploader auf den Nextcloud-Host kommt und die Drop-Zone erreichbar ist.
```bash
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.conf
sftp -i ~/.ssh/nc_sftp_ed25519 -oBatchMode=yes -oStrictHostKeyChecking=accept-new -P 22 sftp_uploader@<IP_des_Nextcloud_LXC> <<'SFTP'
mkdir incoming
mkdir incoming/_test
ls incoming
rmdir incoming/_test
SFTP
exit
```
Erwartung: die Ausgabe zeigt incoming. Dann ist die Verbindung korrekt.
**8.2 Download/Upload Skript erstellen**
**Ort:** Clipper-LXC Shell
Noch immer in der Konsole des Clipper LXC verlässt du mit `exit` den User und bist wieder root User.
Im Anschluss erstellst du eine neue Datei mit
Wir erstellen ein Skript, das ein Twitch-VOD mit yt-dlp lädt und per SFTP nach incoming/<VOD_ID>/<VOD_ID>.mp4 auf dem Nextcloud-Host hochlädt.
Voraussetzung: In /etc/clipper/clipper.env sind gesetzt:
SFTP_HOST, SFTP_PORT, SFTP_USER, SFTP_KEY, SFTP_DROP_BASE, außerdem CLIPPER_TMP, CLIPPER_OUT.
```bash
nano <clipper-ordner>/bin/clipper-vod-get
```
@@ -636,30 +630,31 @@ In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**. Er sorgt d
```bash
#!/usr/bin/env bash
set -euo pipefail
. /etc/clipper/clipper.env
ENV_FILE="/etc/clipper/clipper.env"
[[ -r "$ENV_FILE" ]] || { echo "ENV nicht lesbar: $ENV_FILE" >&2; exit 1; }
source "$ENV_FILE"
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"
TMP="${CLIPPER_TMP:-/srv/clipper/temp}"
OUT_BASE="${CLIPPER_OUT:-/srv/clipper/out}/${ID}"
LOGDIR="/srv/clipper/logs/${ID}"
FILE="${TMP}/${ID}.mp4"
TEMP="${TMP}/${ID}.temp.mp4"
PART="${TMP}/${ID}.mp4.part"
LOCK="${TMP}/${ID}.lock"
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"
DROP_BASE="${SFTP_DROP_BASE:-incoming}"
REMOTE_DIR="${DROP_BASE}/${ID}"
REMOTE_FILE="${REMOTE_DIR}/${ID}.mp4"
mkdir -p "$TMP" "$LOGDIR" "$OUT_BASE"
LOG="$LOGDIR/download.log"
log(){ echo "[$(date '+%F %T')] $*"; }
LOG="${LOGDIR}/download.log"
log(){ printf '[%(%F %T)T] %s\n' -1 "$*" ; }
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"
@@ -667,44 +662,36 @@ In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**. Er sorgt d
fi
trap 'flock -u 9; rm -f "$LOCK"' EXIT
log "=== Start VOD $ID ==="
log "URL: $URL"
log "DST: $DST"
SFTP_OPTS=(-i "${SFTP_KEY}" -P "${SFTP_PORT:-22}" -oBatchMode=yes -oStrictHostKeyChecking=accept-new)
SFTP_TARGET="${SFTP_USER}@${SFTP_HOST}"
# ---- 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"
sftp_batch() {
local cmds
cmds=$(printf "%s\n" "$@")
sftp "${SFTP_OPTS[@]}" "${SFTP_TARGET}" <<< "$cmds"
}
exists_remote_file() {
local out
out=$(sftp "${SFTP_OPTS[@]}" "${SFTP_TARGET}" <<< "ls -l ${REMOTE_FILE}" 2>&1 || true)
[[ "$out" != *"No such file"* ]] && [[ "$out" != *"not found"* ]]
}
log "=== Start VOD ${ID} ==="
log "URL: ${URL}"
log "DROP: ${REMOTE_FILE}"
if exists_remote_file; then
log "SKIP: ${REMOTE_FILE} existiert bereits"
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
OUT="${TMP}/${ID}.%(ext)s"
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"
@@ -712,18 +699,30 @@ In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**. Er sorgt d
if [[ ! -s "$FILE" ]]; then
log "ERROR: Download fehlgeschlagen ($FILE fehlt/leer)"
exit 2
exit 10
fi
log "MOVE: $FILE → $DST"
rclone move "$FILE" "$DST" "${RCLONE_FLAGS[@]}"
rm -f "$PART" "$TEMP" || true
sftp_batch "mkdir ${DROP_BASE}" "mkdir ${REMOTE_DIR}"
tries=0
until exists_remote_file; do
tries=$((tries+1))
log "UPLOAD Try #$tries: $FILE -> ${REMOTE_FILE}"
sftp_batch "reput ${FILE} ${REMOTE_FILE}" "put ${FILE} ${REMOTE_FILE}" || true
sleep $((2*tries))
[[ $tries -ge 5 ]] && break
done
if ! exists_remote_file; then
log "ERROR: Upload fehlgeschlagen"
exit 20
fi
rm -f "$PART" "$TEMP" || true
log "CLEANUP: $TMP"
rm -rf "${TMP:?}/"*
log "=== Done VOD $ID ==="
"
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`.
@@ -735,6 +734,85 @@ In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**. Er sorgt d
> [!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.
8.3 **Finalize-Skript auf dem Nextcloud-Host**
Nachdem der Clipper die VOD-Datei in die Drop-Zone incoming/<VOD_ID> hochgeladen hat, müssen wir diese Dateien an den endgültigen Platz in Nextcloud verschieben. Nur so erscheinen sie auch im Web-Interface. Genau dafür legen wir jetzt ein Skript an, das automatisch aufgerufen werden kann.
Das Skript übernimmt drei Aufgaben:
- Dateien aus der Drop-Zone verschieben in den Zielordner innerhalb von Nextcloud.
- Rechte setzen, damit Nextcloud (Benutzer www-data) die Dateien verwalten kann.
- Den Nextcloud-Dateibaum mit occ files:scan aktualisieren, damit die Dateien sofort sichtbar werden.
Wie zuvor müssen wir ein Konfigurationsdatei anlegen.
```bash
nano /etc/nc_uploader.conf
```
Fülle sie mit:
```bash
NC_USER=DEIN_NC_USER # Nextcloud-Benutzer, dem die Dateien gehören sollen
NC_TARGET_SUBPATH="Medien/VODs" # Zielordner innerhalb von Nextcloud (wie er im Web erscheint)
NC_DATA="/var/www/nextcloud/data" # Basis-Datenverzeichnis deiner Nextcloud-Instanz
DROP_BASE="/home/sftp_uploader/incoming" # SFTP-Drop-Zone von sftp_uploader
PHP="/usr/bin/php"
OCC="/var/www/nextcloud/occ"
```
Speichere die Datei wieder mit `STRG + O` und schließe den Editor mit `STRG + x`.
Das folgende Skript sorgt dann dafür. dass unser eben hoch geladendes VOD an der richtigen Stelle zu finden ist und über die Weboberfläche erreichbar sein wird.
```bash
nano /usr/local/bin/nc_finalize_vod.sh
```
Inhalt:
```bash
# /usr/local/bin/nc_finalize_vod.sh
#!/usr/bin/env bash
set -euo pipefail
CONF="/etc/nc_uploader.conf"
[[ -f "$CONF" ]] || { echo "Config fehlt: $CONF" >&2; exit 1; }
# shellcheck disable=SC1090
source "$CONF"
VOD_ID="${1:?need VOD id}"
FILE_BASENAME="${2:-${VOD_ID}.mp4}"
SRC_DIR="${DROP_BASE}/${VOD_ID}"
SRC_FILE="${SRC_DIR}/${FILE_BASENAME}"
DST_DIR="${NC_DATA}/${NC_USER}/files/${NC_TARGET_SUBPATH}/${VOD_ID}"
SCAN_PATH="${NC_USER}/files/${NC_TARGET_SUBPATH}/${VOD_ID}"
mkdir -p "$DST_DIR"
if [[ -d "$SRC_DIR" ]]; then
# kompletter VOD-Ordner vorhanden → verschiebe Inhalt (oder Ordner, falls leer)
shopt -s nullglob dotglob
if compgen -G "${SRC_DIR}/*" > /dev/null; then
mv -f "${SRC_DIR}/"* "$DST_DIR"/
fi
rmdir "$SRC_DIR" 2>/dev/null || true
elif [[ -f "$SRC_FILE" ]]; then
mv -f "$SRC_FILE" "$DST_DIR"/
else
echo "Quelle nicht gefunden: $SRC_DIR oder $SRC_FILE" >&2
exit 2
fi
chown -R www-data:www-data "$DST_DIR"
"$PHP" "$OCC" files:scan --path="$SCAN_PATH" --quiet
echo "OK: ${DST_DIR}"
```
Wie zuvor auch, müssen wir die Rechte korrekt setzen, damit alles reibungslos funktioniert.
Gebe dazu in der Konsole
```bash
chmod 755 /usr/local/bin/nc_finalize_vod.sh
chown root:root /usr/local/bin/nc_finalize_vod.sh
```
ein.
Im weiteren Verlauf erstellen wir dann einen Node, der dieses Skript aufruft. Im Anschluss sollte das VOD in dem entsprechenden Ordner landen.
9. **Merge Combine** (Node-Name: `Select VODs to Download`)
- **Node-Typ:** Merge
- **Mode:** Combine
@@ -772,13 +850,24 @@ In diesem Schritt erstellen wir den eigentlichen Workflow in **n8n**. Er sorgt d
```bash
<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?
13. **SSH Node 3 Finalize** (Node-Name: Finalize VOD)
- Node-Typ: SSH
- Credentials: SSH Nextcloud (nc_runner)
- Operation: Execute Command
- Command is an Expression: ON
- Command:
```bash
/usr/local/bin/nc_finalize_vod.sh {{$('Down 'n' Up').item.json.vodId}} {{$('Down 'n' Up').item.json.filename}}
```
Diese 12 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
```bash
--- *SSH Check State* --- *Set File Information* --- *Set vods in Array* --- *Split Out vods* ------
--- **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)
**Cron Alle 10 Min** ---- | **Select VODs to Download** --- **Einzeldurchlauf** --- **State Datei schreiben** --- **Down 'n' Up** --- **Finalize VOD** (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* --------------------------------------------------
```