@@ -10,6 +10,64 @@ YELLOW='\033[1;33m'
1010CYAN=' \033[0;36m'
1111NC=' \033[0m'
1212
13+ MEDIA_DIR=" $HOME /Media"
14+ INSTALL_DIR=" $HOME /mac-media-stack-advanced"
15+ NON_INTERACTIVE=false
16+
17+ usage () {
18+ cat << EOF
19+ Usage: bash bootstrap.sh [OPTIONS]
20+
21+ Options:
22+ --media-dir DIR Media root path (default: ~/Media)
23+ --install-dir DIR Repo install directory (default: ~/mac-media-stack-advanced)
24+ --non-interactive Skip interactive prompts (manual Seerr wiring required)
25+ --help Show this help message
26+
27+ Examples:
28+ bash bootstrap.sh
29+ bash bootstrap.sh --media-dir /Volumes/T9/Media
30+ bash bootstrap.sh --media-dir /Volumes/T9/Media --non-interactive
31+ EOF
32+ }
33+
34+ while [[ $# -gt 0 ]]; do
35+ case " $1 " in
36+ --media-dir)
37+ if [[ $# -lt 2 || " $2 " == --* ]]; then
38+ echo " Missing value for --media-dir"
39+ exit 1
40+ fi
41+ MEDIA_DIR=" $2 "
42+ shift 2
43+ ;;
44+ --install-dir)
45+ if [[ $# -lt 2 || " $2 " == --* ]]; then
46+ echo " Missing value for --install-dir"
47+ exit 1
48+ fi
49+ INSTALL_DIR=" $2 "
50+ shift 2
51+ ;;
52+ --non-interactive)
53+ NON_INTERACTIVE=true
54+ shift
55+ ;;
56+ --help|-h)
57+ usage
58+ exit 0
59+ ;;
60+ * )
61+ echo " Unknown option: $1 "
62+ usage
63+ exit 1
64+ ;;
65+ esac
66+ done
67+
68+ MEDIA_DIR=" ${MEDIA_DIR/# \~ / $HOME } "
69+ INSTALL_DIR=" ${INSTALL_DIR/# \~ / $HOME } "
70+
1371echo " "
1472echo " ======================================="
1573echo " Mac Media Stack Installer (Advanced)"
@@ -51,6 +109,27 @@ detect_running_runtime() {
51109 fi
52110}
53111
112+ wait_for_service () {
113+ local name=" $1 "
114+ local url=" $2 "
115+ local max_attempts=" ${3:- 45} "
116+ local attempt=0
117+ local status
118+
119+ while [[ $attempt -lt $max_attempts ]]; do
120+ status=$( curl -s -o /dev/null -w " %{http_code}" --max-time 3 " $url " 2> /dev/null || true)
121+ if [[ " $status " =~ ^(200| 301| 302| 401| 403)$ ]]; then
122+ echo -e " ${GREEN} OK${NC} $name is reachable"
123+ return 0
124+ fi
125+ sleep 2
126+ attempt=$(( attempt + 1 ))
127+ done
128+
129+ echo -e " ${YELLOW} WARN${NC} $name is not reachable yet (continuing anyway)"
130+ return 1
131+ }
132+
54133INSTALLED_RUNTIME=$( detect_installed_runtime)
55134
56135if ! docker info & > /dev/null; then
@@ -85,10 +164,12 @@ if ! command -v git &>/dev/null; then
85164 exit 1
86165fi
87166
167+ echo " "
168+ echo " Install dir: $INSTALL_DIR "
169+ echo " Media dir: $MEDIA_DIR "
88170echo " "
89171
90172# Clone
91- INSTALL_DIR=" $HOME /mac-media-stack-advanced"
92173if [[ -d " $INSTALL_DIR " ]]; then
93174 echo -e " ${YELLOW} Note:${NC} $INSTALL_DIR already exists. Pulling latest..."
94175 if ! git -C " $INSTALL_DIR " pull --ff-only; then
@@ -107,41 +188,65 @@ echo ""
107188
108189# Setup
109190echo -e " ${CYAN} Running setup...${NC} "
110- bash scripts/setup.sh
191+ bash scripts/setup.sh --media-dir " $MEDIA_DIR "
111192
112193echo " "
113194
114195# VPN keys
115196if grep -q " your_wireguard_private_key_here" .env 2> /dev/null; then
116- echo -e " ${CYAN} VPN Configuration${NC} "
117- echo " "
118- read -s -p " WireGuard Private Key: " vpn_key
119- echo " "
120- read -p " WireGuard Address (e.g. 10.2.0.2/32): " vpn_addr
121-
122- if [[ -n " $vpn_key " && -n " $vpn_addr " ]]; then
123- sed -i ' ' " s|WIREGUARD_PRIVATE_KEY=.*|WIREGUARD_PRIVATE_KEY=$vpn_key |" .env
124- sed -i ' ' " s|WIREGUARD_ADDRESSES=.*|WIREGUARD_ADDRESSES=$vpn_addr |" .env
125- echo -e " ${GREEN} VPN keys saved${NC} "
197+ if [[ " $NON_INTERACTIVE " == true ]]; then
198+ echo -e " ${YELLOW} WARN${NC} Non-interactive mode: VPN placeholders still present in .env"
199+ echo " Update WIREGUARD_PRIVATE_KEY and WIREGUARD_ADDRESSES before using the stack."
126200 else
127- echo -e " ${YELLOW} Skipped.${NC} Edit .env manually: open -a TextEdit $INSTALL_DIR /.env"
201+ echo -e " ${CYAN} VPN Configuration${NC} "
202+ echo " "
203+ read -s -p " WireGuard Private Key: " vpn_key
204+ echo " "
205+ read -p " WireGuard Address (e.g. 10.2.0.2/32): " vpn_addr
206+
207+ if [[ -n " $vpn_key " && -n " $vpn_addr " ]]; then
208+ sed -i ' ' " s|WIREGUARD_PRIVATE_KEY=.*|WIREGUARD_PRIVATE_KEY=$vpn_key |" .env
209+ sed -i ' ' " s|WIREGUARD_ADDRESSES=.*|WIREGUARD_ADDRESSES=$vpn_addr |" .env
210+ echo -e " ${GREEN} VPN keys saved${NC} "
211+ else
212+ echo -e " ${YELLOW} Skipped.${NC} Edit .env manually: open -a TextEdit $INSTALL_DIR /.env"
213+ fi
128214 fi
129215fi
130216
131217echo " "
132218
219+ # Preflight
220+ echo -e " ${CYAN} Running preflight checks...${NC} "
221+ if ! bash scripts/doctor.sh --media-dir " $MEDIA_DIR " ; then
222+ echo " "
223+ echo -e " ${RED} Preflight checks failed.${NC} Fix the FAIL items above, then re-run bootstrap."
224+ exit 1
225+ fi
226+
227+ echo " "
228+
133229# Start stack
134230echo -e " ${CYAN} Starting media stack (first run downloads ~3-5 GB)...${NC} "
135231echo " "
136232docker compose up -d
137233
138234echo " "
139- echo " Waiting 30 seconds for services to initialize..."
140- sleep 30
235+ echo " Waiting for core services..."
236+ wait_for_service " qBittorrent" " http://localhost:8080" || true
237+ wait_for_service " Prowlarr" " http://localhost:9696" || true
238+ wait_for_service " Radarr" " http://localhost:7878" || true
239+ wait_for_service " Sonarr" " http://localhost:8989" || true
240+ wait_for_service " Seerr" " http://localhost:5055" || true
241+ wait_for_service " Tdarr" " http://localhost:8265" || true
141242
142243# Configure
143244echo " "
144- bash scripts/configure.sh
245+ if [[ " $NON_INTERACTIVE " == true ]]; then
246+ bash scripts/configure.sh --non-interactive
247+ else
248+ bash scripts/configure.sh
249+ fi
145250
146251# Install automation
147252echo " "
@@ -157,10 +262,12 @@ echo " Seerr: http://localhost:5055"
157262echo " Plex: http://localhost:32400/web"
158263echo " Tdarr: http://localhost:8265"
159264echo " "
265+ echo " Media location: $MEDIA_DIR "
266+ echo " "
160267echo " Remaining manual steps:"
161- echo " 1. Set up Plex libraries (Movies: ~/Media/ Movies, TV: ~/Media /TV Shows)"
162- echo " 2. Edit ~/Media /config/recyclarr/recyclarr.yml with your API keys"
163- echo " 3. Edit ~/Media /config/kometa/config.yml with Plex token + TMDB key"
268+ echo " 1. Set up Plex libraries (Movies: $MEDIA_DIR / Movies, TV: $MEDIA_DIR /TV Shows)"
269+ echo " 2. Edit $MEDIA_DIR /config/recyclarr/recyclarr.yml with your API keys"
270+ echo " 3. Edit $MEDIA_DIR /config/kometa/config.yml with Plex token + TMDB key"
164271echo " 4. Update .env with Unpackerr API keys, then: docker compose restart unpackerr"
165272echo " 5. Configure Tdarr at http://localhost:8265"
166273echo " "
0 commit comments