292 lines
9.2 KiB
Bash
Executable File
292 lines
9.2 KiB
Bash
Executable File
#!/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 "$@"
|