diff --git a/Kapitel 13/Tutorial.md b/Kapitel 13/Tutorial.md index efa0805..5811d66 100644 --- a/Kapitel 13/Tutorial.md +++ b/Kapitel 13/Tutorial.md @@ -1210,3 +1210,137 @@ curl -fsSL https://git.bratonien.de/Thomas/Homelab--Bratonein-Kontrollzentrum--T Alternativ kann die Datei auch manuell heruntergeladen und dort abgelegt werden. Die Datei enthält eine Liste von z. B. bekannten Anime-Namen – eine pro Zeile. + +Um nun die Clips zu schneiden, benötigen wir ein weiteres Skript und einen weiteren Node. +Lege mit ```nano /bin/clipper-cut-vod ``` die benötigte Datei an und fülle sie mit dem folgenden COde: + +```bash +#!/bin/bash + + +VOD_ID="$1" +# Abschnitt 1: Namensmodus erkennen + +ETC_DIR="/srv/clipper/etc" +CODE_POOL="$ETC_DIR/codename_pool.txt" +ADJ_POOL="$ETC_DIR/adjektive_de.txt" + +# Standardmodus +NAMING_MODE="fallback" + +if [[ -s "$CODE_POOL" && -s "$ADJ_POOL" ]]; then + NAMING_MODE="adjektiv_codename" +elif [[ -s "$CODE_POOL" ]]; then + NAMING_MODE="codename" +fi + +echo "[INFO] Namensmodus erkannt: $NAMING_MODE" + +# Abschnitt 2: Namen wählen (robust & ohne Wiederholung) + +USED_PATH="/srv/clipper/etc/used.json" +mkdir -p "$(dirname "$USED_PATH")" +touch "$USED_PATH" +USED_LIST=$(jq -r '.[]' "$USED_PATH" 2>/dev/null || echo "") + +is_used() { + grep -Fxq "$1" <<< "$USED_LIST" +} + +choose_final_name() { + case "$NAMING_MODE" in + "codename") + mapfile -t CANDIDATES < "$CODE_POOL" + ;; + "adjektiv_codename") + mapfile -t CODES < "$CODE_POOL" + mapfile -t ADJS < "$ADJ_POOL" + CANDIDATES=() + for adj in "${ADJS[@]}"; do + for code in "${CODES[@]}"; do + CANDIDATES+=("${adj}-${code}") + done + done + ;; + "fallback") + echo "$VOD_ID" + return 0 + ;; + esac + + # Filtere bereits genutzte Namen + AVAILABLE=() + for name in "${CANDIDATES[@]}"; do + if ! is_used "$name"; then + AVAILABLE+=("$name") + fi + done + + if [[ ${#AVAILABLE[@]} -eq 0 ]]; then + echo "[WARN] Keine verfügbaren Namen mehr – nutze Fallback: $VOD_ID" + echo "$VOD_ID" + else + FINAL_NAME="${AVAILABLE[RANDOM % ${#AVAILABLE[@]}]}" + echo "[INFO] Gewählter Codename: $FINAL_NAME" + echo "$FINAL_NAME" + fi +} + +# Codename in used.json speichern (wenn nicht fallback) +if [[ "$FINAL_NAME" != "$VOD_ID" ]]; then + if jq -e . >/dev/null 2>&1 <<< "$USED_LIST"; then + UPDATED=$(jq --arg name "$FINAL_NAME" '. + [$name]' <<< "$USED_LIST") + else + UPDATED="[$(printf '%s\n' "$USED_LIST" | jq -R . | jq -s .), \"$FINAL_NAME\"]" + fi + echo "$UPDATED" > "$USED_PATH" +fi + +# Verzeichnisstruktur +TMP_DIR="/srv/clipper/temp/$VOD_ID" +VOD_PATH="/srv/clipper/out/$VOD_ID/original/$VOD_ID.mp4" +CANDIDATES_JSON="$TMP_DIR/candidates.json" +CLIPS_DIR="/srv/clipper/out/$VOD_ID/clips" + +mkdir -p "$CLIPS_DIR/combined" +mkdir -p "$CLIPS_DIR/audio" +mkdir -p "$CLIPS_DIR/video" + +# Ziel für temporären CSV-Index +INDEX_CSV="$TMP_DIR/index.csv" +echo "Typ;Quelle;Beginn;Ende;Dateiname;Pfad" > "$INDEX_CSV" + +CLIP_NUM=1 + +for SECTION in combined only_audio only_video; do + case "$SECTION" in + combined) SUBDIR="kombiniert"; QUELLE="kombiniert" ;; + only_audio) SUBDIR="audio"; QUELLE="audio" ;; + only_video) SUBDIR="video"; QUELLE="video" ;; + esac + + mkdir -p "$CLIPS_DIR/$SUBDIR" + + jq -c ".$SECTION[]" "$CANDIDATES_JSON" | while read -r clip; do + START=$(jq -r '.start' <<< "$clip") + END=$(jq -r '.end' <<< "$clip") + DURATION=$(awk "BEGIN { printf \"%.2f\", $END - $START }") + + OUT_NAME=$(printf "%03d_%s.mp4" "$CLIP_NUM" "$FINAL_NAME") + OUT_PATH="$CLIPS_DIR/$SUBDIR/$OUT_NAME" + + echo "[INFO] Schneide Clip $OUT_NAME ($START - $END → $DURATION s)" + ffmpeg -hide_banner -loglevel error -ss "$START" -i "$VOD_PATH" -t "$DURATION" -c copy "$OUT_PATH" + + # Zeitformat HH:MM:SS + START_FMT=$(date -u -d "@$START" +"%H:%M:%S") + END_FMT=$(date -u -d "@$END" +"%H:%M:%S") + + echo "Clip;$QUELLE;$START_FMT;$END_FMT;$OUT_NAME;clips/$SUBDIR/" >> "$INDEX_CSV" + + CLIP_NUM=$((CLIP_NUM + 1)) + done +done +``` + +