#!/bin/bash # Common utility functions and variables for torrent-mover # Global Runtime Variables DRY_RUN=0 INTERACTIVE=0 CACHE_WARMUP=0 DEBUG=0 # To avoid reprocessing the same source directory (across different torrents) declare -A processed_source_dirs declare -A CHECKED_MOUNTS=() declare -A PATH_CACHE # Logging Functions # All log messages go to stderr. log_debug() { if [[ "${DEBUG}" -eq 1 ]]; then echo -e "[DEBUG] $(date '+%F %T') - $*" | tee -a "${LOG_FILE}" >&2 [[ "${USE_SYSLOG}" == "true" ]] && logger -t torrent-mover "[DEBUG] $*" fi } log_info() { echo -e "[INFO] $(date '+%F %T') - $*" | tee -a "${LOG_FILE}" >&2 [[ "${USE_SYSLOG}" == "true" ]] && logger -t torrent-mover "[INFO] $*" } log_warn() { echo -e "[WARN] $(date '+%F %T') - $*" | tee -a "${LOG_FILE}" >&2 [[ "${USE_SYSLOG}" == "true" ]] && logger -t torrent-mover "[WARN] $*" } log_error() { echo -e "[ERROR] $(date '+%F %T') - $*" | tee -a "${LOG_FILE}" >&2 [[ "${USE_SYSLOG}" == "true" ]] && logger -t torrent-mover "[ERROR] $*" } # Error Handling & Notifications error_handler() { local lineno="$1" local msg="$2" log_error "Error on line ${lineno}: ${msg}" # Optionally send a notification (e.g., email) return 1 } # translate_source: Converts the Transmission‑reported path into the local path. translate_source() { local src="$1" echo "${src/#${TRANSMISSION_PATH_PREFIX}/${LOCAL_PATH_PREFIX}}" } # parse_args: Processes command‑line options. parse_args() { while [[ $# -gt 0 ]]; do case "$1" in --dry-run) DRY_RUN=1; shift ;; --interactive) INTERACTIVE=1; shift ;; --cache-warmup) CACHE_WARMUP=1; shift ;; --debug) DEBUG=1; shift ;; --help) echo "Usage: $0 [--dry-run] [--interactive] [--cache-warmup] [--debug]" >&2 exit 0 ;; *) echo "Invalid option: $1" >&2; exit 1 ;; esac done } # check_dependencies: Ensures required commands are available. check_dependencies() { local deps=("transmission-remote" "unrar" "unzip" "7z" "parallel" "bc") for dep in "${deps[@]}"; do command -v "${dep}" >/dev/null 2>&1 || { log_error "Missing dependency: ${dep}"; exit 1; } done } # check_disk_usage: Warn if disk usage is over 90%. check_disk_usage() { local dir="$1" [[ -z "${dir}" ]] && return if ! df -P "${dir}" &>/dev/null; then log_warn "Directory not found: ${dir}" return fi local mount_point mount_point=$(df -P "${dir}" | awk 'NR==2 {print $6}') [[ -z "${mount_point}" ]] && return if [[ -z "${CHECKED_MOUNTS["${mount_point}"]+x}" ]]; then local usage usage=$(df -P "${dir}" | awk 'NR==2 {sub(/%/, "", $5); print $5}') if (( usage >= 90 )); then log_warn "Storage warning: ${mount_point} at ${usage}% capacity" fi CHECKED_MOUNTS["${mount_point}"]=1 fi } # retry_command: Execute a command with retries retry_command() { local cmd="$1" local max_attempts="${2:-3}" # Default to 3 attempts local wait_time="${3:-10}" # Default to 10 seconds wait between attempts local attempt=1 while (( attempt <= max_attempts )); do log_debug "Attempt $attempt of $max_attempts: $cmd" if eval "$cmd"; then return 0 else log_warn "Command failed (attempt $attempt): $cmd" if (( attempt == max_attempts )); then log_error "Maximum attempts reached for: $cmd" return 1 fi sleep "$wait_time" (( attempt++ )) fi done return 1 } # validate_directories: Ensure required directories exist and are writable validate_directories() { local directories=("$@") for dir in "${directories[@]}"; do if [[ ! -d "${dir}" ]]; then log_error "Directory missing: ${dir}" return 1 fi if [[ ! -w "${dir}" ]]; then log_error "Write permission denied: ${dir}" return 1 fi done return 0 }