torrent-man/main-installer.sh
Claude 9e544456db Initial commit with UI fixes for dark mode
This repository contains Transmission RSS Manager with the following changes:
- Fixed dark mode navigation tab visibility issue
- Improved text contrast in dark mode throughout the app
- Created dedicated dark-mode.css for better organization
- Enhanced JavaScript for dynamic styling in dark mode
- Added complete installation scripts

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-13 17:16:41 +00:00

582 lines
21 KiB
Bash
Executable File

#!/bin/bash
# Transmission RSS Manager Modular Installer
# Modified to work with the git-based approach
# Set script to exit on error
set -e
# Load installation environment variables if they exist
if [ -f "$(dirname "$0")/.env.install" ]; then
source "$(dirname "$0")/.env.install"
echo "Loaded TRANSMISSION_REMOTE=$TRANSMISSION_REMOTE from environment file"
fi
# Text formatting
BOLD='\033[1m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Get current directory
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# Source the utils module first to make the log function available
source "${SCRIPT_DIR}/modules/utils-module.sh"
# Print header
echo -e "${BOLD}==================================================${NC}"
echo -e "${BOLD} Transmission RSS Manager Installer ${NC}"
VERSION=$(grep -oP '"version": "\K[^"]+' "${SCRIPT_DIR}/package.json" 2>/dev/null || echo "Unknown")
# Check if package.json exists, if not suggest creating it
if [ ! -f "${SCRIPT_DIR}/package.json" ]; then
echo -e "${YELLOW}Warning: package.json not found. You may need to run 'npm init' first.${NC}"
fi
echo -e "${BOLD} Version ${VERSION} - Git Edition ${NC}"
echo -e "${BOLD}==================================================${NC}"
echo
# Check if script is run with sudo
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}Please run as root (use sudo)${NC}"
exit 1
fi
# Check for installation type
IS_UPDATE=false
INSTALLATION_DETECTED=false
# Check if we have existing config info from install-script.sh
if [ -n "$EXISTING_INSTALL_DIR" ] && [ -n "$EXISTING_CONFIG_PATH" ]; then
INSTALLATION_DETECTED=true
IS_UPDATE=true
# Use the existing installation directory as our target
INSTALL_DIR="$EXISTING_INSTALL_DIR"
CONFIG_FILE="$EXISTING_CONFIG_PATH"
log "INFO" "Using existing installation at $INSTALL_DIR detected by install-script.sh"
export INSTALL_DIR
else
# Check for config.json file (primary indicator)
POSSIBLE_CONFIG_LOCATIONS=(
"${SCRIPT_DIR}/config.json"
"/opt/transmission-rss-manager/config.json"
"/etc/transmission-rss-manager/config.json"
)
for CONFIG_PATH in "${POSSIBLE_CONFIG_LOCATIONS[@]}"; do
if [ -f "$CONFIG_PATH" ]; then
INSTALLATION_DETECTED=true
IS_UPDATE=true
INSTALL_DIR="$(dirname "$CONFIG_PATH")"
CONFIG_FILE="$CONFIG_PATH"
log "INFO" "Found existing installation at $INSTALL_DIR"
export INSTALL_DIR
break
fi
done
# Check for service file (secondary indicator) if no config file found
if [ "$INSTALLATION_DETECTED" = "false" ] && [ -f "/etc/systemd/system/transmission-rss-manager.service" ]; then
INSTALLATION_DETECTED=true
IS_UPDATE=true
# Extract the installation directory from the service file
SERVICE_INSTALL_DIR=$(grep "WorkingDirectory=" "/etc/systemd/system/transmission-rss-manager.service" | cut -d'=' -f2)
if [ -n "$SERVICE_INSTALL_DIR" ]; then
INSTALL_DIR="$SERVICE_INSTALL_DIR"
log "INFO" "Found existing installation at $INSTALL_DIR from service file"
export INSTALL_DIR
# Check for config file in the detected installation directory
if [ -f "$INSTALL_DIR/config.json" ]; then
CONFIG_FILE="$INSTALL_DIR/config.json"
fi
fi
fi
# Check for data directory (tertiary indicator)
if [ "$INSTALLATION_DETECTED" = "false" ] && [ -d "${SCRIPT_DIR}/data" ] && [ "$(ls -A "${SCRIPT_DIR}/data" 2>/dev/null)" ]; then
INSTALLATION_DETECTED=true
fi
fi
# Provide clear feedback about the installation type
if [ "$IS_UPDATE" = "true" ]; then
log "INFO" "Running in UPDATE mode - will preserve existing configuration"
log "INFO" "Target installation directory: $INSTALL_DIR"
if [ -n "$CONFIG_FILE" ]; then
log "INFO" "Using configuration file: $CONFIG_FILE"
fi
# Make sure the variables are set correctly
echo -e "${YELLOW}Existing installation detected. Running in update mode.${NC}"
echo -e "${GREEN}Your existing configuration will be preserved.${NC}"
echo -e "${GREEN}Only application files will be updated.${NC}"
else
log "INFO" "Running in FRESH INSTALL mode"
echo -e "${GREEN}Fresh installation. Will create new configuration.${NC}"
fi
export IS_UPDATE
# Check if required module files exist
REQUIRED_MODULES=(
"${SCRIPT_DIR}/modules/config-module.sh"
"${SCRIPT_DIR}/modules/utils-module.sh"
"${SCRIPT_DIR}/modules/dependencies-module.sh"
"${SCRIPT_DIR}/modules/service-setup-module.sh"
"${SCRIPT_DIR}/modules/file-creator-module.sh"
)
for module in "${REQUIRED_MODULES[@]}"; do
if [ ! -f "$module" ]; then
echo -e "${RED}Error: Required module file not found: $module${NC}"
echo -e "${YELLOW}The module files should be included in the git repository.${NC}"
exit 1
fi
done
# Source the remaining module files
source "${SCRIPT_DIR}/modules/config-module.sh"
source "${SCRIPT_DIR}/modules/dependencies-module.sh"
# Check if the updated service module exists, use it if available
if [ -f "${SCRIPT_DIR}/modules/service-setup-module-updated.sh" ]; then
log "INFO" "Using updated service setup module"
source "${SCRIPT_DIR}/modules/service-setup-module-updated.sh"
else
log "INFO" "Using standard service setup module"
source "${SCRIPT_DIR}/modules/service-setup-module.sh"
fi
source "${SCRIPT_DIR}/modules/file-creator-module.sh"
# Function to handle cleanup on error
function cleanup_on_error() {
log "ERROR" "Installation failed: $1"
log "INFO" "Cleaning up..."
# Add any cleanup steps here if needed
log "INFO" "You can try running the installer again after fixing the issues."
exit 1
}
# Set trap for error handling
trap 'cleanup_on_error "$BASH_COMMAND"' ERR
# Execute the installation steps in sequence
log "INFO" "Starting installation process..."
# Set defaults for key variables
export TRANSMISSION_REMOTE=false
export CONFIG_DIR=${CONFIG_DIR:-"/etc/transmission-rss-manager"}
export USER=${USER:-$(logname || echo $SUDO_USER)}
if [ "$IS_UPDATE" = true ]; then
log "INFO" "Running in update mode - preserving existing configuration..."
# First, let's check if we already have this value from the environment
# This allows for non-interactive usage in scripts
if [ -n "$TRANSMISSION_REMOTE" ]; then
is_remote=$([ "$TRANSMISSION_REMOTE" = true ] && echo "Remote" || echo "Local")
log "INFO" "Using Transmission mode from environment: $is_remote"
# Set the input_remote variable based on the environment variable
# This ensures consistent behavior with the rest of the script
if [ "$TRANSMISSION_REMOTE" = true ]; then
input_remote="y"
else
input_remote="n"
fi
else
# Directly ask about Transmission
# This is a direct approach that bypasses any potential sourcing issues
log "INFO" "Configuring Transmission connection..."
echo -e "${BOLD}Transmission Configuration:${NC}"
echo -e "Configure connection to your Transmission client:"
echo
# If stdin is not a terminal (pipe or redirect), assume default
if [ ! -t 0 ]; then
input_remote="n" # Default to no
log "INFO" "Non-interactive mode detected, using default: local Transmission"
else
read -p "Is Transmission running on a remote server? (y/n) [n]: " input_remote
fi
log "INFO" "DEBUG: Input received for remote: '$input_remote'"
fi
# More explicit check for "y" or "Y" input
if [ "$input_remote" = "y" ] || [ "$input_remote" = "Y" ]; then
export TRANSMISSION_REMOTE=true
log "INFO" "Remote Transmission selected."
# Update the config file directly to set remote mode
if [ -f "$CONFIG_DIR/config.json" ]; then
log "INFO" "Updating configuration file for remote Transmission..."
# Log all environment variables we have for debugging
log "INFO" "DEBUG: Environment variables for remote configuration:"
log "INFO" "DEBUG: TRANSMISSION_HOST=${TRANSMISSION_HOST:-'not set'}"
log "INFO" "DEBUG: TRANSMISSION_PORT=${TRANSMISSION_PORT:-'not set'}"
log "INFO" "DEBUG: REMOTE_DOWNLOAD_DIR=${REMOTE_DOWNLOAD_DIR:-'not set'}"
log "INFO" "DEBUG: LOCAL_DOWNLOAD_DIR=${LOCAL_DOWNLOAD_DIR:-'not set'}"
# Check if we already have the remote configuration details from the environment
if [ -n "$TRANSMISSION_HOST" ] && [ -n "$TRANSMISSION_PORT" ] && [ -n "$REMOTE_DOWNLOAD_DIR" ] && [ -n "$LOCAL_DOWNLOAD_DIR" ]; then
log "INFO" "Using remote Transmission configuration from environment"
# Values are already set from the environment, no need to ask again
else
# Get and validate hostname
read -p "Remote Transmission host [localhost]: " input_trans_host
TRANSMISSION_HOST=${input_trans_host:-"localhost"}
# Get and validate port
read -p "Remote Transmission port [9091]: " input_trans_port
TRANSMISSION_PORT=${input_trans_port:-9091}
# Get credentials
read -p "Remote Transmission username []: " input_trans_user
TRANSMISSION_USER=${input_trans_user:-""}
# Use read -s for password to avoid showing it on screen
read -s -p "Remote Transmission password []: " input_trans_pass
echo # Add a newline after the password input
TRANSMISSION_PASS=${input_trans_pass:-""}
read -p "Remote Transmission RPC path [/transmission/rpc]: " input_trans_path
TRANSMISSION_RPC_PATH=${input_trans_path:-"/transmission/rpc"}
# Configure directory mapping for remote setup
echo
echo -e "${YELLOW}Directory Mapping Configuration${NC}"
echo -e "When using a remote Transmission server, you need to map paths between servers."
echo -e "For each directory on the remote server, specify the corresponding local directory."
echo
# Get remote download directory
read -p "Remote Transmission download directory [/var/lib/transmission-daemon/downloads]: " REMOTE_DOWNLOAD_DIR
REMOTE_DOWNLOAD_DIR=${REMOTE_DOWNLOAD_DIR:-"/var/lib/transmission-daemon/downloads"}
# Get local directory that corresponds to remote download directory
read -p "Local directory that corresponds to the remote download directory [/mnt/transmission-downloads]: " LOCAL_DOWNLOAD_DIR
LOCAL_DOWNLOAD_DIR=${LOCAL_DOWNLOAD_DIR:-"/mnt/transmission-downloads"}
fi
# Create mapping JSON
TRANSMISSION_DIR_MAPPING=$(cat <<EOF
{
"$REMOTE_DOWNLOAD_DIR": "$LOCAL_DOWNLOAD_DIR"
}
EOF
)
# Create the local directory
mkdir -p "$LOCAL_DOWNLOAD_DIR"
chown -R $USER:$USER "$LOCAL_DOWNLOAD_DIR"
# Update the config file with the new remote settings
log "INFO" "Updating configuration file with remote Transmission settings..."
# Backup the original config file
cp "$CONFIG_DIR/config.json" "$CONFIG_DIR/config.json.bak.$(date +%Y%m%d%H%M%S)"
# Update the isRemote setting
sed -i 's/"isRemote": false/"isRemote": true/' "$CONFIG_DIR/config.json"
# Update the host setting
sed -i "s/\"host\": \"[^\"]*\"/\"host\": \"$TRANSMISSION_HOST\"/" "$CONFIG_DIR/config.json"
# Update the port setting
sed -i "s/\"port\": [0-9]*/\"port\": $TRANSMISSION_PORT/" "$CONFIG_DIR/config.json"
# Update the username setting
sed -i "s/\"username\": \"[^\"]*\"/\"username\": \"$TRANSMISSION_USER\"/" "$CONFIG_DIR/config.json"
# Update the password setting
sed -i "s/\"password\": \"[^\"]*\"/\"password\": \"$TRANSMISSION_PASS\"/" "$CONFIG_DIR/config.json"
# Update the RPC path setting
sed -i "s|\"path\": \"[^\"]*\"|\"path\": \"$TRANSMISSION_RPC_PATH\"|" "$CONFIG_DIR/config.json"
# Update the directory mapping
# Use a more complex approach since it's a JSON object
# This is a simplification and might need improvement for complex JSON handling
sed -i "/\"directoryMapping\":/c\\ \"directoryMapping\": $TRANSMISSION_DIR_MAPPING" "$CONFIG_DIR/config.json"
log "INFO" "Configuration updated for remote Transmission."
fi
else
export TRANSMISSION_REMOTE=false
log "INFO" "Local Transmission selected."
# Update the config file directly to set local mode
if [ -f "$CONFIG_DIR/config.json" ]; then
log "INFO" "Updating configuration file for local Transmission..."
# Backup the original config file
cp "$CONFIG_DIR/config.json" "$CONFIG_DIR/config.json.bak.$(date +%Y%m%d%H%M%S)"
# Update the isRemote setting
sed -i 's/"isRemote": true/"isRemote": false/' "$CONFIG_DIR/config.json"
# Update the host setting
sed -i 's/"host": "[^"]*"/"host": "localhost"/' "$CONFIG_DIR/config.json"
log "INFO" "Configuration updated for local Transmission."
fi
fi
# Step 1: Check dependencies (but don't reconfigure)
log "INFO" "Checking dependencies..."
install_dependencies || {
log "ERROR" "Dependency check failed"
exit 1
}
# Step the service configuration (will preserve existing settings)
log "INFO" "Updating service configuration..."
setup_service || {
log "ERROR" "Service update failed"
exit 1
}
# Install npm dependencies using our common function
ensure_npm_packages "$INSTALL_DIR" || {
log "ERROR" "NPM installation failed"
exit 1
}
# Copy JavaScript module files during update as well
log "INFO" "Copying JavaScript module files..."
copy_module_files || {
log "ERROR" "Failed to copy JavaScript module files"
exit 1
}
else
# This is a fresh installation - run all steps
# Step 1: First, let's check if we already have this value from the environment
# This allows for non-interactive usage in scripts
if [ -n "$TRANSMISSION_REMOTE" ]; then
is_remote=$([ "$TRANSMISSION_REMOTE" = true ] && echo "Remote" || echo "Local")
log "INFO" "Using Transmission mode from environment: $is_remote"
# Set the input_remote variable based on the environment variable
# This ensures consistent behavior with the rest of the script
if [ "$TRANSMISSION_REMOTE" = true ]; then
input_remote="y"
else
input_remote="n"
fi
else
# Directly ask about Transmission
# This is a direct approach that bypasses any potential sourcing issues
log "INFO" "Configuring Transmission connection..."
echo -e "${BOLD}Transmission Configuration:${NC}"
echo -e "Configure connection to your Transmission client:"
echo
# If stdin is not a terminal (pipe or redirect), assume default
if [ ! -t 0 ]; then
input_remote="n" # Default to no
log "INFO" "Non-interactive mode detected, using default: local Transmission"
else
read -p "Is Transmission running on a remote server? (y/n) [n]: " input_remote
fi
log "INFO" "DEBUG: Input received for remote: '$input_remote'"
fi
# More explicit check for "y" or "Y" input
if [ "$input_remote" = "y" ] || [ "$input_remote" = "Y" ]; then
export TRANSMISSION_REMOTE=true
log "INFO" "Remote Transmission selected."
else
export TRANSMISSION_REMOTE=false
log "INFO" "Local Transmission selected."
fi
# Now gather the rest of the configuration
log "INFO" "Gathering remaining configuration..."
gather_configuration || {
log "ERROR" "Configuration gathering failed"
exit 1
}
# Debug: Verify TRANSMISSION_REMOTE is set
log "INFO" "After configuration gathering, TRANSMISSION_REMOTE=$TRANSMISSION_REMOTE"
# Step 2: Install dependencies
log "INFO" "Installing dependencies..."
install_dependencies || {
log "ERROR" "Dependency installation failed"
exit 1
}
# Step 3: Create installation directories
log "INFO" "Creating directories..."
# Make sure CONFIG_DIR is set and exported
export CONFIG_DIR=${CONFIG_DIR:-"/etc/transmission-rss-manager"}
# Call our new create_directories function
create_directories || {
log "ERROR" "Directory creation failed"
exit 1
}
# Step 4: Create configuration files only (no application files since they're from git)
log "INFO" "Creating configuration files..."
create_config_files || {
log "ERROR" "Configuration file creation failed"
exit 1
}
# Step 5: Create service files and install the service
log "INFO" "Setting up service..."
setup_service || {
log "ERROR" "Service setup failed"
exit 1
}
# Step 6: Install npm dependencies using our common function
ensure_npm_packages "$INSTALL_DIR" || {
log "ERROR" "NPM installation failed"
exit 1
}
fi
# Step 7: Set up update script
log "INFO" "Setting up update script..."
mkdir -p "${SCRIPT_DIR}/scripts"
# Check if update script exists - don't copy it to itself
if [ ! -f "${SCRIPT_DIR}/scripts/update.sh" ]; then
# First, check if we have an update script to copy
if [ -f "${SCRIPT_DIR}/update.sh" ]; then
cp "${SCRIPT_DIR}/update.sh" "${SCRIPT_DIR}/scripts/update.sh"
log "INFO" "Copied update script from root to scripts directory"
else
# Create the update script since it doesn't exist
cat > "${SCRIPT_DIR}/scripts/update.sh" << 'EOL'
#!/bin/bash
# Transmission RSS Manager - Update Script
# This script pulls the latest version from git and runs necessary updates
# Color and formatting
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
BOLD='\033[1m'
# Installation directory (should be current directory)
INSTALL_DIR=$(pwd)
# Check if we're in the right directory
if [ ! -f "$INSTALL_DIR/package.json" ] || [ ! -d "$INSTALL_DIR/modules" ]; then
echo -e "${RED}Error: This script must be run from the installation directory.${NC}"
exit 1
fi
# Get the current version
CURRENT_VERSION=$(grep -oP '"version": "\K[^"]+' package.json)
echo -e "${YELLOW}Current version: ${BOLD}$CURRENT_VERSION${NC}"
# Check for git repository
if [ ! -d ".git" ]; then
echo -e "${RED}Error: This installation was not set up using git.${NC}"
echo -e "Please use the bootstrap installer to perform a fresh installation."
exit 1
fi
# Stash any local changes
echo -e "${YELLOW}Backing up any local configuration changes...${NC}"
git stash -q
# Pull the latest changes
echo -e "${YELLOW}Pulling latest updates from git...${NC}"
git pull
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to pull updates. Restoring original state...${NC}"
git stash pop -q
exit 1
fi
# Get the new version
NEW_VERSION=$(grep -oP '"version": "\K[^"]+' package.json)
echo -e "${GREEN}New version: ${BOLD}$NEW_VERSION${NC}"
# Check if update is needed
if [ "$CURRENT_VERSION" == "$NEW_VERSION" ]; then
echo -e "${GREEN}You already have the latest version.${NC}"
exit 0
fi
# Install any new npm dependencies
echo -e "${YELLOW}Installing dependencies...${NC}"
npm install
# Apply any local configuration changes
if git stash list | grep -q "stash@{0}"; then
echo -e "${YELLOW}Restoring local configuration changes...${NC}"
git stash pop -q
# Handle conflicts if any
if [ $? -ne 0 ]; then
echo -e "${RED}There were conflicts when restoring your configuration.${NC}"
echo -e "Please check the files and resolve conflicts manually."
echo -e "Your original configuration is saved in .git/refs/stash"
fi
fi
# Restart the service
echo -e "${YELLOW}Restarting service...${NC}"
if command -v systemctl &> /dev/null; then
sudo systemctl restart transmission-rss-manager
else
echo -e "${RED}Could not restart service automatically.${NC}"
echo -e "Please restart the service manually."
fi
# Update complete
echo -e "${GREEN}${BOLD}Update complete!${NC}"
echo -e "Updated from version $CURRENT_VERSION to $NEW_VERSION"
echo -e "Changes will take effect immediately."
EOL
chmod +x "${SCRIPT_DIR}/scripts/update.sh"
log "INFO" "Created update script: ${SCRIPT_DIR}/scripts/update.sh"
fi
fi
# Step 8: Final setup and permissions
log "INFO" "Finalizing setup..."
finalize_setup || {
log "ERROR" "Setup finalization failed"
exit 1
}
# Installation complete
echo
echo -e "${BOLD}${GREEN}==================================================${NC}"
if [ "$IS_UPDATE" = true ]; then
echo -e "${BOLD}${GREEN} Update Complete! ${NC}"
else
echo -e "${BOLD}${GREEN} Installation Complete! ${NC}"
fi
echo -e "${BOLD}${GREEN}==================================================${NC}"
echo -e "You can access the web interface at: ${BOLD}http://localhost:$PORT${NC} or ${BOLD}http://your-server-ip:$PORT${NC}"
echo -e "You may need to configure your firewall to allow access to port $PORT"
echo
echo -e "${BOLD}Useful Commands:${NC}"
echo -e " To check the service status: ${YELLOW}systemctl status $SERVICE_NAME${NC}"
echo -e " To view logs: ${YELLOW}journalctl -u $SERVICE_NAME${NC}"
echo -e " To restart the service: ${YELLOW}systemctl restart $SERVICE_NAME${NC}"
echo -e " To update the application: ${YELLOW}Use the Update button in the System Status section${NC}"
echo
if [ "$IS_UPDATE" = true ]; then
echo -e "Thank you for updating Transmission RSS Manager!"
echo -e "The service has been restarted with the new version."
else
echo -e "Thank you for installing Transmission RSS Manager!"
fi
echo -e "${BOLD}==================================================${NC}"