Skip to content

Commit ddaa90e

Browse files
committed
feat: add one-liner install script (curl | bash)
Add install.sh — a self-contained cross-platform installer that: - Detects OS (Linux/macOS/Windows), package manager, and arch - Checks for Python 3.10+ (fails clearly if absent) - Installs FFmpeg via brew/apt/dnf/pacman/zypper automatically - Creates an isolated venv at ~/.local/share/music-cli - Installs coder-music-cli (+ optional extras) from PyPI - Symlinks music-cli to ~/.local/bin with PATH guidance - Verifies the install and prints a getting-started guide - Supports EXTRAS, INSTALL_DIR, PYTHON, SKIP_FFMPEG env vars Update README with the quick-install one-liner and extras usage.
1 parent e1c896c commit ddaa90e

File tree

2 files changed

+336
-0
lines changed

2 files changed

+336
-0
lines changed

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,41 @@ music-cli status # Check what's playing + inspirational quote
2424

2525
## Installation
2626

27+
### Quick Install (one command)
28+
29+
```bash
30+
curl -sSL https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh | bash
31+
```
32+
33+
Or with wget:
34+
35+
```bash
36+
wget -qO- https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh | bash
37+
```
38+
39+
With optional extras:
40+
41+
```bash
42+
# YouTube streaming support
43+
EXTRAS=youtube curl -sSL https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh | bash
44+
45+
# AI music generation (~5GB, PyTorch + Transformers)
46+
EXTRAS=ai curl -sSL https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh | bash
47+
48+
# Both
49+
EXTRAS="youtube,ai" curl -sSL https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh | bash
50+
```
51+
52+
Prefer to inspect first?
53+
54+
```bash
55+
curl -sSL https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh -o install.sh
56+
less install.sh # review
57+
bash install.sh
58+
```
59+
60+
### Manual Install (PyPI)
61+
2762
```bash
2863
# Install from PyPI
2964
pip install coder-music-cli

install.sh

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# ============================================================================
5+
# music-cli Installer
6+
# A command-line music player for coders: radio, local files, AI generation
7+
#
8+
# Quick install:
9+
# curl -sSL https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh | bash
10+
#
11+
# With optional extras:
12+
# EXTRAS=youtube curl -sSL https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh | bash
13+
# EXTRAS=ai curl -sSL https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh | bash
14+
# EXTRAS="youtube,ai" curl -sSL https://raw.githubusercontent.com/luongnv89/music-cli/main/install.sh | bash
15+
#
16+
# Environment variables:
17+
# EXTRAS Comma-separated optional extras: youtube, ai (default: none)
18+
# INSTALL_DIR Virtual-env install location (default: ~/.local/share/music-cli)
19+
# PYTHON Path to python interpreter to use (default: auto-detected)
20+
# SKIP_FFMPEG Set to 1 to skip FFmpeg installation check
21+
# ============================================================================
22+
23+
TOOL_NAME="music-cli"
24+
PYPI_PACKAGE="coder-music-cli"
25+
REPO="luongnv89/music-cli"
26+
BRANCH="main"
27+
28+
EXTRAS="${EXTRAS:-}"
29+
INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/share/music-cli}"
30+
SKIP_FFMPEG="${SKIP_FFMPEG:-0}"
31+
32+
# --- Color Output ---
33+
RED='\033[0;31m'
34+
GREEN='\033[0;32m'
35+
YELLOW='\033[1;33m'
36+
BLUE='\033[0;34m'
37+
CYAN='\033[0;36m'
38+
BOLD='\033[1m'
39+
NC='\033[0m'
40+
41+
info() { printf "${BLUE}[INFO]${NC} %s\n" "$*"; }
42+
ok() { printf "${GREEN}[ OK ]${NC} %s\n" "$*"; }
43+
warn() { printf "${YELLOW}[WARN]${NC} %s\n" "$*"; }
44+
step() { printf "\n${BOLD}${CYAN}==> %s${NC}\n" "$*"; }
45+
err() { printf "${RED}[ERR ]${NC} %s\n" "$*" >&2; }
46+
die() { err "$@"; exit 1; }
47+
48+
# --- OS / Arch Detection ---
49+
detect_os() {
50+
local os
51+
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
52+
case "$os" in
53+
linux*) echo "linux" ;;
54+
darwin*) echo "macos" ;;
55+
mingw*|msys*|cygwin*) echo "windows" ;;
56+
*) die "Unsupported operating system: $os" ;;
57+
esac
58+
}
59+
60+
detect_package_manager() {
61+
if command -v brew &>/dev/null; then echo "brew"
62+
elif command -v apt-get &>/dev/null; then echo "apt"
63+
elif command -v dnf &>/dev/null; then echo "dnf"
64+
elif command -v yum &>/dev/null; then echo "yum"
65+
elif command -v pacman &>/dev/null; then echo "pacman"
66+
elif command -v zypper &>/dev/null; then echo "zypper"
67+
else echo "unknown"
68+
fi
69+
}
70+
71+
need_sudo() {
72+
if [ "$(id -u)" -ne 0 ]; then
73+
if command -v sudo &>/dev/null; then echo "sudo"
74+
else echo "" # caller will warn if sudo is needed
75+
fi
76+
else
77+
echo ""
78+
fi
79+
}
80+
81+
# --- Dependency Checks ---
82+
check_command() {
83+
command -v "$1" &>/dev/null
84+
}
85+
86+
require_python() {
87+
# Honour explicit PYTHON override
88+
if [ -n "${PYTHON:-}" ]; then
89+
if ! "$PYTHON" --version &>/dev/null; then
90+
die "PYTHON='$PYTHON' is not executable"
91+
fi
92+
echo "$PYTHON"
93+
return
94+
fi
95+
96+
for candidate in python3 python; do
97+
if check_command "$candidate"; then
98+
local ver
99+
ver="$("$candidate" -c 'import sys; print("%d.%d" % sys.version_info[:2])')"
100+
local major minor
101+
major="${ver%%.*}"
102+
minor="${ver##*.}"
103+
if [ "$major" -ge 3 ] && [ "$minor" -ge 10 ]; then
104+
echo "$candidate"
105+
return
106+
fi
107+
fi
108+
done
109+
110+
die "Python 3.10+ is required but was not found.
111+
Install it from https://www.python.org/downloads/ or via your package manager, then re-run this script."
112+
}
113+
114+
install_ffmpeg() {
115+
local os="$1"
116+
local pm="$2"
117+
local sudo_cmd="$3"
118+
119+
if check_command ffmpeg; then
120+
ok "FFmpeg already installed ($(ffmpeg -version 2>&1 | head -1 | awk '{print $3}'))"
121+
return
122+
fi
123+
124+
info "Installing FFmpeg..."
125+
case "$os" in
126+
macos)
127+
if [ "$pm" = "brew" ]; then
128+
brew install ffmpeg
129+
else
130+
die "Homebrew is required to install FFmpeg on macOS.
131+
Install Homebrew: https://brew.sh
132+
Then re-run this script."
133+
fi
134+
;;
135+
linux)
136+
case "$pm" in
137+
apt) $sudo_cmd apt-get update -qq && $sudo_cmd apt-get install -y -qq ffmpeg ;;
138+
dnf) $sudo_cmd dnf install -y -q ffmpeg ;;
139+
yum) $sudo_cmd yum install -y -q ffmpeg ;;
140+
pacman) $sudo_cmd pacman -Sy --noconfirm ffmpeg ;;
141+
zypper) $sudo_cmd zypper install -y ffmpeg ;;
142+
*)
143+
warn "Cannot auto-install FFmpeg (unknown package manager)."
144+
warn "Please install FFmpeg manually: https://ffmpeg.org/download.html"
145+
warn "Then re-run this script."
146+
return 1
147+
;;
148+
esac
149+
;;
150+
windows)
151+
warn "On Windows, please install FFmpeg manually."
152+
warn "Options:"
153+
warn " winget install ffmpeg"
154+
warn " choco install ffmpeg"
155+
warn " Or download from: https://ffmpeg.org/download.html"
156+
warn "Then re-run this script."
157+
return 1
158+
;;
159+
esac
160+
ok "FFmpeg installed"
161+
}
162+
163+
install_pip_if_needed() {
164+
local python="$1"
165+
if ! "$python" -m pip --version &>/dev/null; then
166+
info "pip not found — installing via ensurepip..."
167+
"$python" -m ensurepip --upgrade || die "Failed to install pip. Install it manually: https://pip.pypa.io/en/stable/installation/"
168+
fi
169+
}
170+
171+
# --- Main music-cli Install ---
172+
install_music_cli() {
173+
local python="$1"
174+
175+
step "Creating isolated environment at $INSTALL_DIR"
176+
"$python" -m venv "$INSTALL_DIR"
177+
local venv_python="$INSTALL_DIR/bin/python"
178+
local venv_pip="$INSTALL_DIR/bin/pip"
179+
180+
step "Upgrading pip inside venv"
181+
"$venv_pip" install --quiet --upgrade pip
182+
183+
# Build extras specifier
184+
local pkg="$PYPI_PACKAGE"
185+
if [ -n "$EXTRAS" ]; then
186+
pkg="${PYPI_PACKAGE}[$EXTRAS]"
187+
fi
188+
189+
step "Installing $pkg from PyPI"
190+
"$venv_pip" install --quiet "$pkg"
191+
ok "Installed $pkg"
192+
}
193+
194+
# --- Symlink / PATH setup ---
195+
link_binary() {
196+
local venv_bin="$INSTALL_DIR/bin/music-cli"
197+
local link_target="$HOME/.local/bin/music-cli"
198+
199+
mkdir -p "$HOME/.local/bin"
200+
201+
if [ -L "$link_target" ] || [ -f "$link_target" ]; then
202+
rm -f "$link_target"
203+
fi
204+
ln -s "$venv_bin" "$link_target"
205+
ok "Linked $link_target -> $venv_bin"
206+
207+
# Shell PATH advice
208+
if ! echo "$PATH" | grep -q "$HOME/.local/bin"; then
209+
warn "'$HOME/.local/bin' is not in your PATH."
210+
warn "Add the following line to your shell profile (~/.bashrc / ~/.zshrc):"
211+
warn ""
212+
warn " export PATH=\"\$HOME/.local/bin:\$PATH\""
213+
warn ""
214+
warn "Then reload: source ~/.bashrc (or open a new terminal)"
215+
fi
216+
}
217+
218+
# --- Verification ---
219+
verify_installation() {
220+
local venv_bin="$INSTALL_DIR/bin/music-cli"
221+
step "Verifying installation"
222+
if [ -x "$venv_bin" ]; then
223+
local ver
224+
ver="$("$venv_bin" --version 2>/dev/null || true)"
225+
ok "$TOOL_NAME $ver is ready"
226+
else
227+
die "Installation verification failed — $venv_bin not found or not executable"
228+
fi
229+
}
230+
231+
# --- Entry Point ---
232+
main() {
233+
printf "\n${BOLD}${GREEN}music-cli installer${NC}\n"
234+
printf "${CYAN} Code. Listen. Iterate.${NC}\n\n"
235+
printf " Repo : https://github.com/$REPO\n"
236+
printf " PyPI : https://pypi.org/project/$PYPI_PACKAGE\n"
237+
printf " Extras : ${EXTRAS:-none}\n"
238+
printf " Dest : $INSTALL_DIR\n\n"
239+
240+
local os pm sudo_cmd python
241+
os="$(detect_os)"
242+
pm="$(detect_package_manager)"
243+
sudo_cmd="$(need_sudo)"
244+
245+
info "Platform: $os | Package manager: $pm"
246+
247+
# ── Python ──────────────────────────────────────────────
248+
step "Checking Python 3.10+"
249+
python="$(require_python)"
250+
ok "Using Python: $python ($("$python" --version))"
251+
252+
# ── pip ─────────────────────────────────────────────────
253+
step "Checking pip"
254+
install_pip_if_needed "$python"
255+
ok "pip available"
256+
257+
# ── FFmpeg ──────────────────────────────────────────────
258+
if [ "$SKIP_FFMPEG" = "0" ]; then
259+
step "Checking FFmpeg"
260+
if ! install_ffmpeg "$os" "$pm" "$sudo_cmd"; then
261+
warn "FFmpeg installation skipped. music-cli requires FFmpeg for audio playback."
262+
warn "Install it manually and ensure it is in your PATH before using music-cli."
263+
fi
264+
else
265+
warn "Skipping FFmpeg check (SKIP_FFMPEG=1)"
266+
fi
267+
268+
# ── music-cli ────────────────────────────────────────────
269+
install_music_cli "$python"
270+
271+
# ── Symlink ──────────────────────────────────────────────
272+
step "Setting up PATH"
273+
link_binary
274+
275+
# ── Done ─────────────────────────────────────────────────
276+
verify_installation
277+
278+
printf "\n${BOLD}${GREEN}============================================${NC}\n"
279+
ok "Installation complete!"
280+
printf "${BOLD}${GREEN}============================================${NC}\n\n"
281+
printf " Get started:\n\n"
282+
printf " ${CYAN}music-cli play${NC} # context-aware radio\n"
283+
printf " ${CYAN}music-cli play --mood focus${NC} # focus music\n"
284+
printf " ${CYAN}music-cli status${NC} # what's playing\n"
285+
printf " ${CYAN}music-cli --help${NC} # all commands\n\n"
286+
287+
if [ -n "$EXTRAS" ]; then
288+
printf " Extras installed: ${YELLOW}$EXTRAS${NC}\n"
289+
if echo "$EXTRAS" | grep -q "ai"; then
290+
printf " AI models are downloaded on first use (~1.5–6 GB each).\n"
291+
printf " Try: ${CYAN}music-cli ai play --mood focus${NC}\n"
292+
fi
293+
if echo "$EXTRAS" | grep -q "youtube"; then
294+
printf " YouTube streaming is ready.\n"
295+
printf " Try: ${CYAN}music-cli play -m youtube -s \"<URL>\"${NC}\n"
296+
fi
297+
fi
298+
printf "\n"
299+
}
300+
301+
main "$@"

0 commit comments

Comments
 (0)