#!/usr/bin/env bash # # Caption Tool installer # # One-command install (host this file, then): # curl -fsSL https://oohfixer.com/caption-tool/install.sh | bash # # Local install (run from this folder): # bash install.sh # # Environment overrides: # CAPTION_TOOL_BASE -> base URL the files are served from (download mode) # CAPTION_TOOL_DIR -> install location (default ~/.local/share/caption_tool) set -euo pipefail BASE_URL="${CAPTION_TOOL_BASE:-https://oohfixer.com/caption-tool}" INSTALL_DIR="${CAPTION_TOOL_DIR:-$HOME/.local/share/caption_tool}" BIN_DIR="$HOME/.local/bin" VENV="$INSTALL_DIR/.venv" info() { printf '%s\n' "$1"; } err() { printf 'Error: %s\n' "$1" >&2; } # Ask a yes/no question on the terminal so it works even when this script is # piped in via curl (where stdin is the script itself, not the keyboard). prompt_yes_no() { local ans if [ -r /dev/tty ]; then read -r -p "$1 [y/N] " ans < /dev/tty || ans="" else read -r -p "$1 [y/N] " ans || ans="" fi case "$ans" in y|Y|yes|YES|Yes) return 0 ;; *) return 1 ;; esac } # Best-effort install of Python 3.13 via the system package manager. install_python() { local os_id="" if [ -f /etc/os-release ]; then # shellcheck disable=SC1091 os_id="$(. /etc/os-release && echo "$ID")" fi case "$os_id" in ubuntu|debian|linuxmint|pop|raspbian|kali) sudo apt-get update if ! sudo apt-get install -y python3.13 python3.13-venv; then sudo apt-get install -y software-properties-common sudo add-apt-repository -y ppa:deadsnakes/ppa sudo apt-get update sudo apt-get install -y python3.13 python3.13-venv fi ;; fedora|rhel|centos|rocky|almalinux) sudo dnf install -y python3.13 ;; arch|manjaro) err "Arch-based systems do not provide older Python easily." info "Install python-3.13 from the AUR, then re-run this installer." return 1 ;; *) if command -v brew >/dev/null 2>&1; then brew install python@3.13 else err "Could not detect your OS package manager." info "Install Python 3.13 manually (https://www.python.org/downloads/), then re-run." return 1 fi ;; esac } # --- 1. Locate or install a suitable Python -------------------------------- PYBIN="" if command -v python3 >/dev/null 2>&1; then PYVER="$(python3 --version 2>&1 | sed 's/Python //')" PYMAJ="$(printf '%s' "$PYVER" | cut -d. -f1)" PYMIN="$(printf '%s' "$PYVER" | cut -d. -f2)" if [ "$PYMAJ" -gt 3 ] || { [ "$PYMAJ" -eq 3 ] && [ "$PYMIN" -ge 14 ]; }; then if prompt_yes_no "Python $PYVER is installed, but Caption Tool needs 3.13 or older. Install Python 3.13 now?"; then install_python || true PYBIN="$(command -v python3.13 || true)" fi else PYBIN="$(command -v python3)" fi else if prompt_yes_no "Python 3 was not found. Install Python 3.13 now?"; then install_python || true PYBIN="$(command -v python3.13 || command -v python3 || true)" fi fi if [ -z "$PYBIN" ]; then err "A Python 3.13 (or older) interpreter is required." info "Install it, then re-run: bash install.sh" exit 1 fi # Re-verify the chosen interpreter is acceptable. PYVER="$("$PYBIN" --version 2>&1 | sed 's/Python //')" PYMAJ="$(printf '%s' "$PYVER" | cut -d. -f1)" PYMIN="$(printf '%s' "$PYVER" | cut -d. -f2)" if [ "$PYMAJ" -gt 3 ] || { [ "$PYMAJ" -eq 3 ] && [ "$PYMIN" -ge 14 ]; }; then err "Python $PYVER is still too new. Caption Tool requires 3.13 or older." exit 6 fi # --- 2. Locate the source files (local copy or download) -------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-.}")" && pwd)" if [ -f "$SCRIPT_DIR/caption.py" ]; then SRC_MODE="local" SRC="$SCRIPT_DIR" else SRC_MODE="download" SRC="$BASE_URL" fi # --- 3. Create install dir + virtual environment ---------------------------- info "Installing Caption Tool" info " Location: $INSTALL_DIR" info "" info "Step 1/5 Preparing the isolated Python environment..." mkdir -p "$INSTALL_DIR" if [ ! -d "$VENV" ]; then "$PYBIN" -m venv "$VENV" fi # --- 4. Fetch the tool files ------------------------------------------------- info "Step 2/5 Getting the tool files..." if [ "$SRC_MODE" = "local" ]; then cp "$SRC/caption.py" "$INSTALL_DIR/" cp "$SRC/caption_config.json" "$INSTALL_DIR/" cp "$SRC/requirements.txt" "$INSTALL_DIR/" else curl -fsSL "$SRC/caption.py" -o "$INSTALL_DIR/caption.py" curl -fsSL "$SRC/caption_config.json" -o "$INSTALL_DIR/caption_config.json" curl -fsSL "$SRC/requirements.txt" -o "$INSTALL_DIR/requirements.txt" fi # --- 5. Install dependencies ------------------------------------------------- info "Step 3/5 Installing dependencies (this can take a few minutes)..." "$VENV/bin/pip" install --quiet --upgrade pip "$VENV/bin/pip" install --quiet -r "$INSTALL_DIR/requirements.txt" # --- 6. Create the global 'captions' command --------------------------------- info "Step 4/5 Creating the 'captions' command..." mkdir -p "$BIN_DIR" cat > "$BIN_DIR/captions" <> "$RC" fi NEED_RESTART=1 fi # --- 8. Done ----------------------------------------------------------------- info "Step 5/5 Done." info "" info "Caption Tool is installed." if [ "$NEED_RESTART" = "1" ]; then info "Run the next line (or open a new terminal) to use 'captions' anywhere:" info " source $RC" else info "The command 'captions' is ready to use now." fi info "" info "Start captioning: captions" info "Or point at a folder: captions --path \"/path/to/images\""