← back to Rentv Tour

batch-pitch.sh

40 lines

#!/bin/bash
cd /Users/macstudio3/Projects/rentv-tour
SAY=~/.claude/skills/clone-voice/scripts/say.sh
AV_LOOK=b2105c3cc1fd4464b11cd24c417b5751
for id in $(node pitch-set.mjs ids); do
  echo "=== $id ==="
  txt=$(node pitch-set.mjs vo $id)
  bash $SAY "$txt" /tmp/pv-$id.wav >/dev/null 2>&1
  ffmpeg -v error -y -i /tmp/pv-$id.wav -c:a aac -b:a 160k videos/pitch/assets/vo.m4a >/dev/null 2>&1
  dur=$(ffprobe -v error -show_entries format=duration -of default=nk=1:nw=1 videos/pitch/assets/vo.m4a)
  echo "  VO ${dur}s"
  node pitch-set.mjs emit $id $dur >/dev/null 2>&1
  (cd videos/pitch && npx hyperframes render --output renders/$id-base.mp4 >/dev/null 2>&1)
  echo "  base rendered"
  # 15s avatar intro
  ffmpeg -v error -y -t 15 -i /tmp/pv-$id.wav -c:a libmp3lame -b:a 192k /tmp/pv15-$id.mp3 >/dev/null 2>&1
  AID=$(heygen asset create --file /tmp/pv15-$id.mp3 2>/dev/null | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"]["asset_id"])' 2>/dev/null)
  VID=$(heygen video create -d "{\"type\":\"avatar\",\"avatar_id\":\"$AV_LOOK\",\"audio_asset_id\":\"$AID\",\"aspect_ratio\":\"1:1\",\"title\":\"$id intro\"}" 2>/dev/null | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"]["video_id"])' 2>/dev/null)
  echo "  avatar VID=$VID"
  for i in $(seq 1 24); do
    S=$(heygen video get $VID 2>/dev/null | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"].get("status",""))' 2>/dev/null)
    if [ "$S" = "completed" ]; then
      URL=$(heygen video get $VID 2>/dev/null | python3 -c 'import sys,json;print(json.load(sys.stdin)["data"].get("video_url",""))' 2>/dev/null)
      curl -s -o /tmp/pav-$id.mp4 "$URL"; echo "  avatar downloaded"; break
    fi
    [ "$S" = "failed" ] && { echo "  avatar FAILED"; break; }
    node -e 'setTimeout(()=>{},10000)' 2>/dev/null
  done
  # composite: circular PIP over first 15s, base audio (full VO)
  if [ -f /tmp/pav-$id.mp4 ]; then
    ffmpeg -v error -y -i videos/pitch/renders/$id-base.mp4 -i /tmp/pav-$id.mp4 -filter_complex \
    "[1:v]scale=340:340,format=rgba,geq=r='r(X,Y)':g='g(X,Y)':b='b(X,Y)':a='if(gt((X-170)*(X-170)+(Y-170)*(Y-170),165*165),0,255)'[pip];[0:v][pip]overlay=W-w-56:H-h-56:enable='lte(t,15)':format=auto[v]" \
    -map "[v]" -map 0:a -c:v libx264 -preset medium -crf 20 -c:a aac -b:a 192k -pix_fmt yuv420p videos/pitch/renders/$id.mp4 >/dev/null 2>&1
    echo "  FINAL $id.mp4 ($(ls -la videos/pitch/renders/$id.mp4|awk '{printf "%.1fMB",$5/1048576}'))"
  else
    cp videos/pitch/renders/$id-base.mp4 videos/pitch/renders/$id.mp4; echo "  (no avatar — used base)"
  fi
done
echo "PITCH BATCH DONE"