-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·414 lines (376 loc) · 13.8 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·414 lines (376 loc) · 13.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
#!/usr/bin/env bash
# ShotX Installer
# Usage: curl -sSL https://raw.githubusercontent.com/vedesh-padal/ShotX/main/install.sh | sh
#
# Supports: Ubuntu/Debian (apt), Fedora/RHEL/CentOS (dnf/yum), Arch/Manjaro (pacman),
# openSUSE (zypper), Alpine (apk)
# Requires: bash, git, Python 3.10+, internet connection
#
# Environment variables:
# SKIP_SYSTEM_DEPS=1 Skip mandatory system dependency installation
# SKIP_OPTIONAL_DEPS=1 Skip optional feature deps (OCR, QR scan, recording)
# SKIP_AUTOSTART=1 Skip XDG autostart entry creation
#
# After install, run: shotx
set -euo pipefail
# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
REPO_URL="https://github.com/vedesh-padal/ShotX.git"
INSTALL_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/shotx"
BIN_DIR="${HOME}/.local/bin"
LAUNCHER="${BIN_DIR}/shotx"
DESKTOP_FILE="${HOME}/.config/autostart/shotx.desktop"
PYTHON_MIN="3.10"
# ---------------------------------------------------------------------------
# Color output helpers (gracefully degraded if not a TTY)
# ---------------------------------------------------------------------------
if [ -t 1 ]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
RESET='\033[0m'
else
RED='' GREEN='' YELLOW='' CYAN='' BOLD='' RESET=''
fi
info() { printf "${CYAN}[ShotX]${RESET} %s\n" "$*"; }
success() { printf "${GREEN}[ShotX] ✓${RESET} %s\n" "$*"; }
warn() { printf "${YELLOW}[ShotX] ⚠${RESET} %s\n" "$*"; }
die() { printf "${RED}[ShotX] ✗${RESET} %s\n" "$*" >&2; exit 1; }
step() { printf "\n${BOLD}━━━ %s${RESET}\n" "$*"; }
# ---------------------------------------------------------------------------
# Prerequisites
# ---------------------------------------------------------------------------
check_command() {
command -v "$1" >/dev/null 2>&1
}
require_command() {
if ! check_command "$1"; then
die "Required command '${1}' not found. Please install it and re-run this script."
fi
}
check_python_version() {
local python_bin="$1"
local version
version=$("$python_bin" -c "import sys; print('%d.%d' % sys.version_info[:2])" 2>/dev/null || true)
if [ -z "$version" ]; then
return 1
fi
# Compare major.minor numerically
local major minor min_major min_minor
major=$(echo "$version" | cut -d. -f1)
minor=$(echo "$version" | cut -d. -f2)
min_major=$(echo "$PYTHON_MIN" | cut -d. -f1)
min_minor=$(echo "$PYTHON_MIN" | cut -d. -f2)
if [ "$major" -gt "$min_major" ] || { [ "$major" -eq "$min_major" ] && [ "$minor" -ge "$min_minor" ]; }; then
return 0
fi
return 1
}
find_python() {
for candidate in python3.13 python3.12 python3.11 python3.10 python3 python; do
if check_command "$candidate" && check_python_version "$candidate"; then
echo "$candidate"
return 0
fi
done
return 1
}
# ---------------------------------------------------------------------------
# Package manager detection & dependency installation
# ---------------------------------------------------------------------------
detect_pm() {
if check_command apt-get; then echo "apt"
elif check_command dnf; then echo "dnf"
elif check_command yum; then echo "yum"
elif check_command pacman; then echo "pacman"
elif check_command zypper; then echo "zypper"
elif check_command apk; then echo "apk"
else echo "unknown"
fi
}
install_system_deps() {
local pm="$1"
step "Installing system dependencies (${pm})"
case "$pm" in
apt)
info "Updating package lists..."
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
git python3 python3-pip \
libcairo2-dev pkg-config \
gobject-introspection \
libglib2.0-dev \
libegl1 libgl1 libopengl0 \
libxcb-cursor0 libxcb-icccm4 libxcb-image0 \
libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \
libxcb-shape0 libxcb-xfixes0 libxcb-xinerama0 \
libxcb-xkb1 libxkbcommon-x11-0 libdbus-1-3 \
wl-clipboard xclip \
|| true # non-fatal: xclip/wl-clipboard may not exist on all systems
# libgirepository package name differs by Ubuntu version
if apt-cache show libgirepository-2.0-dev >/dev/null 2>&1; then
sudo apt-get install -y --no-install-recommends libgirepository-2.0-dev
else
sudo apt-get install -y --no-install-recommends libgirepository1.0-dev || true
fi
;;
dnf)
sudo dnf install -y --setopt=install_weak_deps=False \
git python3 python3-pip \
cairo-devel pkgconf-pkg-config \
gobject-introspection-devel \
mesa-libGL mesa-libEGL \
libxcb xcb-util-wm xcb-util-image xcb-util-keysyms \
xcb-util-cursor xkbcommon-x11 dbus-libs \
wl-clipboard xclip
;;
yum)
# RHEL/CentOS fallback — dnf preferred
sudo yum install -y \
git python3 python3-pip \
cairo-devel pkgconfig \
gobject-introspection-devel \
mesa-libGL mesa-libEGL \
libxcb xkbcommon-x11 dbus-libs
;;
pacman)
sudo pacman -Sy --noconfirm --needed \
git python python-pip \
cairo pkgconf \
gobject-introspection \
mesa \
xcb-util-wm xcb-util-image xcb-util-keysyms \
xcb-util-cursor libxkbcommon-x11 dbus \
wl-clipboard xclip
;;
zypper)
sudo zypper install -y --no-recommends \
git python3 python3-pip \
cairo-devel pkgconf \
gobject-introspection-devel \
Mesa-libGL Mesa-libEGL \
libxcb-devel xkbcommon-x11 dbus-1 \
wl-clipboard xclip
;;
apk)
# Alpine Linux (musl-based) — minimal support
sudo apk add --no-cache \
git python3 py3-pip \
cairo-dev pkgconf \
gobject-introspection-dev \
mesa-gl mesa-egl \
libxcb libxkbcommon dbus \
wl-clipboard
;;
*)
warn "Could not detect a supported package manager."
warn "Please manually install the system dependencies listed at:"
warn " https://shotx.vedeshpadal.me/getting-started/installation/"
;;
esac
success "System dependencies installed."
}
install_optional_system_deps() {
local pm="$1"
if [ -n "${SKIP_OPTIONAL_DEPS:-}" ]; then
warn "SKIP_OPTIONAL_DEPS set — skipping optional feature dependencies."
return
fi
step "Installing optional feature dependencies (OCR, QR scan, recording)"
info "These enable: OCR text extraction, QR code scanning, screen recording."
info "Skip with: SKIP_OPTIONAL_DEPS=1"
case "$pm" in
apt)
sudo apt-get install -y --no-install-recommends \
tesseract-ocr \
libzbar0 \
ffmpeg \
wf-recorder \
|| true
;;
dnf)
sudo dnf install -y --setopt=install_weak_deps=False \
tesseract tesseract-osd \
zbar \
ffmpeg \
wf-recorder \
|| true
;;
yum)
sudo yum install -y \
tesseract \
ffmpeg \
|| true
;;
pacman)
sudo pacman -Sy --noconfirm --needed \
tesseract tesseract-data-eng \
zbar \
ffmpeg \
wf-recorder \
|| true
;;
zypper)
sudo zypper install -y --no-recommends \
tesseract-ocr \
libzbar0 \
ffmpeg \
wf-recorder \
|| true
;;
apk)
sudo apk add --no-cache \
tesseract-ocr \
zbar \
ffmpeg \
|| true
;;
*)
warn "Cannot install optional deps: unknown package manager."
warn "For OCR: install 'tesseract-ocr' manually."
warn "For QR: install 'libzbar0' or 'zbar' manually."
warn "For recording: install 'ffmpeg' and 'wf-recorder' manually."
;;
esac
success "Optional feature dependencies installed."
}
# ---------------------------------------------------------------------------
# uv installation
# ---------------------------------------------------------------------------
install_uv() {
step "Installing uv (Python package manager)"
if check_command uv; then
local version
version=$(uv --version) || true
success "uv already installed (${version})"
return
fi
info "Downloading uv installer..."
if check_command curl; then
curl -LsSf https://astral.sh/uv/install.sh | sh
elif check_command wget; then
wget -qO- https://astral.sh/uv/install.sh | sh
else
die "Neither 'curl' nor 'wget' found. Cannot download uv."
fi
# Add uv to PATH for the rest of this script
export PATH="${HOME}/.local/bin:${HOME}/.cargo/bin:${PATH}"
if ! check_command uv; then
die "uv installation failed. Please install uv manually: https://docs.astral.sh/uv/"
fi
success "uv installed successfully."
}
# ---------------------------------------------------------------------------
# ShotX installation
# ---------------------------------------------------------------------------
install_shotx() {
step "Installing ShotX from source"
if [ -d "${INSTALL_DIR}/.git" ]; then
info "Existing installation found at ${INSTALL_DIR}. Updating..."
git -C "${INSTALL_DIR}" fetch --tags origin
git -C "${INSTALL_DIR}" checkout main
git -C "${INSTALL_DIR}" pull --ff-only
else
info "Cloning ShotX repository to ${INSTALL_DIR}..."
mkdir -p "$(dirname "${INSTALL_DIR}")"
git clone --depth=1 "${REPO_URL}" "${INSTALL_DIR}"
fi
info "Creating / updating virtual environment..."
uv sync --project "${INSTALL_DIR}" --group all 2>&1 | grep -v "^$" || true
success "ShotX installed to ${INSTALL_DIR}"
}
create_launcher() {
step "Creating launcher script at ${LAUNCHER}"
mkdir -p "${BIN_DIR}"
cat > "${LAUNCHER}" <<EOF
#!/usr/bin/env bash
# ShotX launcher — auto-generated by install.sh
exec uv run --project "${INSTALL_DIR}" python -m shotx.main "\$@"
EOF
chmod +x "${LAUNCHER}"
success "Launcher created: ${LAUNCHER}"
}
setup_autostart() {
step "Setting up XDG autostart entry"
if [ -n "${SKIP_AUTOSTART:-}" ]; then
info "SKIP_AUTOSTART set — skipping autostart setup."
return
fi
mkdir -p "$(dirname "${DESKTOP_FILE}")"
cat > "${DESKTOP_FILE}" <<EOF
[Desktop Entry]
Type=Application
Name=ShotX
Comment=Screenshot and screen capture tool
Exec=${LAUNCHER} --tray
Icon=${INSTALL_DIR}/src/shotx/assets/shotx.png
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
EOF
success "Autostart entry created: ${DESKTOP_FILE}"
}
# ---------------------------------------------------------------------------
# PATH advice
# ---------------------------------------------------------------------------
check_bin_in_path() {
case ":${PATH}:" in
*":${BIN_DIR}:"*)
return 0 ;;
esac
return 1
}
print_path_advice() {
if ! check_bin_in_path; then
warn ""
warn "${BIN_DIR} is not in your PATH."
warn "Add this line to your shell config (~/.bashrc, ~/.zshrc, ~/.profile, etc.):"
warn ""
warn " export PATH=\"\$HOME/.local/bin:\$PATH\""
warn ""
warn "Then restart your shell or run: source ~/.bashrc"
fi
}
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
main() {
printf "\n%b%bShotX Installer%b\n" "${BOLD}" "${CYAN}" "${RESET}"
printf "════════════════════════════════════\n\n"
# 1. Detect package manager
PM=$(detect_pm)
info "Package manager detected: ${PM}"
# 2. Install system deps (skip if SKIP_SYSTEM_DEPS is set)
if [ -n "${SKIP_SYSTEM_DEPS:-}" ]; then
warn "SKIP_SYSTEM_DEPS set — skipping system dependency installation."
else
install_system_deps "${PM}"
fi
# 2b. Install optional feature deps (OCR, QR, recording)
install_optional_system_deps "${PM}"
# 3. Verify Python 3.10+
step "Checking Python version"
PYTHON=$(find_python || true)
if [ -z "${PYTHON}" ]; then
die "Python ${PYTHON_MIN}+ not found. Please install Python ${PYTHON_MIN} or later."
fi
PY_VER=$("$PYTHON" -c "import sys; print('%d.%d' % sys.version_info[:2])")
success "Found Python ${PY_VER} (${PYTHON})"
# 4. Install uv
install_uv
# 5. Clone / update ShotX
install_shotx
# 6. Create launcher
create_launcher
# 7. Setup autostart (optional, set SKIP_AUTOSTART=1 to disable)
setup_autostart
# 8. PATH check
print_path_advice
printf "\n%b%b━━━ Installation complete! ━━━%b\n\n" "${BOLD}" "${GREEN}" "${RESET}"
printf "Run %bshotx%b to start ShotX in system tray mode.\n" "${BOLD}" "${RESET}"
printf "Run %bshotx --help%b to see all CLI options.\n\n" "${BOLD}" "${RESET}"
}
main "$@"