#!/bin/zsh
# grabmedia <audio|video> <url> [start] [end]
# start/end are yt-dlp timestamps, e.g. 1:30 1:45 (or 90 105). Works for both kinds.
# Shared download engine for the YT Grab app and the ytmp3/ytmp4/ytclip commands.
# Handles YouTube, Instagram, and anything else yt-dlp supports.

export PATH=/opt/homebrew/bin:/usr/local/bin:$PATH

KIND="$1"
URL="$2"
START="$3"
END="$4"

if [ -z "$URL" ]; then
  echo "usage: grabmedia <audio|video> <url> [start] [end]"
  exit 1
fi

# --- destination: Sound-Effects on the X9 when mounted, else ~/Downloads/YT
DRIVE="${GRAB_DRIVE:-/Volumes/Crucial X9}"
if [ -d "$DRIVE" ] && [ -w "$DRIVE" ]; then
  DEST="$DRIVE/Sound-Effects"
else
  DEST="$HOME/Downloads/YT"
fi
mkdir -p "$DEST"

# --- filename template. Instagram posts usually have no title, so use the
#     account name + post id instead of an empty filename.
case "$URL" in
  *instagram.com*|*facebook.com*|*threads.net*)
    OUTTPL="$DEST/%(uploader,channel,id)s_%(id)s.%(ext)s"
    ;;
  *)
    if [ -n "$START" ] && [ -n "$END" ]; then
      OUTTPL="$DEST/%(title).60s_clip.%(ext)s"
    else
      OUTTPL="$DEST/%(title).80s.%(ext)s"
    fi
    ;;
esac

# --- build the yt-dlp arguments
# YouTube's default "android_vr" client currently 403s on the actual video
# data even though it extracts metadata fine. Pin a client order that still
# works without a PO token (web first, tv_simply/android as fallback).
typeset -a ARGS
ARGS=( --no-playlist --restrict-filenames --embed-metadata -o "$OUTTPL"
       --extractor-args "youtube:player_client=web,tv_simply,android" )

if [ "$KIND" = "audio" ]; then
  ARGS+=( -x --audio-format mp3 --audio-quality 0 --embed-thumbnail )
  if [ -n "$START" ] && [ -n "$END" ]; then
    ARGS+=( --download-sections "*${START}-${END}" )
  fi
else
  # H.264/AAC in a real mp4 so Final Cut can import it directly.
  ARGS+=( -f "bv*[vcodec^=avc1]+ba[ext=m4a]/b[ext=mp4]/bv*+ba/b"
          --merge-output-format mp4 )
  if [ -n "$START" ] && [ -n "$END" ]; then
    ARGS+=( --download-sections "*${START}-${END}" --force-keyframes-at-cuts )
  fi
fi

# Grab the whole thing, then trim locally with ffmpeg. Slower, but it never
# hits the 403 that YouTube throws when ffmpeg fetches byte ranges directly.
full_then_trim() {
  typeset -a FARGS
  FARGS=( --no-playlist --restrict-filenames
          --extractor-args "youtube:player_client=web,tv_simply,android"
          -o "$DEST/%(title).60s.%(ext)s" )
  local exec_cmd
  if [ "$KIND" = "audio" ]; then
    FARGS+=( -x --audio-format mp3 --audio-quality 0 )
    exec_cmd="f={}; ffmpeg -y -loglevel error -ss ${START} -to ${END} -i \"\$f\""
    exec_cmd="$exec_cmd -c:a libmp3lame -q:a 0 \"\${f%.*}_clip.mp3\" && rm -f \"\$f\""
  else
    FARGS+=( -f "bv*[vcodec^=avc1]+ba[ext=m4a]/b[ext=mp4]/bv*+ba/b"
             --merge-output-format mp4 )
    exec_cmd="f={}; ffmpeg -y -loglevel error -ss ${START} -to ${END} -i \"\$f\""
    exec_cmd="$exec_cmd -c:v libx264 -crf 18 -preset veryfast -pix_fmt yuv420p"
    exec_cmd="$exec_cmd -c:a aac \"\${f%.*}_clip.mp4\" && rm -f \"\$f\""
  fi
  yt-dlp "${FARGS[@]}" --exec "$exec_cmd" "$@" "$URL"
}

# --- run, retrying with browser cookies for login-walled sites
try_run() {
  yt-dlp "${ARGS[@]}" "$@" "$URL"
}

IS_CLIP=0
[ -n "$START" ] && [ -n "$END" ] && IS_CLIP=1

if [ "$IS_CLIP" = "1" ] && [ -n "$GRAB_FORCE_FULL" ]; then
  : # testing hook: skip the fast path entirely
elif try_run; then
  echo "-> $DEST"
  exit 0
fi

if [ "$IS_CLIP" = "1" ]; then
  echo "Section download failed, grabbing the full file and trimming locally…"
  if full_then_trim; then
    echo "-> $DEST"
    exit 0
  fi
fi

case "$URL" in
  *instagram.com*|*facebook.com*|*threads.net*)
    for b in brave chrome safari; do
      echo "Retrying with $b cookies…"
      if try_run --cookies-from-browser "$b"; then
        echo "-> $DEST"
        exit 0
      fi
    done
    echo ""
    echo "Instagram refused the download."
    echo "Log into Instagram in Brave or Chrome, then try again —"
    echo "most Reels need a logged-in session."
    exit 1
    ;;
esac

exit 1
