**Problem:**
Cleanup was trying to remove /mediacenter/docker instead of
/home/ubuntu/sailarr-installer (the actual repo directory).
**Root Cause:**
Recalculating installer directory with dirname BASH_SOURCE at cleanup time
instead of using SCRIPT_DIR that was calculated at script start.
**Solution:**
Use SCRIPT_DIR variable throughout cleanup section. This is more reliable
since it's calculated once at the beginning before any directory changes.
**Changes:**
- Removed INSTALLER_DIR variable recalculation
- Use SCRIPT_DIR consistently in all cleanup messages
- Updated both success and skip paths to use SCRIPT_DIR
**Testing:**
This ensures the correct directory (sailarr-installer repo) is removed,
not the docker config directory inside /mediacenter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Problem:**
Using sed with hardcoded line numbers (10, 210) is fragile. Any change
to recyclarr.yml (adding profiles, formats, etc.) breaks the injection.
**Solution:**
Replaced sed commands with AWK pattern matching that:
- Detects radarr:/sonarr: section headers
- Finds api_key: within the correct section
- Injects the API key regardless of line numbers
**Benefits:**
- Robust against file changes
- Same approach as recyclarr-sync.sh
- No maintenance when adding new profiles/formats
- More readable and maintainable
**Testing:**
Verified AWK correctly injects both API keys on VM.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Problem:**
The previous fix used line 209, but after updating HDR format IDs,
the Sonarr api_key is now on line 210.
**Root Cause:**
When HDR format IDs were simplified from 12 IDs to 4 IDs with explicit
scoring, the file lost one line, shifting Sonarr's api_key from 209 to 210.
**Testing:**
Verified with grep -n that api_key appears on:
- Line 10: Radarr (correct)
- Line 210: Sonarr (now correct)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Critical Fixes:**
1. Fixed Sonarr API key injection - sed line number was 205, should be 209
2. Updated HDR Custom Format IDs to current TRaSH Guides (January 2025)
**Sonarr API Key Fix:**
- Line 209 contains `api_key:` for Sonarr section (not line 205)
- This was causing "api_key must not be empty" validation errors
**HDR Format IDs Update:**
- Removed 12 obsolete HDR format IDs that no longer exist in TRaSH Guides
- Added current HDR format IDs:
- 493b6d1dbec3c3364c59d7607f7e3405 (HDR - score 500)
- b337d6812e06c200ec9a2d3cfa9d20a7 (DV Boost - score 1000)
- caa37d0df9c348912df1fb1d88f9273a (HDR10+ Boost - score 100)
- 923b6abef9b17f937fab56cfcf89e1f1 (DV w/o HDR fallback - score -10000)
**Testing:**
Both issues discovered during end-to-end installation test. These fixes
resolve Recyclarr validation errors and eliminate custom format warnings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**New Feature:**
After successful installation, the script now asks if the user wants to
remove the sailarr-installer repository directory.
**Behavior:**
- Displays "Cleanup" section after installation completes
- Shows current installation directory location
- Prompts: "Do you want to remove the installer repository? [y/N]"
- Default is NO (safer option)
**If user selects Yes:**
- Moves to parent directory
- Removes the entire sailarr-installer directory
- Confirms successful deletion
- Reminds that all config is preserved in /mediacenter (or custom path)
**If user selects No:**
- Keeps the repository
- Shows command to manually delete it later
- Logs the decision
**Why:**
Once installation completes, the repository is no longer needed. All
configuration files have been copied to the installation directory
(/mediacenter by default). This gives users the option to free up
disk space immediately or keep the repo for reference/future use.
**Safety:**
- Defaults to NO (keeps repository)
- Moves to parent directory before deletion (prevents shell issues)
- Checks deletion success and provides manual cleanup command if fails
- Logs all actions to installation log
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Changes to setup.sh:**
- Added "API KEYS FOR OVERSEERR CONFIGURATION" section to installation summary
- Display Radarr, Sonarr, and Prowlarr API keys at end of installation
- Added reference to docker/POST-INSTALL.md guide
- Users no longer need to run docker exec commands to get API keys
**Changes to POST-INSTALL.md:**
- Updated API key fields from placeholder to "auto-filled below"
- Added "Series Type" field for Sonarr (was missing)
- Clarified all anime-related fields are optional
- Improved field descriptions and recommendations
- Added note that API keys are displayed at installation end
- Kept docker exec commands as backup method to retrieve keys
**Sonarr fields now include:**
- Series Type: Standard (for regular TV shows)
- All anime fields properly listed as optional
- Season Folders with clear recommendation
- Tags section with proper ordering
**Why:**
Users asked for API keys to be provided directly rather than requiring
manual extraction. The installer already has these values, so displaying
them at the end simplifies the Overseerr configuration process.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Problem:**
Lines 1159-1163 (service restart code) were OUTSIDE the main
if [[ $REPLY =~ ^[Yy]$ ]] block but BEFORE the else statement,
causing a syntax error:
./setup.sh: line 1155: syntax error near unexpected token 'else'
**Structure Before:**
```
if [[ $REPLY =~ ^[Yy]$ ]]; then
# auto-configuration code
fi # Line 1157
# Restart services... # Lines 1159-1163 - WRONG LOCATION
./up.sh
else # Line 1164 - SYNTAX ERROR!
```
**Structure After:**
```
if [[ $REPLY =~ ^[Yy]$ ]]; then
# auto-configuration code
# Restart services... # Lines 1158-1162 - INSIDE if block
./up.sh
else
# skip message
fi
```
**Fix:**
Removed the extra fi and moved restart code inside the if block.
Now the else statement is properly positioned.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The entire installation is Docker-based, so mentioning it in this
specific prompt is redundant and adds unnecessary noise.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Problem:**
Authentication configuration was redirecting ALL output to /dev/null,
so failures were silent. The script showed "✓ Authentication configured"
even when the API call failed (due to invalid API keys with ANSI codes).
When users accessed Radarr/Sonarr, they were prompted for credentials
because authentication was never actually configured.
**Changes:**
1. **Removed /dev/null redirect** - Now captures HTTP response and status
2. **Validates config fetch** - Aborts if cannot get current config
3. **Checks HTTP status code** - Only shows success if 2xx response
4. **Shows HTTP code in success** - "✓ Radarr authentication configured (HTTP 202)"
5. **Aborts on failure** - Exits with error message and response body
6. **Applied to both services** - Radarr and Sonarr
**Before:**
- API call failed silently → /dev/null
- Script showed "✓ Authentication configured"
- User got login prompt (auth not actually configured)
**After:**
- Captures response and HTTP code
- Verifies 2xx success or aborts with error
- Shows actual HTTP status in success message
- User has working authentication
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Problems Fixed:**
1. **API keys contained ANSI color codes** (71 chars instead of 32)
- configure_arr_service() called extract_api_key() without | tail -1
- configure_prowlarr() same issue
- Result: API keys had escape sequences, causing JSON parsing errors
2. **Authentication messages were generic**
- "Configuring authentication..." didn't say which service
- "Authentication configured" didn't say which service
- User confused about what was actually configured
**Solutions:**
1. Added | tail -1 to ALL extract_api_key() calls:
- setup/lib/setup-services.sh: configure_arr_service()
- setup/lib/setup-services.sh: configure_prowlarr()
- These were missing the tail filter
2. Updated auth messages to be specific:
- "Configuring Radarr authentication..."
- "✓ Radarr authentication configured"
- Same for Sonarr
3. Changed configure_prowlarr return 1 to exit 1 for consistency
**Result:**
All API keys should now be exactly 32 characters with no escape codes,
and authentication messages clearly indicate which service is configured.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Problem:**
PROWLARR_API_KEY (and RADARR/SONARR when extracted directly) was
capturing all stdout from extract_api_key(), including log messages:
- log_info "Extracting API key from..."
- log_operation "GREP docker exec..."
- log_success "API key extracted from..."
- The actual API key
This resulted in 213 character "API keys" instead of 32 chars,
causing HTTP 401 authentication failures.
**Root Cause:**
Log functions (log_info, log_operation, log_success) echo to stdout,
and when capturing function output with $(...), ALL stdout is captured.
**Solution:**
Pipe extract_api_key output through 'tail -1' to capture only the
last line (the actual API key):
PROWLARR_API_KEY=$(extract_api_key "prowlarr" | tail -1)
Applied to all three services: radarr, sonarr, prowlarr
**Testing:**
All API keys should now be exactly 32 characters and authentication
should work correctly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**MAJOR BUG:**
The installer was continuing execution after critical errors, leading to:
- Infinite loops waiting for services that will never respond
- Cascading failures as dependent operations try to use invalid state
- User confusion as errors scroll by but script keeps running
**Problems Fixed:**
1. **configure_arr_service()** - Now exits if:
- API key extraction fails (was: return 1, continued)
- Root folder creation fails (was: log error, continued)
- Download client addition fails (was: log error, continued)
- Remote path mapping is non-critical, logs warning only
2. **add_arr_to_prowlarr()** calls in setup.sh - Now exits if:
- Failed to add Radarr to Prowlarr (was: log error, continued)
- Failed to add Sonarr to Prowlarr (was: log error, continued)
3. **API key extraction** in setup.sh - Now exits if:
- Any of the three API keys (Radarr/Sonarr/Prowlarr) are empty
- Shows which specific keys are missing
- Provides docker logs command to troubleshoot
**Result:**
- Script now STOPS IMMEDIATELY when a critical operation fails
- Clear error messages explain what failed and how to debug
- Logs are preserved for troubleshooting
- No more infinite loops or cascading failures
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Problems:**
1. RADARR_API_KEY and SONARR_API_KEY were capturing ALL output from
configure_arr_service, including JSON responses from api_call
- Resulted in 1200+ character "API keys" instead of 32 chars
- Caused HTTP 401 errors (invalid API key sent to services)
- Caused sed errors in recyclarr config (unterminated commands)
2. sed commands used '/' delimiter which could fail with special chars
**Root Cause:**
configure_arr_service() calls add_root_folder(), add_download_client(),
and add_remote_path_mapping(). These call api_call() which does
'echo "$response"' to return JSON. When doing:
RADARR_API_KEY=$(configure_arr_service ...)
ALL those echo statements were captured, not just the final API key.
**Solution:**
1. Pipe configure_arr_service output through 'tail -1' to capture only
the last line (the API key):
RADARR_API_KEY=$(configure_arr_service ... | tail -1)
2. Change sed delimiter from '/' to '|' for robustness:
sed -i "10s|api_key:.*|api_key: ${RADARR_API_KEY}|"
**Testing:**
API keys should now be 32 characters, authentication should work,
and recyclarr sed commands should execute without errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Problem:**
Previously only validated rclone and zurg, allowing installation to
continue even if other critical services failed to start.
**Solution:**
- Capture docker compose exit code and abort if non-zero
- Validate ALL expected services are running (17 base + 2 if Traefik)
- Check for unhealthy containers and wait 60s for them to recover
- If services are missing or remain unhealthy, abort with detailed error messages
- List which services failed and how to check their logs
**Expected Services Validated:**
Core: zurg, rclone, decypharr, prowlarr, radarr, sonarr, overseerr, plex
Support: zilean, zilean-postgres, homarr, dashdot, autoscan, tautulli
Automation: watchtower, plextraktsync, pinchflat
Optional: traefik, traefik-socket-proxy (if enabled)
This prevents the installer from trying to configure services that
aren't running, which would cause API errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Critical bug fix: rclone.conf was only copied when installing to a different
directory. When users install in the cloned repo directory (most common case),
the file wasn't copied and Docker created it as a directory, causing rclone
container to fail with 'is a directory' error.
Changes:
- Move rclone.conf copy outside the 'if ROOT_DIR != SCRIPT_DIR' block
- Ensure rclone.conf is ALWAYS copied before docker compose up
- Add clear log message indicating the copy operation
- Prevents Docker from auto-creating rclone.conf as a directory
- Validate rclone and zurg containers started successfully after docker compose up
- Stop installation if critical services fail (prevents cascade failures)
- Verify rclone.conf is a FILE before copying (not a directory)
- Remove destination rclone.conf if it's a directory
- Verify rclone.conf was copied correctly as a file
- Add helpful error messages with fix instructions
- Exit with error code 1 on critical failures
- Create logs in /tmp/sailarr-install-TIMESTAMP/ directory
- Add install.log: complete installation log with timestamps
- Add trace.log: detailed function tracing for debugging
- Add log_operation() for tracking file operations (COPY, MKDIR, DOWNLOAD, etc)
- Add log_debug() for debug-level messages
- Add function entry/exit tracing with parameters and return codes
- Log all API calls with HTTP status codes and response lengths
- Log file operations (copy, download, grep, etc) before execution
- Display log location at start and end of installation
- All logs include timestamps for precise debugging