#!/bin/bash ################################################################################ # Pavon Archive Cleanup Script # Purpose: Delete camera footage older than 3 years (before April 2023) # Server: 172.16.1.33 (Pavon Unraid) # Expected Recovery: 25.2TB # Date: April 12, 2026 ################################################################################ # Configuration BASE_PATH="/mnt/user/Storage" LOG_DIR="/root/cleanup_logs" LOG_FILE="${LOG_DIR}/cleanup_$(date +%Y%m%d_%H%M%S).log" DRY_RUN=1 # 1 = dry-run (preview only), 0 = actual deletion # Color codes for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Periods to delete (before April 2023) PERIODS=( "202212:Dec 2022" "202301:Jan 2023" "202302:Feb 2023" "202303:Mar 2023" ) ################################################################################ # Functions ################################################################################ log() { echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE" >&2 } log_warn() { echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" | tee -a "$LOG_FILE" >&2 } log_error() { echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" | tee -a "$LOG_FILE" >&2 } log_info() { echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')] INFO:${NC} $1" | tee -a "$LOG_FILE" >&2 } # Initialize logging init_logging() { mkdir -p "$LOG_DIR" log "===================================================================" log "Pavon Archive Cleanup Script - Started" log "===================================================================" log "Base Path: $BASE_PATH" log "Mode: $([ $DRY_RUN -eq 1 ] && echo 'DRY-RUN (preview only)' || echo 'LIVE DELETION')" log "Log File: $LOG_FILE" log "-------------------------------------------------------------------" } # Calculate total size for a period calculate_period_size() { local pattern=$1 local description=$2 log_info "Scanning: $description (pattern: Event${pattern}*.avi)" local file_count=0 local total_size=0 # Count files and calculate size while IFS= read -r file; do ((file_count++)) done < <(find "$BASE_PATH"/cam* -type f -name "Event${pattern}*.avi" 2>/dev/null) if [ $file_count -gt 0 ]; then total_size=$(find "$BASE_PATH"/cam* -type f -name "Event${pattern}*.avi" -exec du -ch {} + 2>/dev/null | tail -1 | cut -f1) else total_size="0" fi log_info " Files: $file_count" log_info " Size: $total_size" echo "$file_count:$total_size" } # Preview what will be deleted preview_deletion() { log "===================================================================" log "DELETION PREVIEW" log "===================================================================" local grand_total_files=0 local grand_total_size_kb=0 for period in "${PERIODS[@]}"; do IFS=':' read -r pattern description <<< "$period" log "" log "--- $description ---" result=$(calculate_period_size "$pattern" "$description") IFS=':' read -r file_count total_size <<< "$result" grand_total_files=$((grand_total_files + file_count)) # Show sample files log_info "Sample files to be deleted:" find "$BASE_PATH"/cam* -type f -name "Event${pattern}*.avi" 2>/dev/null | head -5 | while read -r file; do size=$(du -h "$file" 2>/dev/null | cut -f1) log_info " $size - $(basename "$file")" done done log "" log "===================================================================" log "SUMMARY" log "===================================================================" log "Total files to delete: $grand_total_files" log "Expected space recovery: 25.2TB (calculated from audit)" log "===================================================================" } # Delete files for a specific period delete_period() { local pattern=$1 local description=$2 log "" log "===================================================================" log "Processing: $description" log "===================================================================" local deleted_count=0 local failed_count=0 local deleted_size=0 # Find and delete files while IFS= read -r file; do if [ $DRY_RUN -eq 1 ]; then log_info "[DRY-RUN] Would delete: $file" ((deleted_count++)) else size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null) if rm -f "$file" 2>/dev/null; then log_info "Deleted: $file" ((deleted_count++)) deleted_size=$((deleted_size + size)) # Progress indicator every 1000 files if [ $((deleted_count % 1000)) -eq 0 ]; then log "Progress: $deleted_count files deleted..." fi else log_error "Failed to delete: $file" ((failed_count++)) fi fi done < <(find "$BASE_PATH"/cam* -type f -name "Event${pattern}*.avi" 2>/dev/null) log "-------------------------------------------------------------------" log "$description Complete:" log " Deleted: $deleted_count files" if [ $DRY_RUN -eq 0 ]; then log " Failed: $failed_count files" log " Space freed: $(numfmt --to=iec-i --suffix=B $deleted_size 2>/dev/null || echo 'N/A')" fi log "-------------------------------------------------------------------" echo "$deleted_count:$failed_count:$deleted_size" } # Clean up empty directories cleanup_empty_dirs() { if [ $DRY_RUN -eq 1 ]; then log_info "[DRY-RUN] Would clean up empty directories" return fi log "" log "===================================================================" log "Cleaning up empty directories" log "===================================================================" local removed_dirs=0 for cam_dir in "$BASE_PATH"/cam*; do if [ -d "$cam_dir" ]; then # Remove empty date directories find "$cam_dir" -type d -empty -delete 2>/dev/null ((removed_dirs++)) fi done log "Empty directories cleaned: $removed_dirs camera folders checked" } # Main execution main() { init_logging # Verify base path exists if [ ! -d "$BASE_PATH" ]; then log_error "Base path does not exist: $BASE_PATH" exit 1 fi # Show preview preview_deletion # If dry-run, stop here if [ $DRY_RUN -eq 1 ]; then log "" log "===================================================================" log "DRY-RUN COMPLETE - No files were deleted" log "===================================================================" log "To execute actual deletion, edit this script and set: DRY_RUN=0" log "Or run with: DRY_RUN=0 $0" log "===================================================================" exit 0 fi # Confirm before deletion log "" log_warn "===================================================================" log_warn "FINAL CONFIRMATION REQUIRED" log_warn "===================================================================" log_warn "This will PERMANENTLY delete approximately 25.2TB of data" log_warn "Files from: Dec 2022 - Mar 2023" log_warn "" read -p "Type 'DELETE' to confirm: " confirmation if [ "$confirmation" != "DELETE" ]; then log_error "Deletion cancelled by user" exit 1 fi # Execute deletion log "" log "===================================================================" log "STARTING DELETION PROCESS" log "===================================================================" local grand_total_deleted=0 local grand_total_failed=0 local grand_total_size=0 for period in "${PERIODS[@]}"; do IFS=':' read -r pattern description <<< "$period" result=$(delete_period "$pattern" "$description") IFS=':' read -r deleted failed size <<< "$result" grand_total_deleted=$((grand_total_deleted + deleted)) grand_total_failed=$((grand_total_failed + failed)) grand_total_size=$((grand_total_size + size)) done # Clean up empty directories cleanup_empty_dirs # Final summary log "" log "===================================================================" log "DELETION COMPLETE" log "===================================================================" log "Total files deleted: $grand_total_deleted" log "Total files failed: $grand_total_failed" log "Total space freed: $(numfmt --to=iec-i --suffix=B $grand_total_size 2>/dev/null || echo 'N/A')" log "Log file: $LOG_FILE" log "===================================================================" # Show new disk usage log "" log "Updated disk usage:" df -h "$BASE_PATH" | tee -a "$LOG_FILE" } ################################################################################ # Script execution ################################################################################ # Allow override via environment variable if [ -n "$DRY_RUN" ]; then DRY_RUN=$DRY_RUN fi main "$@"