torrent/usr/local/bin/torrent-config
2025-02-28 11:24:31 +01:00

481 lines
15 KiB
Bash
Executable File

#!/bin/bash
#
# Torrent Mover Configuration Utility
# A helper tool to safely update and manage your torrent-mover configuration
set -e
CONFIG_PATH="/etc/torrent/mover.conf"
BACKUP_DIR="/etc/torrent/backups"
DEFAULT_EDITOR="${EDITOR:-nano}"
# Colors for terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
print_header() {
echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Torrent Mover Config Utility ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}"
echo ""
}
usage() {
print_header
echo -e "Usage: ${GREEN}$(basename "$0")${NC} [OPTION]"
echo ""
echo "Options:"
echo -e " ${YELLOW}edit${NC} Edit the configuration file with your default editor"
echo -e " ${YELLOW}backup${NC} Create a backup of the current configuration"
echo -e " ${YELLOW}restore${NC} [file] Restore a previous backup (lists available backups if no file specified)"
echo -e " ${YELLOW}validate${NC} Check the configuration for errors"
echo -e " ${YELLOW}default${NC} Show the default configuration values"
echo -e " ${YELLOW}show${NC} Display the current configuration"
echo -e " ${YELLOW}set${NC} key value Update a specific configuration value"
echo -e " ${YELLOW}get${NC} key Get the value of a specific configuration key"
echo -e " ${YELLOW}help${NC} Display this help message"
echo ""
echo "Examples:"
echo " $(basename "$0") edit # Edit the configuration file"
echo " $(basename "$0") backup # Create a timestamped backup"
echo " $(basename "$0") set COPY_MODE move # Change the copy mode to 'move'"
echo " $(basename "$0") get TRANSMISSION_IP # Show the Transmission server IP"
echo ""
}
# Check if user is root or using sudo
check_permissions() {
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}Error: This command requires root privileges.${NC}"
echo "Please run with sudo:"
echo -e " ${YELLOW}sudo $(basename "$0") $*${NC}"
exit 1
fi
}
# Create a backup of the current configuration
backup_config() {
check_permissions "$@"
if [ ! -f "$CONFIG_PATH" ]; then
echo -e "${RED}Error: Configuration file not found at $CONFIG_PATH${NC}"
exit 1
fi
mkdir -p "$BACKUP_DIR"
local timestamp=$(date +"%Y%m%d_%H%M%S")
local backup_file="$BACKUP_DIR/mover.conf.$timestamp"
cp "$CONFIG_PATH" "$backup_file"
echo -e "${GREEN}Configuration backed up to:${NC} $backup_file"
}
# Restore a configuration from backup
restore_config() {
check_permissions "$@"
if [ ! -d "$BACKUP_DIR" ]; then
echo -e "${RED}Error: Backup directory not found at $BACKUP_DIR${NC}"
exit 1
fi
if [ -z "$1" ]; then
# List available backups
echo -e "${BLUE}Available backups:${NC}"
local count=0
for file in "$BACKUP_DIR"/mover.conf.*; do
if [ -f "$file" ]; then
count=$((count+1))
local date_part=$(basename "$file" | cut -d. -f3)
echo -e "${YELLOW}$count)${NC} $(basename "$file") ($(date -d "${date_part:0:8} ${date_part:9:2}:${date_part:11:2}:${date_part:13:2}" "+%Y-%m-%d %H:%M:%S"))"
fi
done
if [ "$count" -eq 0 ]; then
echo -e "${YELLOW}No backups found.${NC}"
exit 0
fi
echo ""
read -p "Enter the number of the backup to restore: " selection
if ! [[ "$selection" =~ ^[0-9]+$ ]] || [ "$selection" -lt 1 ] || [ "$selection" -gt "$count" ]; then
echo -e "${RED}Error: Invalid selection.${NC}"
exit 1
fi
# Get the filename of the selected backup
local selected_file=$(ls -1 "$BACKUP_DIR"/mover.conf.* | sed -n "${selection}p")
else
# Use the specified backup file
local selected_file="$BACKUP_DIR/$1"
if [ ! -f "$selected_file" ]; then
echo -e "${RED}Error: Backup file not found at $selected_file${NC}"
exit 1
fi
fi
# Create a backup of the current config before restoring
backup_config
# Restore the selected backup
cp "$selected_file" "$CONFIG_PATH"
echo -e "${GREEN}Configuration restored from:${NC} $selected_file"
}
# Edit the configuration file
edit_config() {
check_permissions "$@"
if [ ! -f "$CONFIG_PATH" ]; then
echo -e "${RED}Error: Configuration file not found at $CONFIG_PATH${NC}"
exit 1
fi
# Create a backup before editing
backup_config
# Open in the user's preferred editor
$DEFAULT_EDITOR "$CONFIG_PATH"
# Validate after editing
validate_config
}
# Validate the configuration for errors
validate_config() {
check_permissions "$@"
if [ ! -f "$CONFIG_PATH" ]; then
echo -e "${RED}Error: Configuration file not found at $CONFIG_PATH${NC}"
exit 1
fi
echo -e "${BLUE}Validating configuration file...${NC}"
# Source the config file in a subshell to check for syntax errors
if ! (bash -n "$CONFIG_PATH"); then
echo -e "${RED}Error: The configuration file contains syntax errors.${NC}"
exit 1
fi
# Load the configuration
source "$CONFIG_PATH"
# Check mandatory settings
local required_vars=(
"TRANSMISSION_IP"
"TRANSMISSION_PORT"
"TRANSMISSION_PATH_PREFIX"
"LOCAL_PATH_PREFIX"
"DIR_MOVIES_DST"
"DIR_APPS_DST"
"DIR_GAMES_DST"
"DIR_BOOKS_DST"
"DEFAULT_DST"
"COPY_MODE"
)
local error_count=0
for var in "${required_vars[@]}"; do
if [ -z "${!var}" ]; then
echo -e "${RED}Error: Required setting '$var' is not defined.${NC}"
error_count=$((error_count+1))
fi
done
# Validate COPY_MODE
if [ -n "$COPY_MODE" ] && [ "$COPY_MODE" != "copy" ] && [ "$COPY_MODE" != "move" ]; then
echo -e "${RED}Error: COPY_MODE must be 'copy' or 'move', not '$COPY_MODE'.${NC}"
error_count=$((error_count+1))
fi
# Validate directory paths
local dir_vars=(
"DIR_GAMES_DST"
"DIR_APPS_DST"
"DIR_MOVIES_DST"
"DIR_BOOKS_DST"
"DIR_TV_DST"
"DIR_MUSIC_DST"
"DEFAULT_DST"
)
for var in "${dir_vars[@]}"; do
if [ -n "${!var}" ]; then
if [[ ! "${!var}" == /* ]]; then
echo -e "${RED}Error: Directory path for '$var' must be absolute (start with /).${NC}"
error_count=$((error_count+1))
fi
fi
done
# Check if any pattern in CUSTOM_PATTERNS references undefined variables
if [ -n "$CUSTOM_PATTERNS" ]; then
IFS=';' read -ra PATTERN_ARRAY <<< "$CUSTOM_PATTERNS"
for pattern in "${PATTERN_ARRAY[@]}"; do
IFS='=' read -ra PARTS <<< "$pattern"
if [ "${#PARTS[@]}" -eq 2 ]; then
local dest="${PARTS[1]}"
if [[ "$dest" == *'${'*'}'* ]]; then
local var_name=$(echo "$dest" | sed -n 's/.*\${//;s/}.*//p')
if [ -z "${!var_name}" ]; then
echo -e "${RED}Error: Custom pattern uses undefined variable: \${$var_name}${NC}"
error_count=$((error_count+1))
fi
fi
fi
done
fi
if [ "$error_count" -eq 0 ]; then
echo -e "${GREEN}Configuration validation passed. No errors found.${NC}"
else
echo -e "${RED}Configuration validation failed with $error_count error(s).${NC}"
exit 1
fi
}
# Show the current configuration
show_config() {
if [ ! -f "$CONFIG_PATH" ]; then
echo -e "${RED}Error: Configuration file not found at $CONFIG_PATH${NC}"
exit 1
fi
print_header
echo -e "${BLUE}Current Configuration:${NC}"
echo ""
# Load config and display it categorized
source "$CONFIG_PATH"
echo -e "${YELLOW}=== Connection Settings ===${NC}"
echo -e "TRANSMISSION_IP=${GREEN}${TRANSMISSION_IP:-<not set>}${NC}"
echo -e "TRANSMISSION_PORT=${GREEN}${TRANSMISSION_PORT:-<not set>}${NC}"
if [ -n "$TRANSMISSION_USER" ]; then
echo -e "TRANSMISSION_USER=${GREEN}${TRANSMISSION_USER}${NC}"
echo -e "TRANSMISSION_PASSWORD=${GREEN}********${NC}"
else
echo -e "TRANSMISSION_USER=${YELLOW}<not set>${NC}"
echo -e "TRANSMISSION_PASSWORD=${YELLOW}<not set>${NC}"
fi
echo -e "TRANSMISSION_PATH_PREFIX=${GREEN}${TRANSMISSION_PATH_PREFIX:-<not set>}${NC}"
echo -e "LOCAL_PATH_PREFIX=${GREEN}${LOCAL_PATH_PREFIX:-<not set>}${NC}"
echo ""
echo -e "${YELLOW}=== Destination Directories ===${NC}"
echo -e "DIR_GAMES_DST=${GREEN}${DIR_GAMES_DST:-<not set>}${NC}"
echo -e "DIR_APPS_DST=${GREEN}${DIR_APPS_DST:-<not set>}${NC}"
echo -e "DIR_MOVIES_DST=${GREEN}${DIR_MOVIES_DST:-<not set>}${NC}"
echo -e "DIR_BOOKS_DST=${GREEN}${DIR_BOOKS_DST:-<not set>}${NC}"
echo -e "DIR_TV_DST=${GREEN}${DIR_TV_DST:-<not set>}${NC}"
echo -e "DIR_MUSIC_DST=${GREEN}${DIR_MUSIC_DST:-<not set>}${NC}"
echo -e "DEFAULT_DST=${GREEN}${DEFAULT_DST:-<not set>}${NC}"
echo ""
echo -e "${YELLOW}=== Additional Storage Libraries ===${NC}"
echo -e "STORAGE_DIRS=${GREEN}${STORAGE_DIRS:-<not set>}${NC}"
echo -e "STORAGE_TV_DIRS=${GREEN}${STORAGE_TV_DIRS:-<not set>}${NC}"
echo ""
echo -e "${YELLOW}=== Security Settings ===${NC}"
echo -e "TORRENT_USER=${GREEN}${TORRENT_USER:-debian-transmission}${NC}"
echo -e "TORRENT_GROUP=${GREEN}${TORRENT_GROUP:-debian-transmission}${NC}"
echo ""
echo -e "${YELLOW}=== Performance Settings ===${NC}"
echo -e "PARALLEL_THREADS=${GREEN}${PARALLEL_THREADS:-$(nproc)}${NC}"
echo -e "PARALLEL_PROCESSING=${GREEN}${PARALLEL_PROCESSING:-1}${NC}"
echo -e "COPY_MODE=${GREEN}${COPY_MODE:-<not set>}${NC}"
echo ""
echo -e "${YELLOW}=== Error Recovery ===${NC}"
echo -e "MAX_RETRY_ATTEMPTS=${GREEN}${MAX_RETRY_ATTEMPTS:-3}${NC}"
echo -e "RETRY_WAIT_TIME=${GREEN}${RETRY_WAIT_TIME:-15}${NC}"
echo ""
echo -e "${YELLOW}=== Logging & Integrity ===${NC}"
echo -e "LOG_FILE=${GREEN}${LOG_FILE:-/var/log/torrent_mover.log}${NC}"
echo -e "LOG_LEVEL=${GREEN}${LOG_LEVEL:-INFO}${NC}"
echo -e "USE_SYSLOG=${GREEN}${USE_SYSLOG:-false}${NC}"
echo -e "PROCESSED_LOG=${GREEN}${PROCESSED_LOG:-/var/log/torrent_processed.log}${NC}"
echo -e "CHECKSUM_DB=${GREEN}${CHECKSUM_DB:-/var/lib/torrent/checksums.db}${NC}"
echo -e "CHECK_TRANSFER_INTEGRITY=${GREEN}${CHECK_TRANSFER_INTEGRITY:-true}${NC}"
echo ""
if [ -n "$CUSTOM_PATTERNS" ]; then
echo -e "${YELLOW}=== Custom Content Patterns ===${NC}"
IFS=';' read -ra PATTERN_ARRAY <<< "$CUSTOM_PATTERNS"
for pattern in "${PATTERN_ARRAY[@]}"; do
if [ -n "$pattern" ]; then
IFS='=' read -ra PARTS <<< "$pattern"
if [ "${#PARTS[@]}" -eq 2 ]; then
local regex="${PARTS[0]}"
local dest="${PARTS[1]}"
echo -e "Pattern: ${GREEN}${regex}${NC}${BLUE}${dest}${NC}"
fi
fi
done
echo ""
fi
}
# Update a specific configuration value
set_config_value() {
check_permissions "$@"
if [ -z "$1" ] || [ -z "$2" ]; then
echo -e "${RED}Error: Both key and value must be provided.${NC}"
echo "Usage: $(basename "$0") set KEY VALUE"
exit 1
fi
local key="$1"
local value="$2"
if [ ! -f "$CONFIG_PATH" ]; then
echo -e "${RED}Error: Configuration file not found at $CONFIG_PATH${NC}"
exit 1
fi
# Create a backup before modifying
backup_config
# Check if the key already exists in the config
if grep -q "^$key=" "$CONFIG_PATH"; then
# Update the existing key
sed -i "s|^$key=.*|$key=\"$value\"|" "$CONFIG_PATH"
echo -e "${GREEN}Updated configuration:${NC} $key = \"$value\""
else
# Add the new key
echo "$key=\"$value\"" >> "$CONFIG_PATH"
echo -e "${GREEN}Added new configuration:${NC} $key = \"$value\""
fi
# Validate after updating
validate_config
}
# Get a specific configuration value
get_config_value() {
if [ -z "$1" ]; then
echo -e "${RED}Error: Key must be provided.${NC}"
echo "Usage: $(basename "$0") get KEY"
exit 1
fi
local key="$1"
if [ ! -f "$CONFIG_PATH" ]; then
echo -e "${RED}Error: Configuration file not found at $CONFIG_PATH${NC}"
exit 1
fi
# Source the config file to get the value
source "$CONFIG_PATH"
if [ -n "${!key+x}" ]; then
echo -e "${key}=${GREEN}${!key}${NC}"
else
echo -e "${RED}Error: Configuration key '$key' is not defined.${NC}"
exit 1
fi
}
# Show default configuration options
show_default_config() {
print_header
echo -e "${BLUE}Default Configuration Values:${NC}"
echo ""
cat << EOF
# Transmission Settings
TRANSMISSION_IP="192.168.1.100"
TRANSMISSION_PORT="9091"
TRANSMISSION_USER=""
TRANSMISSION_PASSWORD=""
# Path Mapping
TRANSMISSION_PATH_PREFIX="/downloads"
LOCAL_PATH_PREFIX="/mnt/data"
# Destination Directories
DIR_GAMES_DST="/mnt/media/Games"
DIR_APPS_DST="/mnt/media/Apps"
DIR_MOVIES_DST="/mnt/media/Movies"
DIR_BOOKS_DST="/mnt/media/Books"
DIR_TV_DST="/mnt/media/TV"
DIR_MUSIC_DST="/mnt/media/Music"
DEFAULT_DST="/mnt/media/Other"
# Additional Storage
STORAGE_DIRS=""
STORAGE_TV_DIRS=""
# Security
TORRENT_USER="torrent-mover"
TORRENT_GROUP="torrent-mover"
# Error Recovery
MAX_RETRY_ATTEMPTS="3"
RETRY_WAIT_TIME="15"
# Performance
PARALLEL_THREADS="$(nproc)"
PARALLEL_PROCESSING="1"
COPY_MODE="copy"
# Logging & Integrity
LOG_FILE="/var/log/torrent_mover.log"
LOG_LEVEL="INFO"
USE_SYSLOG="false"
PROCESSED_LOG="/var/log/torrent_processed.log"
CHECKSUM_DB="/var/lib/torrent/checksums.db"
CHECK_TRANSFER_INTEGRITY="true"
# Custom Content Patterns
CUSTOM_PATTERNS=".*documentary.*=\${DIR_MOVIES_DST}/Documentary;.*anime.*=\${DIR_TV_DST}/Anime"
EOF
echo ""
}
# Main command processing
case "$1" in
edit)
edit_config "${@:2}"
;;
backup)
backup_config "${@:2}"
;;
restore)
restore_config "${@:2}"
;;
validate)
validate_config "${@:2}"
;;
show)
show_config
;;
set)
set_config_value "${@:2}"
;;
get)
get_config_value "${@:2}"
;;
default)
show_default_config
;;
help|--help|-h)
usage
;;
*)
usage
exit 1
;;
esac
exit 0