Skip to content

Commit 1dccf15

Browse files
committed
feat(androidtv): add Projectivy deployment helper
1 parent 30729dd commit 1dccf15

3 files changed

Lines changed: 104 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Utility scripts for selfhosted infrastructure management.
77
- `.bash_aliases` — Shell aliases for common operations
88
- `docker_aliases.sh` — Docker Compose wrapper with 1Password secret resolution, fzf integration, Dozzle group management, and tab completion
99
- `tmux_session_picker.sh` — Auto-creates tmux sessions on SSH login with process detection and last-access display
10+
- `projectivy-deploy.sh` — Installs and configures Projectivy Launcher on Android TV over ADB
1011

1112
## Conventions
1213
- Bash scripts: POSIX-compatible where possible

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Utility scripts for selfhosted infrastructure management.
1010
- `.bash_aliases` — Shell aliases for common operations
1111
- `docker_aliases.sh` — Docker Compose wrapper with 1Password secret resolution, fzf integration, Dozzle group management, and tab completion
1212
- `tmux_session_picker.sh` — Auto-creates tmux sessions on SSH login with a table showing running processes and last access time
13+
- `projectivy-deploy.sh` — Installs Projectivy Launcher on Android TV over ADB, selects it as home, and supports configuration backup/restore
1314

1415
## Contributors
1516

projectivy-deploy.sh

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/env bash
2+
# Install Projectivy Launcher on an Android TV device and select it as home.
3+
# Uses ADB_CONTAINER (default: androidtv.internal) when running, otherwise adb.
4+
5+
set -euo pipefail
6+
7+
readonly PROJECTIVY_PACKAGE="com.spocky.projectivylauncher"
8+
readonly PROJECTIVY_HOME="${PROJECTIVY_PACKAGE}/com.spocky.projectivylauncher.MainActivity"
9+
readonly ADB_CONTAINER="${ADB_CONTAINER:-androidtv.internal}"
10+
11+
usage() {
12+
cat >&2 <<EOF
13+
Usage: $0 <device-host> [<apk-path>|--launcher-only|--backup <file>|--restore <file>]
14+
15+
The device must expose ADB over TCP and trust the selected ADB client key.
16+
Set ADB_CONTAINER to use a running container other than androidtv.internal.
17+
EOF
18+
exit 2
19+
}
20+
21+
[[ $# -ge 1 ]] || usage
22+
readonly DEVICE_HOST="$1"
23+
readonly DEVICE_TARGET="${DEVICE_HOST}:5555"
24+
APK_PATH="${2:-$(dirname "$0")/projectivy.apk}"
25+
LAUNCHER_ONLY=false
26+
RESTORE_PATH=""
27+
BACKUP_PATH=""
28+
29+
case "${2:-}" in
30+
--launcher-only) LAUNCHER_ONLY=true ;;
31+
--restore)
32+
LAUNCHER_ONLY=true
33+
RESTORE_PATH="${3:?--restore needs a path}"
34+
;;
35+
--backup)
36+
LAUNCHER_ONLY=true
37+
BACKUP_PATH="${3:?--backup needs a path}"
38+
;;
39+
esac
40+
41+
declare -a adb_cmd
42+
if command -v docker >/dev/null 2>&1 \
43+
&& docker ps --format '{{.Names}}' 2>/dev/null | grep -Fxq "$ADB_CONTAINER"; then
44+
adb_cmd=(docker exec "$ADB_CONTAINER" adb)
45+
printf 'Using ADB from container %s\n' "$ADB_CONTAINER"
46+
elif command -v adb >/dev/null 2>&1; then
47+
adb_cmd=(adb)
48+
printf 'Using host ADB\n'
49+
else
50+
printf 'ERROR: no running ADB container and no host adb executable\n' >&2
51+
exit 1
52+
fi
53+
54+
run_adb() {
55+
"${adb_cmd[@]}" "$@"
56+
}
57+
58+
cleanup() {
59+
run_adb disconnect "$DEVICE_TARGET" >/dev/null 2>&1 || true
60+
}
61+
trap cleanup EXIT
62+
63+
printf 'Connecting to %s\n' "$DEVICE_TARGET"
64+
run_adb connect "$DEVICE_TARGET" >/dev/null
65+
run_adb -s "$DEVICE_TARGET" wait-for-device
66+
67+
device_name="$(run_adb -s "$DEVICE_TARGET" shell getprop ro.product.model 2>/dev/null | tr -d '\r' || true)"
68+
printf 'Connected: %s\n' "${device_name:-unknown}"
69+
70+
if [[ "$LAUNCHER_ONLY" == false ]]; then
71+
[[ -f "$APK_PATH" ]] || {
72+
printf 'ERROR: APK not found at %s; use --launcher-only after store installation\n' "$APK_PATH" >&2
73+
exit 1
74+
}
75+
run_adb -s "$DEVICE_TARGET" install -r -g "$APK_PATH"
76+
fi
77+
78+
if ! run_adb -s "$DEVICE_TARGET" shell pm list packages 2>/dev/null \
79+
| grep -Fq "package:${PROJECTIVY_PACKAGE}"; then
80+
printf 'ERROR: Projectivy is not installed; install it first or provide an APK\n' >&2
81+
exit 1
82+
fi
83+
84+
if [[ -n "$RESTORE_PATH" ]]; then
85+
[[ -f "$RESTORE_PATH" ]] || {
86+
printf 'ERROR: restore file not found: %s\n' "$RESTORE_PATH" >&2
87+
exit 1
88+
}
89+
printf 'Restoring Projectivy configuration; confirm the prompt on the TV\n'
90+
run_adb -s "$DEVICE_TARGET" restore "$RESTORE_PATH"
91+
fi
92+
93+
if [[ -n "$BACKUP_PATH" ]]; then
94+
printf 'Backing up Projectivy configuration; confirm the prompt on the TV\n'
95+
run_adb -s "$DEVICE_TARGET" backup -f "$BACKUP_PATH" -noapk "$PROJECTIVY_PACKAGE"
96+
printf 'Backup written: %s bytes\n' "$(stat -c %s "$BACKUP_PATH" 2>/dev/null || echo missing)"
97+
exit 0
98+
fi
99+
100+
printf 'Setting Projectivy as the default launcher\n'
101+
run_adb -s "$DEVICE_TARGET" shell cmd package set-home-activity "$PROJECTIVY_HOME"
102+
printf 'Done. Press Home on the TV to verify Projectivy launches.\n'

0 commit comments

Comments
 (0)