#!/bin/bash # Snap It installer. Downloads the prebuilt universal app, puts it in # /Applications and launches it. No Xcode, no toolchain, no compile. # # curl -fsSL https://snap-it-bheng.vercel.app/install.sh | bash # # Building from source is still fully supported: see the README. set -euo pipefail APP="Snap It" REPO="bunlongheng/snap-it" ASSET="Snap-It-universal.zip" URL="https://github.com/$REPO/releases/latest/download/$ASSET" MIN_MAJOR=13 if [ -t 1 ]; then B=$'\033[1m'; D=$'\033[2m'; R=$'\033[0m'; else B=; D=; R=; fi say() { printf '%s\n' "$*"; } die() { printf '\n%serror:%s %s\n\n' "${B}" "${R}" "$*" >&2; exit 1; } # --- 1. is this Mac supported ------------------------------------------------ [ "$(uname -s)" = "Darwin" ] || die "Snap It is a macOS app; this is $(uname -s)." os="$(sw_vers -productVersion)" major="${os%%.*}" case "$major" in 13) name="Ventura" ;; 14) name="Sonoma" ;; 15) name="Sequoia" ;; 26) name="Tahoe" ;; *) name="" ;; esac if [ "$major" -lt "$MIN_MAJOR" ]; then die "Snap It needs macOS 13 Ventura or newer. This Mac is on macOS $os." fi say "" say "${B}Snap It${R} ${D}- macOS $os${name:+ $name}, $(uname -m)${R}" # --- 2. download ------------------------------------------------------------- tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT say " downloading" curl -fsSL --retry 3 --connect-timeout 20 "$URL" -o "$tmp/$ASSET" \ || die "could not download $URL Check your connection, or build from source: git clone https://github.com/$REPO && cd snap-it && make install" # A 404 page or an HTML error would also land here, so confirm it is a zip. head -c 2 "$tmp/$ASSET" | grep -q PK || die "the download was not a zip file. Try again in a moment." # --- 3. unpack --------------------------------------------------------------- # ditto is the only unpacker that keeps a bundle's code signature intact. ditto -x -k "$tmp/$ASSET" "$tmp/unpacked" || die "could not unpack the download." [ -d "$tmp/unpacked/$APP.app" ] || die "the download did not contain $APP.app." # --- 4. choose a destination ------------------------------------------------- dest="/Applications" if [ ! -w "$dest" ]; then dest="$HOME/Applications" mkdir -p "$dest" say " ${D}/Applications is not writable, installing to ~/Applications instead${R}" fi # --- 5. replace any existing copy -------------------------------------------- osascript -e "quit app \"$APP\"" >/dev/null 2>&1 || true rm -rf "$dest/$APP.app" mv "$tmp/unpacked/$APP.app" "$dest/$APP.app" || die "could not write to $dest." # The app is signed but not notarized, so macOS would block a downloaded copy # until the quarantine flag is cleared. Clearing it is what a right click and # Open does, without making you hunt through Settings for the Open Anyway button. xattr -dr com.apple.quarantine "$dest/$APP.app" 2>/dev/null || true say " installed ${B}$dest/$APP.app${R}" # --- 6. launch and confirm it really came up --------------------------------- # Snap It is LSUIElement, so it has no Dock icon, no window and no entry in the # app switcher. Launching it looks exactly like nothing happening, which is why # this waits for the process and then says where to look. open "$dest/$APP.app" || die "installed, but could not launch it. Open it from $dest." running=false for _ in 1 2 3 4 5 6 7 8 9 10; do if pgrep -f "$dest/$APP.app" >/dev/null 2>&1; then running=true; break; fi sleep 0.5 done if $running; then say " running ${D}(menu bar only, it has no window and no Dock icon)${R}" else die "installed to $dest but it did not stay running. Open it by hand and note any message." fi # --- 7. the one thing that cannot be automated ------------------------------- # macOS deliberately refuses to let any script grant Accessibility. The app # asks for it on launch; these are the exact steps for THIS macOS version. cat <