#!/bin/bash # Utilities module for Transmission RSS Manager Installation # Function to log a message with timestamp function log() { local level=$1 local message=$2 local timestamp=$(date '+%Y-%m-%d %H:%M:%S') case $level in "INFO") echo -e "${timestamp} ${GREEN}[INFO]${NC} $message" ;; "WARN") echo -e "${timestamp} ${YELLOW}[WARN]${NC} $message" ;; "ERROR") echo -e "${timestamp} ${RED}[ERROR]${NC} $message" ;; "DEBUG") if [ "${DEBUG_ENABLED}" = "true" ]; then echo -e "${timestamp} ${BOLD}[DEBUG]${NC} $message" fi ;; *) echo -e "${timestamp} [LOG] $message" ;; esac # If log file is specified, also write to log file if [ -n "${LOG_FILE}" ]; then echo "${timestamp} [${level}] ${message}" >> "${LOG_FILE}" fi } # Function to check if a command exists function command_exists() { command -v "$1" &> /dev/null } # Function to backup a file before modifying it function backup_file() { local file=$1 if [ -f "$file" ]; then local backup="${file}.bak.$(date +%Y%m%d%H%M%S)" cp "$file" "$backup" log "INFO" "Created backup of $file at $backup" echo "$backup" fi } # Function to manage config file updates function update_config_file() { local config_file=$1 local is_update=$2 if [ "$is_update" = true ] && [ -f "$config_file" ]; then # Backup the existing config file local backup_file=$(backup_file "$config_file") log "INFO" "Existing configuration backed up to $backup_file" # We'll let the server.js handle merging the config log "INFO" "Existing configuration will be preserved" # Update the config version if needed local current_version=$(grep -o '"version": "[^"]*"' "$config_file" | cut -d'"' -f4) if [ -n "$current_version" ]; then local new_version="2.0.0" if [ "$current_version" != "$new_version" ]; then log "INFO" "Updating config version from $current_version to $new_version" sed -i "s/\"version\": \"$current_version\"/\"version\": \"$new_version\"/" "$config_file" fi fi return 0 else # New installation, config file will be created by finalize_setup log "INFO" "New configuration will be created" return 1 fi } # Function to create a directory if it doesn't exist function create_dir_if_not_exists() { local dir=$1 local owner=$2 if [ ! -d "$dir" ]; then mkdir -p "$dir" log "INFO" "Created directory: $dir" if [ -n "$owner" ]; then chown -R "$owner" "$dir" log "INFO" "Set ownership of $dir to $owner" fi fi } # Function to finalize the setup (permissions, etc.) # Function to ensure NPM packages are properly installed function ensure_npm_packages() { local install_dir=$1 # First ensure the installation directory exists if [ ! -d "$install_dir" ]; then log "INFO" "Creating installation directory: $install_dir" mkdir -p "$install_dir" if [ $? -ne 0 ]; then log "ERROR" "Failed to create installation directory: $install_dir" return 1 fi fi # Ensure data directory exists if [ ! -d "$install_dir/data" ]; then log "INFO" "Creating data directory: $install_dir/data" mkdir -p "$install_dir/data" if [ $? -ne 0 ]; then log "ERROR" "Failed to create data directory: $install_dir/data" return 1 fi # Initialize empty data files echo "[]" > "$install_dir/data/rss-feeds.json" echo "[]" > "$install_dir/data/rss-items.json" log "INFO" "Initialized empty data files" fi # Ensure package.json exists in the installation directory if [ ! -f "$install_dir/package.json" ]; then log "INFO" "Copying package.json to installation directory..." cp "$SCRIPT_DIR/package.json" "$install_dir/package.json" if [ $? -ne 0 ]; then log "ERROR" "Failed to copy package.json to installation directory" return 1 fi fi # Install NPM packages if not already installed or if it's an update if [ ! -d "$install_dir/node_modules" ] || [ "$IS_UPDATE" = "true" ]; then log "INFO" "Installing NPM packages in $install_dir..." # Save current directory local current_dir=$(pwd) # Change to install directory and install packages cd "$install_dir" if [ $? -ne 0 ]; then log "ERROR" "Failed to change to installation directory: $install_dir" return 1 fi npm install if [ $? -ne 0 ]; then log "ERROR" "NPM installation failed in $install_dir" cd "$current_dir" # Return to original directory return 1 fi # Return to original directory cd "$current_dir" log "INFO" "NPM packages successfully installed in $install_dir" else log "INFO" "NPM packages appear to be already installed in $install_dir, skipping" fi return 0 } function finalize_setup() { log "INFO" "Setting up final permissions and configurations..." # Ensure logs directory exists mkdir -p "$INSTALL_DIR/logs" log "INFO" "Created logs directory: $INSTALL_DIR/logs" # Ensure CONFIG_DIR exists if [ ! -d "$CONFIG_DIR" ]; then mkdir -p "$CONFIG_DIR" log "INFO" "Created configuration directory: $CONFIG_DIR" chown -R "$USER:$USER" "$CONFIG_DIR" fi # Check if the config symlink exists, create it if not if [ ! -L "$INSTALL_DIR/config.json" ] || [ ! -e "$INSTALL_DIR/config.json" ]; then # If there's a real file at INSTALL_DIR/config.json (not a symlink), move it to CONFIG_DIR if [ -f "$INSTALL_DIR/config.json" ] && [ ! -L "$INSTALL_DIR/config.json" ]; then log "INFO" "Moving existing config.json to $CONFIG_DIR" mv "$INSTALL_DIR/config.json" "$CONFIG_DIR/config.json" fi # Create the symlink ln -sf "$CONFIG_DIR/config.json" "$INSTALL_DIR/config.json" log "INFO" "Created symlink from $INSTALL_DIR/config.json to $CONFIG_DIR/config.json" fi # Set proper ownership for the installation directory chown -R $USER:$USER $INSTALL_DIR # Create media directories with correct permissions create_dir_if_not_exists "$MEDIA_DIR/movies" "$USER:$USER" create_dir_if_not_exists "$MEDIA_DIR/tvshows" "$USER:$USER" create_dir_if_not_exists "$MEDIA_DIR/music" "$USER:$USER" create_dir_if_not_exists "$MEDIA_DIR/software" "$USER:$USER" # Create book/magazine directories if enabled if [ "$ENABLE_BOOK_SORTING" = true ]; then create_dir_if_not_exists "$MEDIA_DIR/books" "$USER:$USER" create_dir_if_not_exists "$MEDIA_DIR/magazines" "$USER:$USER" fi # Install npm packages ensure_npm_packages "$INSTALL_DIR" || { log "ERROR" "Failed to install NPM packages" } # Handle configuration file if ! update_config_file "$CONFIG_DIR/config.json" "$IS_UPDATE"; then log "INFO" "Creating default configuration file..." # Create the users array content for JSON USER_JSON="" if [ "${AUTH_ENABLED}" = "true" ] && [ -n "${ADMIN_USERNAME}" ]; then USER_JSON="{ \"username\": \"${ADMIN_USERNAME}\", \"password\": \"${ADMIN_PASSWORD}\", \"role\": \"admin\" }" fi # Make sure CONFIG_DIR exists mkdir -p "$CONFIG_DIR" # Get version from package.json dynamically VERSION=$(grep -oP '"version": "\K[^"]+' "${SCRIPT_DIR}/package.json" 2>/dev/null || echo "2.0.9") cat > $CONFIG_DIR/config.json << EOF { "version": "$VERSION", "transmissionConfig": { "host": "${TRANSMISSION_HOST}", "port": ${TRANSMISSION_PORT}, "username": "${TRANSMISSION_USER}", "password": "${TRANSMISSION_PASS}", "path": "${TRANSMISSION_RPC_PATH}" }, "remoteConfig": { "isRemote": ${TRANSMISSION_REMOTE}, "directoryMapping": ${TRANSMISSION_DIR_MAPPING} }, "destinationPaths": { "movies": "${MEDIA_DIR}/movies", "tvShows": "${MEDIA_DIR}/tvshows", "music": "${MEDIA_DIR}/music", "books": "${MEDIA_DIR}/books", "magazines": "${MEDIA_DIR}/magazines", "software": "${MEDIA_DIR}/software" }, "seedingRequirements": { "minRatio": 1.0, "minTimeMinutes": 60, "checkIntervalSeconds": 300 }, "processingOptions": { "enableBookSorting": ${ENABLE_BOOK_SORTING}, "extractArchives": true, "deleteArchives": true, "createCategoryFolders": true, "ignoreSample": true, "ignoreExtras": true, "renameFiles": true, "autoReplaceUpgrades": true, "removeDuplicates": true, "keepOnlyBestVersion": true }, "securitySettings": { "authEnabled": ${AUTH_ENABLED:-false}, "httpsEnabled": ${HTTPS_ENABLED:-false}, "sslCertPath": "${SSL_CERT_PATH:-""}", "sslKeyPath": "${SSL_KEY_PATH:-""}", "users": [ ${USER_JSON} ] }, "rssFeeds": [], "rssUpdateIntervalMinutes": 60, "autoProcessing": false, "port": ${PORT}, "logLevel": "info" } EOF # Set ownership for the config file chown $USER:$USER $CONFIG_DIR/config.json # Ensure symlink exists from INSTALL_DIR to CONFIG_DIR ln -sf "$CONFIG_DIR/config.json" "$INSTALL_DIR/config.json" log "INFO" "Created symlink from $INSTALL_DIR/config.json to $CONFIG_DIR/config.json" log "INFO" "Default configuration created successfully" fi # Start the service log "INFO" "Starting the service..." systemctl daemon-reload systemctl enable $SERVICE_NAME systemctl start $SERVICE_NAME # Check if service started successfully sleep 2 if systemctl is-active --quiet $SERVICE_NAME; then log "INFO" "Service started successfully!" else log "ERROR" "Service failed to start. Check logs with: journalctl -u $SERVICE_NAME" fi log "INFO" "Setup finalized!" }