#!/bin/sh # juke-wizard/bin/jukewizard — build (cached) + launch JukeWizard. # # JukeWizard is the MASTER JUKE: it ALWAYS loads the whole /pop library so # every track is visible. Open it with no args to browse, or pass a specific # track to jump straight to it — the full library still loads underneath. # Each track shows its cover art, per-service listen links (Spotify/Apple/ # YouTube/DistroKid), and any reels/videos made for it (from the lane's out/). # The sidebar sort menu reorders by newest-rendered, rating, title, etc. # # usage: # juke-wizard/bin/jukewizard # browse the whole /pop library # juke-wizard/bin/jukewizard # load library + select/play that track # juke-wizard/bin/jukewizard --queue # focused ordered playlist; play a # juke-wizard/bin/jukewizard # load library + add these too # juke-wizard/bin/jukewizard ... --watch # auto-pop new renders # # Runs from anywhere; resolves the package from its own location. set -e HERE="$(cd "$(dirname "$0")" && pwd)" WIZ="$HERE/.." REPO="$(cd "$WIZ/.." && pwd)" if [ "${1:-}" = "login" ]; then shift if command -v ac-login >/dev/null 2>&1; then exec ac-login "$@"; fi exec node "$REPO/tezos/ac-login.mjs" "$@" fi if [ "${1:-}" = "cloud" ]; then shift exec node "$HERE/juke-cloud.mjs" "$@" fi if [ "${1:-}" = "--help" ] || [ "${1:-}" = "help" ]; then node "$HERE/juke-cloud.mjs" --help exit 0 fi swift build -c release --package-path "$WIZ" 2>&1 | grep -v '^$' | tail -2 || true BIN="$WIZ/.build/release/JukeWizard" LIB="$REPO/pop/out/pop-library.json" node "$REPO/pop/bin/pop-library.mjs" >/dev/null 2>&1 || true # refresh the index # JukeWizard deliberately remains resident after its last window closes, so a # second CLI launch would otherwise create another invisible audio engine. # The installed copy is launchd-owned for menu-bar residency, so killing it # here would race KeepAlive and can produce two players again. Raise the one # resident instance and let its menu-bar/library UI remain authoritative. JUKE_PID="$(pgrep -x JukeWizard | head -n 1 || true)" if [ -n "$JUKE_PID" ]; then osascript \ -e 'on run argv' \ -e 'tell application "System Events" to set frontmost of first process whose unix id is (item 1 of argv as integer) to true' \ -e 'end run' "$JUKE_PID" >/dev/null 2>&1 || true echo "JukeWizard is already running; raised the resident menu-bar instance." >&2 exit 0 fi # Close the small gap between the process check above and AppKit registering # the new process. This matters when launchd and a CLI queue arrive together. JUKE_LOCK="${TMPDIR:-/tmp}/computer.aesthetic.jukewizard.launching" if ! mkdir "$JUKE_LOCK" 2>/dev/null; then for _juke_wait in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do JUKE_PID="$(pgrep -x JukeWizard | head -n 1 || true)" [ -n "$JUKE_PID" ] && break sleep 0.05 done if [ -n "$JUKE_PID" ]; then echo "JukeWizard is already launching; using the resident menu-bar instance." >&2 exit 0 fi rmdir "$JUKE_LOCK" 2>/dev/null || true mkdir "$JUKE_LOCK" 2>/dev/null || exit 0 fi trap 'rmdir "$JUKE_LOCK" 2>/dev/null || true' EXIT HUP INT TERM # Focused queue mode: use only the following loose files/folders/playlists, # preserving their command-line order. This makes `--queue a.mp3 b.mp3` a # real two-track listening session instead of burying those tracks inside the # master /pop library. Select + autoplay the first supplied audio file. if [ "${1:-}" = "--queue" ]; then shift if [ "$#" -eq 0 ]; then echo "usage: jukewizard --queue [...]" >&2 exit 2 fi FIRST="$1" case "$FIRST" in /*) SEL="$FIRST";; *) SEL="$(pwd)/$FIRST";; esac "$BIN" "$@" --select "$SEL" exit $? fi # No args → just the master library. if [ "$#" -eq 0 ]; then "$BIN" "$LIB" exit $? fi # A specific audio file → load the master library AND select/play it # (absolutized so it matches the library entry; added to the queue if it's a # fresh draft not in the index yet). if [ -f "$1" ]; then case "$1" in /*) SEL="$1";; *) SEL="$(pwd)/$1";; esac "$BIN" "$LIB" "$@" --select "$SEL" exit $? fi # A folder / playlist / flags → load the master library and add them too. "$BIN" "$LIB" "$@"