This commit addresses multiple code consistency and reliability issues across the codebase: 1. Version consistency - use package.json version (2.0.9) throughout 2. Improved module loading with better error handling and consistent symlinks 3. Enhanced data directory handling with better error checking 4. Fixed redundant code in main-installer.sh 5. Improved error handling in transmission-client.js 6. Added extensive module symlink creation 7. Better file path handling and permission checks 8. Enhanced API response handling 💡 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
308 lines
9.3 KiB
Bash
308 lines
9.3 KiB
Bash
#!/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" || {
|
|
log "ERROR" "Failed to create installation directory: $install_dir"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
# Ensure data directory exists
|
|
if [ ! -d "$install_dir/data" ]; then
|
|
log "INFO" "Creating data directory: $install_dir/data"
|
|
mkdir -p "$install_dir/data" || {
|
|
log "ERROR" "Failed to create data directory: $install_dir/data"
|
|
return 1
|
|
}
|
|
|
|
# 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" || {
|
|
log "ERROR" "Failed to copy package.json to installation directory"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
# 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" || {
|
|
log "ERROR" "Failed to change to installation directory: $install_dir"
|
|
return 1
|
|
}
|
|
|
|
npm install || {
|
|
log "ERROR" "NPM installation failed in $install_dir"
|
|
cd "$current_dir" # Return to original directory
|
|
return 1
|
|
}
|
|
|
|
# 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!"
|
|
}
|