diff --git a/backup-plex.sh b/backup-plex.sh index 63e224e..04c1605 100755 --- a/backup-plex.sh +++ b/backup-plex.sh @@ -23,9 +23,10 @@ MAX_BACKUPS_TO_KEEP=10 BACKUP_ROOT="/mnt/share/media/backups/plex" LOG_ROOT="/mnt/share/media/backups/logs" SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" -JSON_LOG_FILE="${SCRIPT_DIR}/logs/plex-backup.json" PERFORMANCE_LOG_FILE="${SCRIPT_DIR}/logs/plex-backup-performance.json" +# Backup strategy configuration - Always perform full backups + # Plex SQLite path (custom Plex SQLite binary) PLEX_SQLITE="/usr/lib/plexmediaserver/Plex SQLite" @@ -81,6 +82,7 @@ while [[ $# -gt 0 ]]; do echo " --webhook=URL Send notifications to webhook URL" echo " --email=ADDRESS Send notifications to email address" echo " -h, --help Show this help message" + echo "" exit 0 ;; *) @@ -170,48 +172,15 @@ track_performance() { log_info "Performance: $operation completed in ${duration}s" } -# Initialize JSON log file -initialize_json_log() { - if [ ! -f "${JSON_LOG_FILE}" ] || ! jq empty "${JSON_LOG_FILE}" 2>/dev/null; then - echo "{}" > "${JSON_LOG_FILE}" - log_message "Initialized JSON log file" +# Initialize log directory +initialize_logs() { + mkdir -p "$(dirname "$PERFORMANCE_LOG_FILE")" + if [ ! -f "$PERFORMANCE_LOG_FILE" ]; then + echo "[]" > "$PERFORMANCE_LOG_FILE" + log_message "Initialized performance log file" fi } -# Check if file needs backup based on modification time -needs_backup() { - local file="$1" - - if [ ! -f "$file" ]; then - log_warning "File not found: $file" - return 1 - fi - - local current_mod_date=$(stat -c %Y "$file") - local last_backup_date=$(jq -r --arg file "$file" '.[$file] // 0' "${JSON_LOG_FILE}") - - if [ "$last_backup_date" == "null" ] || [ "$last_backup_date" == "0" ]; then - log_message "File has never been backed up: $(basename "$file")" - return 0 - fi - - if [ "$current_mod_date" -gt "$last_backup_date" ]; then - log_message "File modified since last backup: $(basename "$file")" - return 0 - fi - - log_message "File unchanged since last backup: $(basename "$file")" - return 1 -} - -# Update backup time in JSON log -update_backup_time() { - local file="$1" - local timestamp="$2" - - jq --arg file "$file" --arg timestamp "$timestamp" '.[$file] = ($timestamp | tonumber)' "${JSON_LOG_FILE}" > "${JSON_LOG_FILE}.tmp" && mv "${JSON_LOG_FILE}.tmp" "${JSON_LOG_FILE}" -} - # Enhanced notification system send_notification() { local title="$1" @@ -754,7 +723,7 @@ estimate_backup_size() { for nickname in "${!PLEX_FILES[@]}"; do local file="${PLEX_FILES[$nickname]}" - if [ -f "$file" ] && needs_backup "$file" >/dev/null 2>&1; then + if [ -f "$file" ]; then local size_kb=$(du -k "$file" 2>/dev/null | cut -f1) total_size=$((total_size + size_kb)) fi @@ -907,8 +876,8 @@ main() { mkdir -p "${BACKUP_ROOT}" mkdir -p "${LOG_ROOT}" - # Initialize JSON log - initialize_json_log + # Initialize logs + initialize_logs # Check if only doing integrity check if [ "$INTEGRITY_CHECK_ONLY" = true ]; then @@ -983,43 +952,34 @@ main() { # Handle WAL files backup handle_wal_files "backup" "$BACKUP_PATH" - # Backup files + # Backup files - always perform full backup local backup_start=$(date +%s) for nickname in "${!PLEX_FILES[@]}"; do local file="${PLEX_FILES[$nickname]}" if [ -f "$file" ]; then - if needs_backup "$file" ]; then - log_message "Backing up: $(basename "$file")" + log_message "Backing up: $(basename "$file")" + + # Create backup filename without timestamp (use original filename) + local backup_file="${BACKUP_PATH}/$(basename "$file")" + + # Copy file + if sudo cp "$file" "$backup_file"; then + log_success "Copied: $(basename "$file")" - # Create backup filename without timestamp (use original filename) - local backup_file="${BACKUP_PATH}/$(basename "$file")" - - # Copy file - if sudo cp "$file" "$backup_file"; then - log_success "Copied: $(basename "$file")" - - # Verify backup - if verify_backup "$file" "$backup_file"; then - log_success "Verified: $(basename "$file")" - - # Update backup time in JSON log - local current_timestamp=$(date +%s) - update_backup_time "$file" "$current_timestamp" - - files_backed_up=$((files_backed_up + 1)) - else - log_error "Verification failed: $(basename "$file")" - backup_errors=$((backup_errors + 1)) - # Remove failed backup - rm -f "$backup_file" - fi + # Verify backup + if verify_backup "$file" "$backup_file"; then + log_success "Verified: $(basename "$file")" + files_backed_up=$((files_backed_up + 1)) else - log_error "Failed to copy: $(basename "$file")" + log_error "Verification failed: $(basename "$file")" backup_errors=$((backup_errors + 1)) + # Remove failed backup + rm -f "$backup_file" fi else - log_message "Skipping unchanged file: $(basename "$file")" + log_error "Failed to copy: $(basename "$file")" + backup_errors=$((backup_errors + 1)) fi else log_warning "File not found: $file" diff --git a/docs/plex-backup.md b/docs/plex-backup.md index b650f9f..715502d 100644 --- a/docs/plex-backup.md +++ b/docs/plex-backup.md @@ -1,24 +1,34 @@ # Enhanced Plex Backup Script Documentation -This document provides comprehensive documentation for the enhanced `backup-plex.sh` script. This advanced backup solution includes performance monitoring, parallel processing, intelligent notifications, WAL file handling, and automated testing capabilities. +This document provides comprehensive documentation for the enhanced `backup-plex.sh` script. This advanced backup solution includes performance monitoring, parallel processing, intelligent notifications, and WAL file handling. ## Script Overview The enhanced script performs the following advanced tasks: 1. **Performance Monitoring**: Tracks backup operations with JSON-based performance logging -2. **Intelligent Backup Detection**: Only backs up files that have changed since last backup +2. **Full Backup Operations**: Performs complete backups of all Plex files every time 3. **WAL File Handling**: Properly handles SQLite Write-Ahead Logging files 4. **Database Integrity Verification**: Comprehensive integrity checks with automated repair options 5. **Parallel Processing**: Concurrent verification for improved performance 6. **Multi-Channel Notifications**: Console, webhook, and email notification support -7. **Checksum Caching**: Intelligent caching to avoid recalculating unchanged file checksums -8. **Enhanced Service Management**: Safe Plex service management with progress indicators -9. **Comprehensive Logging**: Detailed logs with color-coded output and timestamps -10. **Automated Cleanup**: Configurable retention policies for old backups +7. **Enhanced Service Management**: Safe Plex service management with progress indicators +8. **Comprehensive Logging**: Detailed logs with color-coded output and timestamps +9. **Safe Automated Cleanup**: Retention policies based on age and backup count ## Enhanced Features +### Full Backup Operation + +The script performs complete backups every time it runs: + +- **What it does**: Backs up all Plex files regardless of modification status +- **Benefits**: + - Guarantees every backup is a complete restoration point + - Eliminates risk of file loss from incomplete backup coverage + - Simplifies backup management and restoration +- **Usage**: `./backup-plex.sh` (no options needed) + ### Performance Tracking - **JSON Performance Logs**: All operations are timed and logged to `logs/plex-backup-performance.json` @@ -208,17 +218,6 @@ The performance log (`logs/plex-backup-performance.json`) contains entries like: ] ``` -### Backup Tracking Log - -The backup tracking log (`logs/plex-backup.json`) tracks last backup times: - -```json -{ - "/var/lib/plexmediaserver/.../com.plexapp.plugins.library.db": 1732567523, - "/var/lib/plexmediaserver/.../Preferences.xml": 1732567523 -} -``` - ## Usage Examples ### Basic Backup @@ -406,15 +405,14 @@ The enhanced script implements a robust backup strategy with a streamlined tar.g The new backup system eliminates intermediate dated directories and stores only compressed archives: -```bash +```text /mnt/share/media/backups/plex/ ├── plex-backup-20250125_143022.tar.gz # Latest backup ├── plex-backup-20250124_143011.tar.gz # Previous backup ├── plex-backup-20250123_143008.tar.gz # Older backup └── logs/ ├── backup_log_20250125_143022.md - ├── plex-backup-performance.json - └── plex-backup.json + └── plex-backup-performance.json ``` ### Archive Naming Convention @@ -434,15 +432,14 @@ Backup files follow the naming convention `plex-backup-YYYYMMDD_HHMMSS.tar.gz` f ## Final Directory Structure -``` +```text /mnt/share/media/backups/plex/ ├── plex-backup-20250125_143022.tar.gz # Latest backup ├── plex-backup-20250124_143011.tar.gz # Previous backup ├── plex-backup-20250123_143008.tar.gz # Older backup └── logs/ ├── backup_log_20250125_143022.md - ├── plex-backup-performance.json - └── plex-backup.json + └── plex-backup-performance.json ``` Backup files follow the pattern: `plex-backup-YYYYMMDD_HHMMSS.tar.gz`