#!/bin/bash
# Controlli condivisi dagli script video RoyLead. Si include con:
#   source "$(dirname "$0")/lib_video.sh"
# Sono nati da tre errori reali della stessa giornata: ComfyUI fermo 20 minuti per un
# problema IPv6, un video consegnato muto per 54 secondi, file lasciati in giro.
#
# Variabili d'ambiente (tutte opzionali):
#   RUNPOD_SSH_KEY   chiave privata registrata su RunPod (default ~/.ssh/id_ed25519)

UA="Mozilla/5.0 (X11; Linux x86_64) Chrome/128.0"
_vlog(){ echo "$(date +%T) $*"; }

# Comandi sul pod dal proxy ssh.runpod.io (l'SSH diretto spesso è rifiutato: servono -tt e i
# comandi da stdin). Il terminale ripete i comandi in uscita: chi cerca un marcatore
# nell'output lo deve costruire a runtime (es. "OK_$((1+1))" stampa OK_2), sennò trova il
# comando stesso. Uso: ssh_pod <utente_ssh> '<comandi>'
ssh_pod(){
  local key="${RUNPOD_SSH_KEY:-$HOME/.ssh/id_ed25519}"
  [ -f "$key" ] || { _vlog "SSH_FAILED: chiave $key non trovata (imposta RUNPOD_SSH_KEY)"; return 1; }
  printf '%s\nexit\n' "$2" | timeout 180 ssh -tt -i "$key" -o StrictHostKeyChecking=no \
    -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -o ConnectTimeout=20 "$1@ssh.runpod.io" 2>&1 \
    | tr -d '\r' | sed 's/\x1b\[[0-9;?]*[a-zA-Z]//g'
}

# Aspetta che ComfyUI risponda. Sulle macchine Community senza IPv6 il template lancia
# --listen senza indirizzo e ComfyUI muore con "could not bind on any address": dopo un
# minuto lo si cerca nel log e si rilancia su 0.0.0.0, una volta sola, invece di aspettare
# il timeout. Uso: comfy_attendi <pod_id> <utente_ssh> [timeout_s=1200]
comfy_attendi(){
  local pod=$1 user=$2 max=${3:-1200} base="https://$1-8188.proxy.runpod.net" t0 el relaunched=0
  t0=$(date +%s)
  until [ "$(curl -s -A "$UA" -o /dev/null -w '%{http_code}' --max-time 15 "$base/system_stats")" = 200 ]; do
    el=$(( $(date +%s)-t0 ))
    if [ "$el" -gt "$max" ]; then _vlog "COMFY_FAILED: non risponde dopo ${max}s"; return 1; fi
    if [ $relaunched = 0 ] && [ "$el" -gt 60 ] && \
       ssh_pod "$user" '! pgrep -f "ComfyUI/main.py" > /dev/null && grep -aqs "could not bind on any address" /workspace/comfyui_*.log && echo "IPV6_$((1+1))"' | grep -q 'IPV6_2'; then
      # Solo se ComfyUI è MORTO: /workspace è persistente e la riga può restare da un avvio vecchio,
      # quindi il log da solo farebbe riavviare un ComfyUI sano che sta solo partendo piano.
      _vlog "COMFY_IPV6: ComfyUI non apre la porta (IPv6), lo rilancio su 0.0.0.0"
      ssh_pod "$user" "pkill -f 'ComfyUI/main.py'; sleep 3; cd /ComfyUI && setsid nohup python3 /ComfyUI/main.py --listen 0.0.0.0 --enable-cors-header '*' --use-sage-attention --extra-model-paths-config /ComfyUI/extra_model_paths.yaml >> /workspace/comfyui_manual.log 2>&1 < /dev/null & disown" > /dev/null
      relaunched=1
    fi
    sleep 15
  done
  _vlog "READY ComfyUI risponde dopo $(( $(date +%s)-t0 ))s"
}

# Si ferma se un audio o un video ha un tratto muto più lungo del consentito. Le pause fra
# due battute stanno sotto il secondo; la chiusura finale senza voce si esclude con coda_s.
# Va chiamata sulle battute PRIMA di caricarle sul pod (una voce muta costa un giro di GPU)
# e sul video finale PRIMA di consegnarlo.
# Uso: controlla_audio <file> [max_silenzio_s=1.5] [coda_s=0]
controlla_audio(){
  local f=$1 max=${2:-1.5} coda=${3:-0} dur bad
  if ! ffprobe -v error -select_streams a -show_entries stream=index -of csv=p=0 "$f" | grep -q .; then
    _vlog "AUDIO_FAILED: $f non ha una traccia audio"; return 1
  fi
  dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$f")
  bad=$(ffmpeg -hide_banner -nostats -i "$f" -af "silencedetect=noise=-40dB:d=$max" -f null - 2>&1 | python3 -c '
import re, sys
dur, coda, mx = map(float, sys.argv[1:4])
lim = dur - coda
start, out = None, []
def seg(s, e):
    # Conta solo la parte di silenzio prima della coda esclusa.
    if min(e, lim) - s > mx:
        out.append(f"{s:.1f}-{e:.1f}s")
for line in sys.stdin:
    m = re.search(r"silence_start: ([0-9.]+)", line)
    if m:
        start = float(m.group(1))
    m = re.search(r"silence_end: ([0-9.]+)", line)
    if m and start is not None:
        seg(start, float(m.group(1)))
        start = None
if start is not None:
    seg(start, dur)
print("SILENZI:" + " ".join(out))
' "$dur" "$coda" "$max")
  # Senza il marcatore il controllo stesso è andato storto (ffmpeg o python): non si dà per buono.
  case "$bad" in
    "SILENZI:") ;;
    SILENZI:*) _vlog "AUDIO_FAILED: tratti muti in $f: ${bad#SILENZI:}"; return 1 ;;
    *) _vlog "AUDIO_FAILED: controllo non riuscito su $f (durata: '$dur')"; return 1 ;;
  esac
  _vlog "AUDIO_OK: $(basename "$f") senza silenzi oltre ${max}s (coda esclusa ${coda}s)"
}

# Trova un font grassetto per testi e sottotitoli: prima quello indicato in FONT_BOLD, poi i
# più comuni su Linux, poi Arial di Windows (da WSL). Stampa il percorso, oppure fallisce.
# Uso: font=$(trova_font) || exit 1
trova_font(){
  local f
  for f in "${FONT_BOLD:-}" \
           /usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf \
           /usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf \
           /usr/share/fonts/TTF/DejaVuSans-Bold.ttf \
           /mnt/c/Windows/Fonts/arialbd.ttf; do
    [ -n "$f" ] && [ -f "$f" ] && { echo "$f"; return 0; }
  done
  _vlog "FONT_FAILED: nessun font grassetto trovato (imposta FONT_BOLD=/percorso/font.ttf)"; return 1
}

# Copia una cartella su una destinazione qualsiasi (un altro disco, una cartella sincronizzata
# con il cloud) e controlla nome e dimensione di ogni file. Con --cancella, e SOLO se tutto
# combacia, cancella la copia locale.
# Uso: copia_verificata <cartella_locale> <cartella_destinazione> [--cancella]
copia_verificata(){
  local src=$1 dst=$2 mode=$3 n=0 bad=0 rel
  [ -d "$src" ] || { _vlog "COPIA_FAILED: $src non esiste"; return 1; }
  mkdir -p "$dst" && cp -r "$src"/. "$dst"/ || { _vlog "COPIA_FAILED: copia in $dst non riuscita"; return 1; }
  while IFS= read -r -d '' f; do
    n=$((n+1)); rel=${f#"$src"/}
    [ -f "$dst/$rel" ] && [ "$(stat -c %s "$f")" = "$(stat -c %s "$dst/$rel")" ] || { echo "MANCA $rel"; bad=$((bad+1)); }
  done < <(find "$src" -type f -print0)
  if [ "$n" = 0 ] || [ "$bad" != 0 ]; then _vlog "COPIA_FAILED: file=$n diversi=$bad, la cartella locale resta dov'è"; return 1; fi
  if [ "$mode" = "--cancella" ]; then
    rm -rf "$src"; _vlog "COPIA_OK: $n file verificati in $dst, copia locale cancellata"
  else
    _vlog "COPIA_OK: $n file verificati in $dst (copia locale tenuta)"
  fi
}
