#!/usr/bin/env bash
#
# Piggy YouTube sign-in helper
# =============================
#
# WHAT THIS DOES
#   YouTube sometimes refuses to serve video to a program or user that isn't
#   signed in, and asks for "sign in to confirm you're not a bot". This script
#   asks a web browser on this computer that is ALREADY signed into YouTube
#   for its saved authentication cookies and writes those to a file named
#   "cookies.txt". You then upload that file on Piggy's Settings page, and
#   Piggy uses it to download videos using your logged in account.
#
# WHAT THIS DOES NOT DO
#   - It never asks you for your YouTube or Google password.
#   - It never sends anything anywhere by itself. It only reads cookies your
#     browser already saved on this computer, and writes them to a file you
#     choose to upload.
#   - It doesn't install a browser extension, and doesn't change anything
#     about your browser.
#
# BEFORE YOU RUN THIS
#   Make sure you're signed into youtube.com in one of these browsers on
#   THIS computer: Firefox, Chrome, Brave, Edge, or (Mac only) Safari.
#
# HOW TO RUN THIS (macOS or Linux)
#   1. Open the Terminal app.
#   2. Type the following and press Enter (adjust the path if you saved
#      this file somewhere other than Downloads):
#         bash ~/Downloads/youtube-cookies-helper.sh
#   3. If your Mac asks permission to read a browser's saved logins/keychain,
#      that's expected -- click "Allow".
#   4. When it finishes, go to Piggy's Settings page and upload the
#      cookies.txt file it mentions.
#
# A NOTE ON PRIVACY
#   cookies.txt grants access to your YouTube/Google session, similar to a
#   password. Don't share it or post it anywhere. Piggy only uses it to talk
#   to YouTube on your behalf. Piggy will NEVER share your data.

set -eo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
out_file="$script_dir/cookies.txt"
work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT

echo "Piggy YouTube sign-in helper"
echo "-----------------------------"

# ---------------------------------------------------------------------------
# Step 1: find or download yt-dlp, the tool that reads browser cookies.
# Piggy itself uses yt-dlp to talk to YouTube, so this reuses the same tool.
# ---------------------------------------------------------------------------
if command -v yt-dlp >/dev/null 2>&1; then
  ytdlp="$(command -v yt-dlp)"
  echo "Found yt-dlp already installed: $ytdlp"
else
  # Cached in a stable, persistent location rather than this run's throwaway
  # temp dir: on macOS, Keychain access grants (and Gatekeeper trust) are
  # tied to a specific binary's identity/path. A fresh, differently-located
  # binary on every run looks like a brand-new, never-seen app each time,
  # which can mean re-prompting indefinitely -- or macOS just declining to
  # ask at all after enough "new" requests. Reusing the same cached binary
  # lets "always allow" actually stick across runs.
  cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/piggy-youtube-helper"
  mkdir -p "$cache_dir"
  ytdlp="$cache_dir/yt-dlp"

  if [ -x "$ytdlp" ]; then
    echo "Using previously downloaded yt-dlp: $ytdlp"
  else
    os="$(uname -s)"
    arch="$(uname -m)"
    case "$os" in
      Darwin)
        asset="yt-dlp_macos"
        ;;
      Linux)
        if [ "$arch" = "aarch64" ] || [ "$arch" = "arm64" ]; then
          asset="yt-dlp_linux_aarch64"
        else
          asset="yt-dlp_linux"
        fi
        ;;
      *)
        echo "Sorry, this script only supports macOS and Linux (found: $os)." >&2
        exit 1
        ;;
    esac

    url="https://github.com/yt-dlp/yt-dlp/releases/latest/download/$asset"
    echo "Downloading yt-dlp (one-time; cached at $ytdlp for next time)..."
    if ! curl -fsSL "$url" -o "$ytdlp"; then
      rm -f "$ytdlp"
      echo "Could not download yt-dlp from $url -- check your internet connection and try again." >&2
      exit 1
    fi
    chmod +x "$ytdlp"
  fi
fi

# ---------------------------------------------------------------------------
# Step 2: try each browser in the list until one has YouTube cookies yt-dlp
# can read. A fixed, permanent, public video is used only to trigger cookie
# loading -- nothing is downloaded or watched.
# ---------------------------------------------------------------------------
# "Me at the zoo" -- the first video ever uploaded to YouTube.
probe_url="https://www.youtube.com/watch?v=jNQXAC9IVRw"
browsers=(firefox chrome brave edge)
if [ "$(uname -s)" = "Darwin" ]; then
  browsers+=(safari)
fi

found=""
diagnostics=""
for browser in "${browsers[@]}"; do
  echo "Trying ${browser}..."
  raw_file="$work_dir/${browser}.raw.txt"
  err_file="$work_dir/${browser}.err.txt"

  # The probe video can fail to resolve a playable format for reasons that
  # have nothing to do with whether the cookies themselves are good, so a
  # nonzero exit here isn't necessarily a failure worth stopping over.
  "$ytdlp" --cookies-from-browser "$browser" --cookies "$raw_file" \
      --skip-download --simulate --quiet --no-warnings "$probe_url" 2>"$err_file" || true

  # A real "you're not signed in" rejection means these cookies are no good.
  #
  # Anything else that went wrong (most commonly: yt-dlp couldn't pick a
  # playable *format* for this specific probe video) is irrelevant -- this
  # script's only job is to provide the cookies get past the sign-in page, so
  # a real cookie file is accepted even if the probe command's overall exit
  # code was nonzero.
  if ! grep -qi "sign in to confirm" "$err_file" 2>/dev/null && [ -s "$raw_file" ]; then
    filtered_file="$work_dir/${browser}.filtered.txt"
    # yt-dlp's --cookies-from-browser dumps the browser's WHOLE cookie jar, we
    # need only YouTube sign-in cookies. Domain alone isn't a tight enough
    # filter: .google.com is used by MANY services. So this also requires the
    # cookie NAME to be one of the specific ones YouTube's bot-check actually
    # reads. "#HttpOnly_" is a standard prefix on the domain field marking an
    # HttpOnly cookie, not a comment -- strip it only to test the domain, the
    # original line (prefix included) is what gets kept.
    {
      echo "# Netscape HTTP Cookie File"
      echo "# Filtered by Piggy's sign-in helper: YouTube sign-in cookies only."
      awk -F'\t' '{
        domain = $1
        sub(/^#HttpOnly_/, "", domain)
        name = $6
        if (domain ~ /^(youtube\.com|\.youtube\.com|www\.youtube\.com|google\.com|\.google\.com|accounts\.google\.com)$/ &&
            name ~ /^(SID|HSID|SSID|APISID|SAPISID|SIDCC|LOGIN_INFO|PREF|VISITOR_INFO1_LIVE|YSC|CONSENT|ACCOUNT_CHOOSER|__Secure-[13]P(API)?SID(CC|TS)?)$/) print
      }' "$raw_file"
    } > "$filtered_file"

    if [ "$(wc -l < "$filtered_file")" -gt 2 ]; then
      cp "$filtered_file" "$out_file"
      found="$browser"
      break
    fi
  fi

  err_tail="$(tail -n 2 "$err_file" 2>/dev/null || true)"
  if [ -n "$err_tail" ]; then
    diagnostics="$diagnostics
  $browser: $err_tail"
  fi
done

if [ -z "$found" ]; then
  echo
  echo "Could not read YouTube cookies from any browser on this computer." >&2
  echo "A few things to check:" >&2
  echo "  - Are you signed into youtube.com in Firefox, Chrome, Brave, Edge, or Safari on THIS computer?" >&2
  echo "  - Chrome, Brave, and Edge sometimes lock their cookie file while running --" >&2
  echo "    try closing that browser fully and running this script again." >&2
  echo "  - Safari on macOS needs Terminal to have \"Full Disk Access\": System" >&2
  echo "    Settings -> Privacy & Security -> Full Disk Access -> enable Terminal," >&2
  echo "    then reopen Terminal and try again. (sudo does NOT fix this.)" >&2
  if [ -n "$diagnostics" ]; then
    echo >&2
    echo "What each browser actually said (for troubleshooting):" >&2
    echo "$diagnostics" >&2
  fi
  exit 1
fi

echo
echo "Success! Found working cookies in $found."
echo "Saved to: $out_file"
echo
echo "Next: go to Piggy's Settings page and upload that cookies.txt file."
echo "(Treat it like a password -- don't share it.)"
