Fix remote transmission detection in installer
- Fix bug in dependencies-module.sh that would prompt to install transmission-daemon for remote installations - Add checks for TRANSMISSION_REMOTE flag to correctly handle remote vs local installations - Update version to 2.0.2 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		| @@ -35,8 +35,8 @@ function install_dependencies() { | ||||
|       log "INFO" "Node.js is already installed." | ||||
|     fi | ||||
|  | ||||
|     # Check if we need to install Transmission (only if local transmission was selected) | ||||
|     if [ "$TRANSMISSION_HOST" = "localhost" ] || [ "$TRANSMISSION_HOST" = "127.0.0.1" ]; then | ||||
|     # Check if we need to install Transmission (only if local transmission was selected and not remote) | ||||
|     if [ "$TRANSMISSION_REMOTE" = false ] && ([ "$TRANSMISSION_HOST" = "localhost" ] || [ "$TRANSMISSION_HOST" = "127.0.0.1" ]); then | ||||
|       if ! command_exists transmission-daemon; then | ||||
|         log "INFO" "Local Transmission installation selected, but transmission-daemon is not installed." | ||||
|         read -p "Would you like to install Transmission now? (y/n): " install_transmission | ||||
| @@ -109,8 +109,8 @@ function install_dependencies() { | ||||
|   local dependencies=("node" "npm" "unzip" "nginx") | ||||
|   local missing_deps=() | ||||
|    | ||||
|   # Add transmission to dependencies check if local installation was selected | ||||
|   if [ "$TRANSMISSION_HOST" = "localhost" ] || [ "$TRANSMISSION_HOST" = "127.0.0.1" ]; then | ||||
|   # Add transmission to dependencies check if local installation was selected and not remote | ||||
|   if [ "$TRANSMISSION_REMOTE" = false ] && ([ "$TRANSMISSION_HOST" = "localhost" ] || [ "$TRANSMISSION_HOST" = "127.0.0.1" ]); then | ||||
|     dependencies+=("transmission-daemon") | ||||
|   fi | ||||
|    | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "transmission-rss-manager", | ||||
|   "version": "2.0.1", | ||||
|   "version": "2.0.2", | ||||
|   "description": "A comprehensive web-based tool to automate and manage your Transmission torrent downloads with RSS feed integration and intelligent media organization", | ||||
|   "main": "server.js", | ||||
|   "scripts": { | ||||
|   | ||||
							
								
								
									
										75
									
								
								temp_work/SUMMARY.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								temp_work/SUMMARY.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| # Git-Based Installation and Update System | ||||
|  | ||||
| We've restructured the Transmission RSS Manager to use a git-based approach for installation and updates. Here's how the new system works: | ||||
|  | ||||
| ## New Architecture | ||||
|  | ||||
| 1. **Bootstrap Installer** | ||||
|    - Small, self-contained installer script | ||||
|    - Installs git if needed | ||||
|    - Clones the main repository | ||||
|    - Runs the main installer | ||||
|  | ||||
| 2. **Main Installer** | ||||
|    - Modified to work with git-managed files | ||||
|    - Doesn't need to generate application files | ||||
|    - Only creates config files and sets up services | ||||
|  | ||||
| 3. **Update System** | ||||
|    - Web interface shows current version | ||||
|    - Checks for updates automatically | ||||
|    - One-click update process | ||||
|    - Preserves user configuration | ||||
|  | ||||
| ## Key Files | ||||
|  | ||||
| 1. **bootstrap-installer.sh** | ||||
|    - Entry point for new installations | ||||
|    - Minimal script that pulls everything else from git | ||||
|  | ||||
| 2. **update.sh** | ||||
|    - Located in the scripts/ directory | ||||
|    - Handles git pull and service restart | ||||
|    - Preserves local configuration changes | ||||
|  | ||||
| 3. **System Status UI** | ||||
|    - Added to the dashboard | ||||
|    - Shows version, uptime, and connection status | ||||
|    - Notifies when updates are available | ||||
|  | ||||
| 4. **Server Endpoints** | ||||
|    - `/api/system/status` - Gets current version and system status | ||||
|    - `/api/system/check-updates` - Checks if updates are available | ||||
|    - `/api/system/update` - Triggers the update process | ||||
|  | ||||
| ## Benefits | ||||
|  | ||||
| 1. **Simplified Maintenance** | ||||
|    - Single source of truth in the git repository | ||||
|    - No need to embed code in installation scripts | ||||
|    - Easy to make changes and publish updates | ||||
|  | ||||
| 2. **Better User Experience** | ||||
|    - Users can see when updates are available | ||||
|    - One-click update process | ||||
|    - No need to manually download and run scripts | ||||
|  | ||||
| 3. **Version Control** | ||||
|    - Clear versioning visible to users | ||||
|    - Update history preserved in git | ||||
|    - Easy rollback if needed | ||||
|  | ||||
| ## Implementation Notes | ||||
|  | ||||
| This implementation preserves local configuration by: | ||||
| 1. Stashing local changes before pulling updates | ||||
| 2. Applying those changes back after the update | ||||
| 3. Handling any potential conflicts | ||||
|  | ||||
| The service automatically restarts after updates, ensuring users always have the latest version running. | ||||
|  | ||||
| ## Next Steps | ||||
|  | ||||
| 1. Update the GitHub repository structure to match this new approach | ||||
| 2. Test the installation and update process in a clean environment | ||||
| 3. Consider adding a changelog display in the UI to show what's new in each version | ||||
							
								
								
									
										131
									
								
								temp_work/app-update.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								temp_work/app-update.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | ||||
| // Client-side JavaScript for system status and updates | ||||
| // Add this to the public/js/app.js file | ||||
|  | ||||
| // System status and updates functionality | ||||
| function initSystemStatus() { | ||||
|   // Elements | ||||
|   const versionElement = document.getElementById('system-version'); | ||||
|   const uptimeElement = document.getElementById('uptime'); | ||||
|   const transmissionStatusElement = document.getElementById('transmission-status'); | ||||
|   const updateStatusElement = document.getElementById('update-status'); | ||||
|   const updateAvailableDiv = document.getElementById('update-available'); | ||||
|   const updateButton = document.getElementById('btn-update-now'); | ||||
|   const refreshButton = document.getElementById('btn-refresh-status'); | ||||
|    | ||||
|   // Load system status | ||||
|   function loadSystemStatus() { | ||||
|     fetch('/api/system/status') | ||||
|       .then(response => response.json()) | ||||
|       .then(data => { | ||||
|         if (data.status === 'success') { | ||||
|           versionElement.textContent = data.data.version; | ||||
|           uptimeElement.textContent = data.data.uptime; | ||||
|            | ||||
|           // Update transmission status with icon | ||||
|           if (data.data.transmissionStatus === 'Connected') { | ||||
|             transmissionStatusElement.innerHTML = '<i class="fas fa-check-circle text-success"></i> Connected'; | ||||
|           } else { | ||||
|             transmissionStatusElement.innerHTML = '<i class="fas fa-times-circle text-danger"></i> Disconnected'; | ||||
|           } | ||||
|         } else { | ||||
|           showToast('error', 'Failed to load system status'); | ||||
|         } | ||||
|       }) | ||||
|       .catch(error => { | ||||
|         console.error('Error fetching system status:', error); | ||||
|         showToast('error', 'Failed to connect to server'); | ||||
|       }); | ||||
|   } | ||||
|    | ||||
|   // Check for updates | ||||
|   function checkForUpdates() { | ||||
|     updateStatusElement.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i> Checking...'; | ||||
|     updateAvailableDiv.classList.add('d-none'); | ||||
|      | ||||
|     fetch('/api/system/check-updates') | ||||
|       .then(response => response.json()) | ||||
|       .then(data => { | ||||
|         if (data.status === 'success') { | ||||
|           if (data.data.updateAvailable) { | ||||
|             updateStatusElement.innerHTML = '<i class="fas fa-exclamation-circle text-warning"></i> Update available'; | ||||
|             updateAvailableDiv.classList.remove('d-none'); | ||||
|             updateAvailableDiv.querySelector('span').textContent =  | ||||
|               `A new version is available: ${data.data.currentVersion} → ${data.data.remoteVersion}`; | ||||
|           } else { | ||||
|             updateStatusElement.innerHTML = '<i class="fas fa-check-circle text-success"></i> Up to date'; | ||||
|           } | ||||
|         } else { | ||||
|           updateStatusElement.innerHTML = '<i class="fas fa-times-circle text-danger"></i> Check failed'; | ||||
|           showToast('error', data.message || 'Failed to check for updates'); | ||||
|         } | ||||
|       }) | ||||
|       .catch(error => { | ||||
|         console.error('Error checking for updates:', error); | ||||
|         updateStatusElement.innerHTML = '<i class="fas fa-times-circle text-danger"></i> Check failed'; | ||||
|         showToast('error', 'Failed to connect to server'); | ||||
|       }); | ||||
|   } | ||||
|    | ||||
|   // Apply update | ||||
|   function applyUpdate() { | ||||
|     // Show confirmation dialog | ||||
|     if (!confirm('Are you sure you want to update the application? The service will restart.')) { | ||||
|       return; | ||||
|     } | ||||
|      | ||||
|     // Show loading state | ||||
|     updateButton.disabled = true; | ||||
|     updateButton.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i> Updating...'; | ||||
|     showToast('info', 'Applying update. Please wait...'); | ||||
|      | ||||
|     fetch('/api/system/update', { | ||||
|       method: 'POST', | ||||
|       headers: { | ||||
|         'Content-Type': 'application/json' | ||||
|       } | ||||
|     }) | ||||
|       .then(response => response.json()) | ||||
|       .then(data => { | ||||
|         if (data.status === 'success') { | ||||
|           showToast('success', 'Update applied successfully. The page will reload in 30 seconds.'); | ||||
|           // Set a timer to reload the page after the service has time to restart | ||||
|           setTimeout(() => { | ||||
|             window.location.reload(); | ||||
|           }, 30000); | ||||
|         } else { | ||||
|           updateButton.disabled = false; | ||||
|           updateButton.innerHTML = '<i class="fas fa-download"></i> Update Now'; | ||||
|           showToast('error', data.message || 'Failed to apply update'); | ||||
|         } | ||||
|       }) | ||||
|       .catch(error => { | ||||
|         console.error('Error applying update:', error); | ||||
|         updateButton.disabled = false; | ||||
|         updateButton.innerHTML = '<i class="fas fa-download"></i> Update Now'; | ||||
|         showToast('error', 'Failed to connect to server'); | ||||
|       }); | ||||
|   } | ||||
|    | ||||
|   // Event listeners | ||||
|   if (refreshButton) { | ||||
|     refreshButton.addEventListener('click', () => { | ||||
|       loadSystemStatus(); | ||||
|       checkForUpdates(); | ||||
|     }); | ||||
|   } | ||||
|    | ||||
|   if (updateButton) { | ||||
|     updateButton.addEventListener('click', applyUpdate); | ||||
|   } | ||||
|    | ||||
|   // Initialize | ||||
|   loadSystemStatus(); | ||||
|   checkForUpdates(); | ||||
|    | ||||
|   // Set interval to refresh uptime every minute | ||||
|   setInterval(loadSystemStatus, 60000); | ||||
| } | ||||
|  | ||||
| // Call this function from the main init function | ||||
| // Add this line to your document ready or DOMContentLoaded handler: | ||||
| // initSystemStatus(); | ||||
							
								
								
									
										72
									
								
								temp_work/bootstrap-installer.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								temp_work/bootstrap-installer.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| # Transmission RSS Manager - Bootstrap Installer | ||||
| # This script downloads the latest version from git and runs the setup | ||||
|  | ||||
| # 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 | ||||
| INSTALL_DIR="/opt/trans-install" | ||||
| REPO_URL="https://git.powerdata.dk/masterdraco/transmission-rss-manager.git" | ||||
|  | ||||
| # Check if running as root | ||||
| if [ "$EUID" -ne 0 ]; then | ||||
|   echo -e "${RED}This script must be run as root or with sudo privileges.${NC}" | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| # Display welcome message | ||||
| echo -e "${GREEN}${BOLD}Transmission RSS Manager - Bootstrap Installer${NC}" | ||||
| echo -e "This script will install the latest version from the git repository." | ||||
| echo | ||||
|  | ||||
| # Check for git installation | ||||
| echo -e "${YELLOW}Checking dependencies...${NC}" | ||||
| if ! command -v git &> /dev/null; then | ||||
|   echo -e "Git not found. Installing git..." | ||||
|   apt-get update | ||||
|   apt-get install -y git | ||||
| fi | ||||
|  | ||||
| # Check if installation directory exists | ||||
| if [ -d "$INSTALL_DIR" ]; then | ||||
|   echo -e "${YELLOW}Installation directory already exists.${NC}" | ||||
|   read -p "Do you want to remove it and perform a fresh install? (y/n): " choice | ||||
|   if [[ "$choice" =~ ^[Yy]$ ]]; then | ||||
|     echo "Removing existing installation..." | ||||
|     rm -rf "$INSTALL_DIR" | ||||
|   else | ||||
|     echo -e "${RED}Installation aborted.${NC}" | ||||
|     exit 1 | ||||
|   fi | ||||
| fi | ||||
|  | ||||
| # Create installation directory | ||||
| echo -e "${YELLOW}Creating installation directory...${NC}" | ||||
| mkdir -p "$INSTALL_DIR" | ||||
|  | ||||
| # Clone the repository | ||||
| echo -e "${YELLOW}Cloning the latest version from git...${NC}" | ||||
| git clone "$REPO_URL" "$INSTALL_DIR" | ||||
| if [ $? -ne 0 ]; then | ||||
|   echo -e "${RED}Failed to clone the repository.${NC}" | ||||
|   exit 1 | ||||
| fi | ||||
|  | ||||
| # Run the main installer | ||||
| echo -e "${YELLOW}Running the main installer...${NC}" | ||||
| cd "$INSTALL_DIR" | ||||
| chmod +x main-installer.sh | ||||
| ./main-installer.sh | ||||
|  | ||||
| # Installation complete | ||||
| echo -e "${GREEN}${BOLD}Bootstrap installation complete!${NC}" | ||||
| echo -e "Transmission RSS Manager has been installed in $INSTALL_DIR" | ||||
| echo -e "You can access the web interface at http://localhost:3000" | ||||
| echo | ||||
| echo -e "To update in the future, use the update button in the System Status section of the web interface." | ||||
							
								
								
									
										374
									
								
								temp_work/config-module-updated.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										374
									
								
								temp_work/config-module-updated.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,374 @@ | ||||
| #!/bin/bash | ||||
| # Configuration module for Transmission RSS Manager Installation | ||||
|  | ||||
| # Configuration variables with defaults | ||||
| INSTALL_DIR="/opt/transmission-rss-manager" | ||||
| SERVICE_NAME="transmission-rss-manager" | ||||
| PORT=3000 | ||||
|  | ||||
| # Get default user safely - avoid using root | ||||
| get_default_user() { | ||||
|   local default_user | ||||
|    | ||||
|   # Try logname first to get the user who invoked sudo | ||||
|   if command -v logname &> /dev/null; then | ||||
|     default_user=$(logname 2>/dev/null) | ||||
|   fi | ||||
|    | ||||
|   # If logname failed, try SUDO_USER | ||||
|   if [ -z "$default_user" ] && [ -n "$SUDO_USER" ]; then | ||||
|     default_user="$SUDO_USER" | ||||
|   fi | ||||
|    | ||||
|   # Fallback to current user if both methods failed | ||||
|   if [ -z "$default_user" ]; then | ||||
|     default_user="$(whoami)" | ||||
|   fi | ||||
|    | ||||
|   # Ensure the user is not root | ||||
|   if [ "$default_user" = "root" ]; then | ||||
|     echo "nobody" | ||||
|   else | ||||
|     echo "$default_user" | ||||
|   fi | ||||
| } | ||||
|  | ||||
| # Initialize default user | ||||
| USER=$(get_default_user) | ||||
|  | ||||
| # Transmission configuration variables | ||||
| TRANSMISSION_REMOTE=false | ||||
| TRANSMISSION_HOST="localhost" | ||||
| TRANSMISSION_PORT=9091 | ||||
| TRANSMISSION_USER="" | ||||
| TRANSMISSION_PASS="" | ||||
| TRANSMISSION_RPC_PATH="/transmission/rpc" | ||||
| TRANSMISSION_DOWNLOAD_DIR="/var/lib/transmission-daemon/downloads" | ||||
| TRANSMISSION_DIR_MAPPING="{}" | ||||
|  | ||||
| # Media path defaults | ||||
| MEDIA_DIR="/mnt/media" | ||||
| ENABLE_BOOK_SORTING=true | ||||
|  | ||||
| # Helper function to validate port number | ||||
| validate_port() { | ||||
|   local port="$1" | ||||
|   if [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ]; then | ||||
|     return 0 | ||||
|   else | ||||
|     return 1 | ||||
|   fi | ||||
| } | ||||
|  | ||||
| # Helper function to validate URL hostname | ||||
| validate_hostname() { | ||||
|   local hostname="$1" | ||||
|   if [[ "$hostname" =~ ^[a-zA-Z0-9]([a-zA-Z0-9\-\.]+[a-zA-Z0-9])?$ ]]; then | ||||
|     return 0 | ||||
|   elif [[ "$hostname" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | ||||
|     return 0 | ||||
|   else | ||||
|     return 1 | ||||
|   fi | ||||
| } | ||||
|  | ||||
| function gather_configuration() { | ||||
|   log "INFO" "Starting configuration gathering" | ||||
|   echo -e "${BOLD}Installation Configuration:${NC}" | ||||
|   echo -e "Please provide the following configuration parameters:" | ||||
|   echo | ||||
|  | ||||
|   read -p "Installation directory [$INSTALL_DIR]: " input_install_dir | ||||
|   if [ -n "$input_install_dir" ]; then | ||||
|     # Validate installation directory | ||||
|     if [[ ! "$input_install_dir" =~ ^/ ]]; then | ||||
|       log "WARN" "Installation directory must be an absolute path. Using default." | ||||
|     else | ||||
|       INSTALL_DIR="$input_install_dir" | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   # Using fixed port 3000 to avoid permission issues with ports below 1024 | ||||
|   log "INFO" "Using port 3000 for the web interface" | ||||
|   log "INFO" "This is to avoid permission issues with ports below 1024 (like port 80)" | ||||
|   PORT=3000 | ||||
|  | ||||
|   # Get user | ||||
|   read -p "Run as user [$USER]: " input_user | ||||
|   if [ -n "$input_user" ]; then | ||||
|     # Check if user exists | ||||
|     if id "$input_user" &>/dev/null; then | ||||
|       USER="$input_user" | ||||
|     else | ||||
|       log "WARN" "User $input_user does not exist. Using $USER instead." | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   echo | ||||
|   echo -e "${BOLD}Transmission Configuration:${NC}" | ||||
|   echo -e "Configure connection to your Transmission client:" | ||||
|   echo | ||||
|  | ||||
|   # Ask if Transmission is remote | ||||
|   read -p "Is Transmission running on a remote server? (y/n) [n]: " input_remote | ||||
|   if [[ $input_remote =~ ^[Yy]$ ]]; then | ||||
|     TRANSMISSION_REMOTE=true | ||||
|      | ||||
|     # Get and validate hostname | ||||
|     while true; do | ||||
|       read -p "Remote Transmission host [localhost]: " input_trans_host | ||||
|       if [ -z "$input_trans_host" ]; then | ||||
|         break | ||||
|       elif validate_hostname "$input_trans_host"; then | ||||
|         TRANSMISSION_HOST="$input_trans_host" | ||||
|         break | ||||
|       else | ||||
|         log "WARN" "Invalid hostname format." | ||||
|       fi | ||||
|     done | ||||
|      | ||||
|     # Get and validate port | ||||
|     while true; do | ||||
|       read -p "Remote Transmission port [9091]: " input_trans_port | ||||
|       if [ -z "$input_trans_port" ]; then | ||||
|         break | ||||
|       elif validate_port "$input_trans_port"; then | ||||
|         TRANSMISSION_PORT="$input_trans_port" | ||||
|         break | ||||
|       else | ||||
|         log "WARN" "Invalid port number. Port must be between 1 and 65535." | ||||
|       fi | ||||
|     done | ||||
|      | ||||
|     # Get credentials | ||||
|     read -p "Remote Transmission username []: " input_trans_user | ||||
|     TRANSMISSION_USER=${input_trans_user:-$TRANSMISSION_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 | ||||
|     if [ -n "$input_trans_pass" ]; then | ||||
|       # TODO: In a production environment, consider encrypting this password | ||||
|       TRANSMISSION_PASS="$input_trans_pass" | ||||
|     fi | ||||
|      | ||||
|     read -p "Remote Transmission RPC path [/transmission/rpc]: " input_trans_path | ||||
|     if [ -n "$input_trans_path" ]; then | ||||
|       # Ensure path starts with / for consistency | ||||
|       if [[ ! "$input_trans_path" =~ ^/ ]]; then | ||||
|         input_trans_path="/$input_trans_path" | ||||
|       fi | ||||
|       TRANSMISSION_RPC_PATH="$input_trans_path" | ||||
|     fi | ||||
|      | ||||
|     # 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: " 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: " LOCAL_DOWNLOAD_DIR | ||||
|     LOCAL_DOWNLOAD_DIR=${LOCAL_DOWNLOAD_DIR:-"/mnt/transmission-downloads"} | ||||
|      | ||||
|     # Create mapping JSON - use proper JSON escaping for directory paths | ||||
|     REMOTE_DOWNLOAD_DIR_ESCAPED=$(echo "$REMOTE_DOWNLOAD_DIR" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g') | ||||
|     LOCAL_DOWNLOAD_DIR_ESCAPED=$(echo "$LOCAL_DOWNLOAD_DIR" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g') | ||||
|      | ||||
|     TRANSMISSION_DIR_MAPPING="{\"$REMOTE_DOWNLOAD_DIR_ESCAPED\": \"$LOCAL_DOWNLOAD_DIR_ESCAPED\"}" | ||||
|      | ||||
|     # Create the local directory | ||||
|     if ! mkdir -p "$LOCAL_DOWNLOAD_DIR"; then | ||||
|       log "ERROR" "Failed to create local download directory: $LOCAL_DOWNLOAD_DIR" | ||||
|     else | ||||
|       if ! chown -R "$USER:$USER" "$LOCAL_DOWNLOAD_DIR"; then | ||||
|         log "ERROR" "Failed to set permissions on local download directory: $LOCAL_DOWNLOAD_DIR" | ||||
|       fi | ||||
|     fi | ||||
|      | ||||
|     # Ask if want to add more mappings | ||||
|     while true; do | ||||
|       read -p "Add another directory mapping? (y/n) [n]: " add_another | ||||
|       if [[ ! $add_another =~ ^[Yy]$ ]]; then | ||||
|         break | ||||
|       fi | ||||
|        | ||||
|       read -p "Remote directory path: " remote_dir | ||||
|       read -p "Corresponding local directory path: " local_dir | ||||
|        | ||||
|       if [ -n "$remote_dir" ] && [ -n "$local_dir" ]; then | ||||
|         # Escape directory paths for JSON | ||||
|         remote_dir_escaped=$(echo "$remote_dir" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g') | ||||
|         local_dir_escaped=$(echo "$local_dir" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g') | ||||
|          | ||||
|         # Update mapping JSON (proper JSON manipulation) | ||||
|         # Remove the closing brace, add a comma and the new mapping, then close with brace | ||||
|         TRANSMISSION_DIR_MAPPING="${TRANSMISSION_DIR_MAPPING%\}}, \"$remote_dir_escaped\": \"$local_dir_escaped\"}" | ||||
|          | ||||
|         # Create the local directory | ||||
|         if ! mkdir -p "$local_dir"; then | ||||
|           log "ERROR" "Failed to create directory: $local_dir" | ||||
|         else | ||||
|           if ! chown -R "$USER:$USER" "$local_dir"; then | ||||
|             log "WARN" "Failed to set permissions on directory: $local_dir" | ||||
|           fi | ||||
|           log "INFO" "Mapping added: $remote_dir → $local_dir" | ||||
|         fi | ||||
|       fi | ||||
|     done | ||||
|      | ||||
|     # Set Transmission download dir for configuration | ||||
|     TRANSMISSION_DOWNLOAD_DIR=$REMOTE_DOWNLOAD_DIR | ||||
|   else | ||||
|     # Local Transmission selected | ||||
|     echo -e "${YELLOW}You've selected to use a local Transmission installation.${NC}" | ||||
|      | ||||
|     # Check if Transmission is already installed | ||||
|     if command -v transmission-daemon &> /dev/null; then | ||||
|       echo -e "${GREEN}Transmission is already installed on this system.${NC}" | ||||
|     else | ||||
|       echo -e "${YELLOW}NOTE: Transmission does not appear to be installed on this system.${NC}" | ||||
|       echo -e "${YELLOW}You will be prompted to install it during the dependency installation step.${NC}" | ||||
|     fi | ||||
|      | ||||
|     # Get and validate port | ||||
|     while true; do | ||||
|       read -p "Local Transmission port [9091]: " input_trans_port | ||||
|       if [ -z "$input_trans_port" ]; then | ||||
|         break | ||||
|       elif validate_port "$input_trans_port"; then | ||||
|         TRANSMISSION_PORT="$input_trans_port" | ||||
|         break | ||||
|       else | ||||
|         log "WARN" "Invalid port number. Port must be between 1 and 65535." | ||||
|       fi | ||||
|     done | ||||
|      | ||||
|     # Get credentials if any | ||||
|     read -p "Local Transmission username (leave empty if authentication is disabled) []: " input_trans_user | ||||
|     TRANSMISSION_USER=${input_trans_user:-$TRANSMISSION_USER} | ||||
|      | ||||
|     if [ -n "$input_trans_user" ]; then | ||||
|       # Use read -s for password to hide it | ||||
|       read -s -p "Local Transmission password []: " input_trans_pass | ||||
|       echo  # Add a newline after the password input | ||||
|       if [ -n "$input_trans_pass" ]; then | ||||
|         TRANSMISSION_PASS="$input_trans_pass" | ||||
|       fi | ||||
|     fi | ||||
|      | ||||
|     read -p "Transmission download directory [/var/lib/transmission-daemon/downloads]: " input_trans_dir | ||||
|     if [ -n "$input_trans_dir" ]; then | ||||
|       if [[ ! "$input_trans_dir" =~ ^/ ]]; then | ||||
|         log "WARN" "Download directory must be an absolute path. Using default." | ||||
|       else | ||||
|         TRANSMISSION_DOWNLOAD_DIR="$input_trans_dir" | ||||
|       fi | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   echo | ||||
|   echo -e "${BOLD}Media Destination Configuration:${NC}" | ||||
|  | ||||
|   read -p "Media destination base directory [/mnt/media]: " input_media_dir | ||||
|   if [ -n "$input_media_dir" ]; then | ||||
|     if [[ ! "$input_media_dir" =~ ^/ ]]; then | ||||
|       log "WARN" "Media directory must be an absolute path. Using default." | ||||
|     else | ||||
|       MEDIA_DIR="$input_media_dir" | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   # Ask about enabling book/magazine sorting | ||||
|   echo | ||||
|   echo -e "${BOLD}Content Type Configuration:${NC}" | ||||
|   read -p "Enable book and magazine sorting? (y/n) [y]: " input_book_sorting | ||||
|   if [[ $input_book_sorting =~ ^[Nn]$ ]]; then | ||||
|     ENABLE_BOOK_SORTING=false | ||||
|   else | ||||
|     ENABLE_BOOK_SORTING=true | ||||
|   fi | ||||
|    | ||||
|   # Security configuration | ||||
|   echo | ||||
|   echo -e "${BOLD}Security Configuration:${NC}" | ||||
|    | ||||
|   # Ask about enabling authentication | ||||
|   read -p "Enable authentication? (y/n) [n]: " input_auth_enabled | ||||
|   AUTH_ENABLED=false | ||||
|   ADMIN_USERNAME="" | ||||
|   ADMIN_PASSWORD="" | ||||
|    | ||||
|   if [[ $input_auth_enabled =~ ^[Yy]$ ]]; then | ||||
|     AUTH_ENABLED=true | ||||
|      | ||||
|     # Get admin username and password | ||||
|     read -p "Admin username [admin]: " input_admin_username | ||||
|     ADMIN_USERNAME=${input_admin_username:-"admin"} | ||||
|      | ||||
|     # Use read -s for password to avoid showing it on screen | ||||
|     read -s -p "Admin password: " input_admin_password | ||||
|     echo  # Add a newline after the password input | ||||
|      | ||||
|     if [ -z "$input_admin_password" ]; then | ||||
|       # Generate a random password if none provided | ||||
|       ADMIN_PASSWORD=$(openssl rand -base64 12) | ||||
|       echo -e "${YELLOW}Generated random admin password: $ADMIN_PASSWORD${NC}" | ||||
|       echo -e "${YELLOW}Please save this password somewhere safe!${NC}" | ||||
|     else | ||||
|       ADMIN_PASSWORD="$input_admin_password" | ||||
|     fi | ||||
|   fi | ||||
|    | ||||
|   # Ask about enabling HTTPS | ||||
|   read -p "Enable HTTPS? (requires SSL certificate) (y/n) [n]: " input_https_enabled | ||||
|   HTTPS_ENABLED=false | ||||
|   SSL_CERT_PATH="" | ||||
|   SSL_KEY_PATH="" | ||||
|    | ||||
|   if [[ $input_https_enabled =~ ^[Yy]$ ]]; then | ||||
|     HTTPS_ENABLED=true | ||||
|      | ||||
|     # Get SSL certificate paths | ||||
|     read -p "SSL certificate path: " input_ssl_cert_path | ||||
|     if [ -n "$input_ssl_cert_path" ]; then | ||||
|       # Check if file exists | ||||
|       if [ -f "$input_ssl_cert_path" ]; then | ||||
|         SSL_CERT_PATH="$input_ssl_cert_path" | ||||
|       else | ||||
|         log "WARN" "SSL certificate file not found. HTTPS will be disabled." | ||||
|         HTTPS_ENABLED=false | ||||
|       fi | ||||
|     else | ||||
|       log "WARN" "SSL certificate path not provided. HTTPS will be disabled." | ||||
|       HTTPS_ENABLED=false | ||||
|     fi | ||||
|      | ||||
|     # Only ask for key if cert was found | ||||
|     if [ "$HTTPS_ENABLED" = true ]; then | ||||
|       read -p "SSL key path: " input_ssl_key_path | ||||
|       if [ -n "$input_ssl_key_path" ]; then | ||||
|         # Check if file exists | ||||
|         if [ -f "$input_ssl_key_path" ]; then | ||||
|           SSL_KEY_PATH="$input_ssl_key_path" | ||||
|         else | ||||
|           log "WARN" "SSL key file not found. HTTPS will be disabled." | ||||
|           HTTPS_ENABLED=false | ||||
|         fi | ||||
|       else | ||||
|         log "WARN" "SSL key path not provided. HTTPS will be disabled." | ||||
|         HTTPS_ENABLED=false | ||||
|       fi | ||||
|     fi | ||||
|   fi | ||||
|  | ||||
|   echo | ||||
|   log "INFO" "Configuration gathering complete" | ||||
|   echo -e "${GREEN}Configuration complete!${NC}" | ||||
|   echo | ||||
| } | ||||
							
								
								
									
										184
									
								
								temp_work/dependencies-module-updated.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								temp_work/dependencies-module-updated.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| #!/bin/bash | ||||
| # Dependencies module for Transmission RSS Manager Installation | ||||
|  | ||||
| function install_dependencies() { | ||||
|   log "INFO" "Installing dependencies..." | ||||
|  | ||||
|   # Check for package manager | ||||
|   if command -v apt-get &> /dev/null; then | ||||
|     # Update package index | ||||
|     apt-get update | ||||
|  | ||||
|     # Install Node.js and npm if not already installed | ||||
|     if ! command_exists node; then | ||||
|       log "INFO" "Installing Node.js and npm..." | ||||
|       apt-get install -y ca-certificates curl gnupg | ||||
|       mkdir -p /etc/apt/keyrings | ||||
|        | ||||
|       # Check if download succeeds | ||||
|       if ! curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg; then | ||||
|         log "ERROR" "Failed to download Node.js GPG key" | ||||
|         exit 1 | ||||
|       fi | ||||
|        | ||||
|       echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" > /etc/apt/sources.list.d/nodesource.list | ||||
|        | ||||
|       # Update again after adding repo | ||||
|       apt-get update | ||||
|        | ||||
|       # Install nodejs | ||||
|       if ! apt-get install -y nodejs; then | ||||
|         log "ERROR" "Failed to install Node.js" | ||||
|         exit 1 | ||||
|       fi | ||||
|     else | ||||
|       log "INFO" "Node.js is already installed." | ||||
|     fi | ||||
|  | ||||
|     # Check if we need to install Transmission (only if local transmission was selected and not remote) | ||||
|     if [ "$TRANSMISSION_REMOTE" = false ] && ([ "$TRANSMISSION_HOST" = "localhost" ] || [ "$TRANSMISSION_HOST" = "127.0.0.1" ]); then | ||||
|       if ! command_exists transmission-daemon; then | ||||
|         log "INFO" "Local Transmission installation selected, but transmission-daemon is not installed." | ||||
|         read -p "Would you like to install Transmission now? (y/n): " install_transmission | ||||
|          | ||||
|         if [[ "$install_transmission" =~ ^[Yy]$ ]]; then | ||||
|           log "INFO" "Installing Transmission..." | ||||
|           if ! apt-get install -y transmission-daemon; then | ||||
|             log "ERROR" "Failed to install Transmission" | ||||
|             log "WARN" "You will need to install Transmission manually before using this application." | ||||
|           else | ||||
|             # Stop transmission-daemon to allow configuration changes | ||||
|             systemctl stop transmission-daemon | ||||
|              | ||||
|             # Set default settings | ||||
|             TRANSMISSION_SETTINGS_DIR="/var/lib/transmission-daemon/info" | ||||
|             if [ -f "$TRANSMISSION_SETTINGS_DIR/settings.json" ]; then | ||||
|               # Backup original settings | ||||
|               cp "$TRANSMISSION_SETTINGS_DIR/settings.json" "$TRANSMISSION_SETTINGS_DIR/settings.json.bak" | ||||
|                | ||||
|               # Update RPC settings to allow our app to connect | ||||
|               sed -i 's/"rpc-authentication-required": true,/"rpc-authentication-required": false,/g' "$TRANSMISSION_SETTINGS_DIR/settings.json" | ||||
|               sed -i 's/"rpc-whitelist-enabled": true,/"rpc-whitelist-enabled": false,/g' "$TRANSMISSION_SETTINGS_DIR/settings.json" | ||||
|                | ||||
|               log "INFO" "Transmission has been configured for local access." | ||||
|             else | ||||
|               log "WARN" "Could not find Transmission settings file. You may need to configure Transmission manually." | ||||
|             fi | ||||
|              | ||||
|             # Start transmission-daemon | ||||
|             systemctl start transmission-daemon | ||||
|             log "INFO" "Transmission has been installed and started." | ||||
|           fi | ||||
|         else | ||||
|           log "WARN" "Transmission installation skipped. You will need to install it manually." | ||||
|         fi | ||||
|       else | ||||
|         log "INFO" "Transmission is already installed." | ||||
|       fi | ||||
|     fi | ||||
|  | ||||
|     # Install additional dependencies | ||||
|     log "INFO" "Installing additional dependencies..." | ||||
|     # Try to install unrar-free if unrar is not available | ||||
|     if ! apt-get install -y unrar 2>/dev/null; then | ||||
|       log "INFO" "unrar not available, trying unrar-free instead..." | ||||
|       apt-get install -y unrar-free | ||||
|     fi | ||||
|      | ||||
|     # Install other dependencies | ||||
|     apt-get install -y unzip p7zip-full | ||||
|      | ||||
|     # Try to install nginx | ||||
|     apt-get install -y nginx || log "WARN" "Nginx installation failed, web interface may not be accessible" | ||||
|   else | ||||
|     log "ERROR" "This installer requires apt-get package manager" | ||||
|     log "INFO" "Please install the following dependencies manually:" | ||||
|     log "INFO" "- Node.js (v18.x)" | ||||
|     log "INFO" "- npm" | ||||
|     log "INFO" "- unrar" | ||||
|     log "INFO" "- unzip" | ||||
|     log "INFO" "- p7zip-full" | ||||
|     log "INFO" "- nginx" | ||||
|     if [ "$TRANSMISSION_REMOTE" = false ] && ([ "$TRANSMISSION_HOST" = "localhost" ] || [ "$TRANSMISSION_HOST" = "127.0.0.1" ]); then | ||||
|       log "INFO" "- transmission-daemon" | ||||
|     fi | ||||
|     exit 1 | ||||
|   fi | ||||
|  | ||||
|   # Check if all dependencies were installed successfully | ||||
|   local dependencies=("node" "npm" "unzip" "nginx") | ||||
|   local missing_deps=() | ||||
|    | ||||
|   # Add transmission to dependencies check if local installation was selected and not remote | ||||
|   if [ "$TRANSMISSION_REMOTE" = false ] && ([ "$TRANSMISSION_HOST" = "localhost" ] || [ "$TRANSMISSION_HOST" = "127.0.0.1" ]); then | ||||
|     dependencies+=("transmission-daemon") | ||||
|   fi | ||||
|    | ||||
|   for dep in "${dependencies[@]}"; do | ||||
|     if ! command_exists "$dep"; then | ||||
|       missing_deps+=("$dep") | ||||
|     fi | ||||
|   done | ||||
|    | ||||
|   # Check for either unrar or unrar-free | ||||
|   if ! command_exists "unrar" && ! command_exists "unrar-free"; then | ||||
|     missing_deps+=("unrar") | ||||
|   fi | ||||
|    | ||||
|   # Check for either 7z or 7za (from p7zip-full) | ||||
|   if ! command_exists "7z" && ! command_exists "7za"; then | ||||
|     missing_deps+=("p7zip") | ||||
|   fi | ||||
|    | ||||
|   if [ ${#missing_deps[@]} -eq 0 ]; then | ||||
|     log "INFO" "All dependencies installed successfully." | ||||
|   else | ||||
|     log "ERROR" "Failed to install some dependencies: ${missing_deps[*]}" | ||||
|     log "WARN" "Please install them manually and rerun this script." | ||||
|      | ||||
|     # More helpful information based on which deps are missing | ||||
|     if [[ " ${missing_deps[*]} " =~ " node " ]]; then | ||||
|       log "INFO" "To install Node.js manually, visit: https://nodejs.org/en/download/" | ||||
|     fi | ||||
|      | ||||
|     if [[ " ${missing_deps[*]} " =~ " nginx " ]]; then | ||||
|       log "INFO" "To install nginx manually: sudo apt-get install nginx" | ||||
|     fi | ||||
|      | ||||
|     if [[ " ${missing_deps[*]} " =~ " transmission-daemon " ]]; then | ||||
|       log "INFO" "To install Transmission manually: sudo apt-get install transmission-daemon" | ||||
|       log "INFO" "After installation, you may need to configure it by editing /var/lib/transmission-daemon/info/settings.json" | ||||
|     fi | ||||
|      | ||||
|     exit 1 | ||||
|   fi | ||||
| } | ||||
|  | ||||
| function create_directories() { | ||||
|   log "INFO" "Creating installation directories..." | ||||
|    | ||||
|   # Check if INSTALL_DIR is defined | ||||
|   if [ -z "$INSTALL_DIR" ]; then | ||||
|     log "ERROR" "INSTALL_DIR is not defined" | ||||
|     exit 1 | ||||
|   fi | ||||
|    | ||||
|   # Create directories and check for errors | ||||
|   DIRECTORIES=( | ||||
|     "$INSTALL_DIR" | ||||
|     "$INSTALL_DIR/logs" | ||||
|     "$INSTALL_DIR/public/js" | ||||
|     "$INSTALL_DIR/public/css" | ||||
|     "$INSTALL_DIR/modules" | ||||
|     "$INSTALL_DIR/data" | ||||
|   ) | ||||
|    | ||||
|   for dir in "${DIRECTORIES[@]}"; do | ||||
|     if ! mkdir -p "$dir"; then | ||||
|       log "ERROR" "Failed to create directory: $dir" | ||||
|       exit 1 | ||||
|     fi | ||||
|   done | ||||
|    | ||||
|   log "INFO" "Directories created successfully." | ||||
| } | ||||
							
								
								
									
										241
									
								
								temp_work/main-installer-modified.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								temp_work/main-installer-modified.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,241 @@ | ||||
| #!/bin/bash | ||||
| # Transmission RSS Manager Modular Installer | ||||
| # Modified to work with the git-based approach | ||||
|  | ||||
| # Set script to exit on error | ||||
| set -e | ||||
|  | ||||
| # Text formatting | ||||
| BOLD='\033[1m' | ||||
| GREEN='\033[0;32m' | ||||
| YELLOW='\033[0;33m' | ||||
| RED='\033[0;31m' | ||||
| NC='\033[0m' # No Color | ||||
|  | ||||
| # Print header | ||||
| echo -e "${BOLD}==================================================${NC}" | ||||
| echo -e "${BOLD}     Transmission RSS Manager Installer           ${NC}" | ||||
| echo -e "${BOLD}     Version 1.2.0 - 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 | ||||
|  | ||||
| # Get current directory | ||||
| SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" | ||||
|  | ||||
| # Check for installation type | ||||
| IS_UPDATE=false | ||||
| if [ -f "${SCRIPT_DIR}/config.json" ]; then | ||||
|   IS_UPDATE=true | ||||
|   echo -e "${YELLOW}Existing installation detected. Running in update mode.${NC}" | ||||
|   echo -e "${GREEN}Your existing configuration will be preserved.${NC}" | ||||
| else | ||||
|   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" | ||||
| ) | ||||
|  | ||||
| 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 module files | ||||
| source "${SCRIPT_DIR}/modules/utils-module.sh" # Load utilities first for logging | ||||
| source "${SCRIPT_DIR}/modules/config-module.sh" | ||||
| source "${SCRIPT_DIR}/modules/dependencies-module.sh" | ||||
| source "${SCRIPT_DIR}/modules/service-setup-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..." | ||||
|  | ||||
| # Step 1: Gather configuration from user | ||||
| log "INFO" "Gathering configuration..." | ||||
| gather_configuration || { | ||||
|   log "ERROR" "Configuration gathering failed" | ||||
|   exit 1 | ||||
| } | ||||
|  | ||||
| # 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..." | ||||
| 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 | ||||
| log "INFO" "Installing npm dependencies..." | ||||
| cd "$SCRIPT_DIR" | ||||
| npm install || { | ||||
|   log "ERROR" "NPM installation failed" | ||||
|   exit 1 | ||||
| } | ||||
|  | ||||
| # Step 7: Set up update script | ||||
| log "INFO" "Setting up update script..." | ||||
| mkdir -p "${SCRIPT_DIR}/scripts" | ||||
| cp "${SCRIPT_DIR}/scripts/update.sh" "${SCRIPT_DIR}/scripts/update.sh" 2>/dev/null || { | ||||
|   # If copy fails, it probably doesn't exist, so we'll create it | ||||
|   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" | ||||
| } | ||||
|  | ||||
| # 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}" | ||||
| echo -e "${BOLD}${GREEN}          Installation Complete!                  ${NC}" | ||||
| 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 | ||||
| echo -e "Thank you for installing Transmission RSS Manager!" | ||||
| echo -e "${BOLD}==================================================${NC}" | ||||
							
								
								
									
										84
									
								
								temp_work/scripts/update.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								temp_work/scripts/update.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| #!/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." | ||||
							
								
								
									
										146
									
								
								temp_work/server-endpoints.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								temp_work/server-endpoints.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| // Version and update endpoints to be added to server.js | ||||
|  | ||||
| // Add these imports at the top of server.js | ||||
| const { exec } = require('child_process'); | ||||
| const { promisify } = require('util'); | ||||
| const execAsync = promisify(exec); | ||||
| const fs = require('fs'); | ||||
| const path = require('path'); | ||||
|  | ||||
| // Add these endpoints | ||||
|  | ||||
| // Get system status including version and uptime | ||||
| app.get('/api/system/status', async (req, res) => { | ||||
|   try { | ||||
|     // Get package.json for version info | ||||
|     const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')); | ||||
|     const version = packageJson.version; | ||||
|      | ||||
|     // Get system uptime | ||||
|     const uptimeSeconds = Math.floor(process.uptime()); | ||||
|     const hours = Math.floor(uptimeSeconds / 3600); | ||||
|     const minutes = Math.floor((uptimeSeconds % 3600) / 60); | ||||
|     const seconds = uptimeSeconds % 60; | ||||
|     const uptime = `${hours}h ${minutes}m ${seconds}s`; | ||||
|      | ||||
|     // Check transmission connection | ||||
|     let transmissionStatus = 'Connected'; | ||||
|     try { | ||||
|       await transmissionClient.sessionGet(); | ||||
|     } catch (err) { | ||||
|       transmissionStatus = 'Disconnected'; | ||||
|     } | ||||
|      | ||||
|     res.json({ | ||||
|       status: 'success', | ||||
|       data: { | ||||
|         version, | ||||
|         uptime, | ||||
|         transmissionStatus | ||||
|       } | ||||
|     }); | ||||
|   } catch (error) { | ||||
|     console.error('Error getting system status:', error); | ||||
|     res.status(500).json({ | ||||
|       status: 'error', | ||||
|       message: 'Failed to get system status' | ||||
|     }); | ||||
|   } | ||||
| }); | ||||
|  | ||||
| // Check for updates | ||||
| app.get('/api/system/check-updates', async (req, res) => { | ||||
|   try { | ||||
|     // Check if git is available and if this is a git repository | ||||
|     const isGitRepo = fs.existsSync(path.join(__dirname, '.git')); | ||||
|     if (!isGitRepo) { | ||||
|       return res.json({ | ||||
|         status: 'error', | ||||
|         message: 'This installation is not set up for updates. Please use the bootstrap installer.' | ||||
|       }); | ||||
|     } | ||||
|      | ||||
|     // Get current version | ||||
|     const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')); | ||||
|     const currentVersion = packageJson.version; | ||||
|      | ||||
|     // Fetch latest updates without applying them | ||||
|     await execAsync('git fetch'); | ||||
|      | ||||
|     // Check if we're behind the remote repository | ||||
|     const { stdout } = await execAsync('git rev-list HEAD..origin/main --count'); | ||||
|     const behindCount = parseInt(stdout.trim()); | ||||
|      | ||||
|     if (behindCount > 0) { | ||||
|       // Get the new version from the remote package.json | ||||
|       const { stdout: remotePackageJson } = await execAsync('git show origin/main:package.json'); | ||||
|       const remotePackage = JSON.parse(remotePackageJson); | ||||
|       const remoteVersion = remotePackage.version; | ||||
|        | ||||
|       return res.json({ | ||||
|         status: 'success', | ||||
|         data: { | ||||
|           updateAvailable: true, | ||||
|           currentVersion, | ||||
|           remoteVersion, | ||||
|           commitsBehind: behindCount | ||||
|         } | ||||
|       }); | ||||
|     } else { | ||||
|       return res.json({ | ||||
|         status: 'success', | ||||
|         data: { | ||||
|           updateAvailable: false, | ||||
|           currentVersion | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   } catch (error) { | ||||
|     console.error('Error checking for updates:', error); | ||||
|     res.status(500).json({ | ||||
|       status: 'error', | ||||
|       message: 'Failed to check for updates' | ||||
|     }); | ||||
|   } | ||||
| }); | ||||
|  | ||||
| // Apply updates | ||||
| app.post('/api/system/update', async (req, res) => { | ||||
|   try { | ||||
|     // Check if git is available and if this is a git repository | ||||
|     const isGitRepo = fs.existsSync(path.join(__dirname, '.git')); | ||||
|     if (!isGitRepo) { | ||||
|       return res.status(400).json({ | ||||
|         status: 'error', | ||||
|         message: 'This installation is not set up for updates. Please use the bootstrap installer.' | ||||
|       }); | ||||
|     } | ||||
|      | ||||
|     // Run the update script | ||||
|     const updateScriptPath = path.join(__dirname, 'scripts', 'update.sh'); | ||||
|      | ||||
|     // Make sure the update script is executable | ||||
|     await execAsync(`chmod +x ${updateScriptPath}`); | ||||
|      | ||||
|     // Execute the update script | ||||
|     const { stdout, stderr } = await execAsync(updateScriptPath); | ||||
|      | ||||
|     // If we get here, the update was successful | ||||
|     // The service will be restarted by the update script | ||||
|     res.json({ | ||||
|       status: 'success', | ||||
|       message: 'Update applied successfully. The service will restart.', | ||||
|       data: { | ||||
|         output: stdout, | ||||
|         errors: stderr | ||||
|       } | ||||
|     }); | ||||
|   } catch (error) { | ||||
|     console.error('Error applying update:', error); | ||||
|     res.status(500).json({ | ||||
|       status: 'error', | ||||
|       message: 'Failed to apply update', | ||||
|       error: error.message | ||||
|     }); | ||||
|   } | ||||
| }); | ||||
							
								
								
									
										41
									
								
								temp_work/system-status.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								temp_work/system-status.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| <!-- This HTML block will be inserted into the index.html dashboard --> | ||||
| <div class="row"> | ||||
|     <div class="col-md-4 mb-3"> | ||||
|         <div class="card"> | ||||
|             <div class="card-header"> | ||||
|                 <h4><i class="fas fa-info-circle"></i> System Status</h4> | ||||
|             </div> | ||||
|             <div class="card-body"> | ||||
|                 <div class="status-item"> | ||||
|                     <span class="status-label">Version:</span> | ||||
|                     <span id="system-version" class="status-value">Loading...</span> | ||||
|                 </div> | ||||
|                 <div class="status-item"> | ||||
|                     <span class="status-label">Running since:</span> | ||||
|                     <span id="uptime" class="status-value">Loading...</span> | ||||
|                 </div> | ||||
|                 <div class="status-item"> | ||||
|                     <span class="status-label">Transmission:</span> | ||||
|                     <span id="transmission-status" class="status-value"> | ||||
|                         <i class="fas fa-circle-notch fa-spin"></i> Checking... | ||||
|                     </span> | ||||
|                 </div> | ||||
|                 <div class="status-item"> | ||||
|                     <span class="status-label">Update:</span> | ||||
|                     <span id="update-status" class="status-value"> | ||||
|                         <i class="fas fa-circle-notch fa-spin"></i> Checking... | ||||
|                     </span> | ||||
|                 </div> | ||||
|                 <div id="update-available" class="mt-3 d-none"> | ||||
|                     <div class="alert alert-info"> | ||||
|                         <i class="fas fa-arrow-circle-up"></i>  | ||||
|                         <span>A new version is available!</span> | ||||
|                         <button id="btn-update-now" class="btn btn-sm btn-primary ml-2"> | ||||
|                             <i class="fas fa-download"></i> Update Now | ||||
|                         </button> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
							
								
								
									
										84
									
								
								temp_work/update.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								temp_work/update.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| #!/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." | ||||
		Reference in New Issue
	
	Block a user