#!/bin/bash # Plex Database Directory Cleanup Script # Author: Peter Wood # Created: June 21, 2025 # # This script safely removes temporary, recovery, and corrupted files # from the Plex databases directory while preserving active databases # and legitimate Plex built-in backups. # Don't exit on errors, we want to continue processing all files set +e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration PLEX_DB_DIR="/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Plug-in Support/Databases" DRY_RUN=false VERBOSE=false # Usage function show_usage() { cat << EOF Usage: $0 [OPTIONS] Clean up temporary, recovery, and corrupted files from Plex databases directory. OPTIONS: --dry-run Show what would be removed without actually removing --verbose Show detailed output --help Show this help message DESCRIPTION: This script removes: - Temporary files (*-tmp, *-2025-*-tmp) - MD5 checksum files (*.md5) - Recovery files (*recovery*) - Repaired files (*repaired*) - Empty backup files (*empty-backup*) - DBRepair.log files - Corrupted database directories (corrupted-*) This script preserves: - Active database files (*.db, *.db-shm, *.db-wal) - Plex built-in backups (*.backup.*) - Legitimate dated backups (*.db.YYYYMMDD) - EPG databases (tv.plex.providers.epg.cloud-*.db) EXAMPLES: $0 --dry-run # Preview what would be removed $0 --verbose # Remove files with detailed output sudo $0 # Remove files (requires root for some files) EOF } # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in --dry-run) DRY_RUN=true shift ;; --verbose) VERBOSE=true shift ;; --help) show_usage exit 0 ;; *) echo -e "${RED}Error: Unknown option '$1'${NC}" show_usage exit 1 ;; esac done # Function to log messages log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${BLUE}[VERBOSE]${NC} $1" fi } # Function to safely remove files/directories safe_remove() { local item="$1" local item_type="$2" # "file" or "directory" if [[ ! -e "$item" ]]; then log_verbose "Skipping $item (does not exist)" return 0 fi if [[ "$DRY_RUN" == "true" ]]; then echo -e "${YELLOW}[DRY-RUN]${NC} Would remove $item_type: $(basename "$item")" if [[ "$item_type" == "directory" ]]; then echo -e "${YELLOW} ${NC} Contents: $(ls -la "$item" 2>/dev/null | wc -l) items" else echo -e "${YELLOW} ${NC} Size: $(ls -lah "$item" 2>/dev/null | awk '{print $5}')" fi else log_verbose "Removing $item_type: $(basename "$item")" if [[ "$item_type" == "directory" ]]; then if rm -rf "$item" 2>/dev/null; then log_success "Removed directory: $(basename "$item")" else log_error "Failed to remove directory: $(basename "$item")" return 1 fi else if rm -f "$item" 2>/dev/null; then log_success "Removed file: $(basename "$item")" else log_error "Failed to remove file: $(basename "$item")" return 1 fi fi fi } # Main cleanup function cleanup_databases() { log_info "Starting Plex database directory cleanup..." if [[ ! -d "$PLEX_DB_DIR" ]]; then log_error "Plex databases directory not found: $PLEX_DB_DIR" exit 1 fi cd "$PLEX_DB_DIR" || { log_error "Cannot access Plex databases directory: $PLEX_DB_DIR" exit 1 } local files_removed=0 local dirs_removed=0 local total_size_removed=0 log_info "Scanning directory: $PLEX_DB_DIR" # Remove temporary files log_info "Cleaning up temporary files..." for file in *-tmp *-2025-*-tmp; do if [[ -f "$file" && "$file" != "*-tmp" && "$file" != "*-2025-*-tmp" ]]; then safe_remove "$file" "file" ((files_removed++)) fi done # Remove MD5 checksum files log_info "Cleaning up MD5 checksum files..." for file in *.md5; do if [[ -f "$file" && "$file" != "*.md5" ]]; then safe_remove "$file" "file" ((files_removed++)) fi done # Remove recovery files log_info "Cleaning up recovery files..." for file in *recovery*; do if [[ -f "$file" && "$file" != "*recovery*" ]]; then safe_remove "$file" "file" ((files_removed++)) fi done # Remove repaired files log_info "Cleaning up repaired files..." for file in *repaired*; do if [[ -f "$file" && "$file" != "*repaired*" ]]; then safe_remove "$file" "file" ((files_removed++)) fi done # Remove empty backup files log_info "Cleaning up empty backup files..." for file in *empty-backup*; do if [[ -f "$file" && "$file" != "*empty-backup*" ]]; then safe_remove "$file" "file" ((files_removed++)) fi done # Remove DBRepair.log log_info "Cleaning up repair log files..." if [[ -f "DBRepair.log" ]]; then safe_remove "DBRepair.log" "file" ((files_removed++)) fi # Remove corrupted directories log_info "Cleaning up corrupted database directories..." for dir in corrupted-*; do if [[ -d "$dir" && "$dir" != "corrupted-*" ]]; then safe_remove "$dir" "directory" ((dirs_removed++)) fi done # Summary echo log_info "=== Cleanup Summary ===" if [[ "$DRY_RUN" == "true" ]]; then echo -e "${YELLOW}[DRY-RUN]${NC} Files that would be removed: $files_removed" echo -e "${YELLOW}[DRY-RUN]${NC} Directories that would be removed: $dirs_removed" else log_success "Files removed: $files_removed" log_success "Directories removed: $dirs_removed" fi # Show what remains echo log_info "=== Remaining Files ===" echo -e "${GREEN}Active database files:${NC}" ls -lah *.db *.db-shm *.db-wal 2>/dev/null | grep -E "\.(db|db-shm|db-wal)$" || echo " None found" echo echo -e "${GREEN}Backup files:${NC}" ls -lah *.backup.* 2>/dev/null || echo " None found" echo echo -e "${GREEN}Historical backups:${NC}" ls -lah *.db.2[0-9][0-9][0-9][0-9][0-9][0-9][0-9] 2>/dev/null || echo " None found" echo echo -e "${GREEN}Other database files:${NC}" ls -lah tv.plex.providers.*.db 2>/dev/null || echo " None found" } # Pre-flight checks preflight_checks() { log_info "Performing pre-flight checks..." # Check if Plex is running if pgrep -f "Plex Media Server" > /dev/null; then log_warning "Plex Media Server is currently running!" log_warning "For safety, consider stopping Plex before cleanup:" log_warning " sudo systemctl stop plexmediaserver" echo read -p "Continue anyway? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_info "Cleanup cancelled by user" exit 0 fi fi # Check permissions if [[ ! -w "$PLEX_DB_DIR" ]]; then log_warning "You may not have write permissions to the databases directory" log_warning "Consider running with sudo if you encounter permission errors" fi # Check disk space local available_space=$(df -h "$PLEX_DB_DIR" | awk 'NR==2 {print $4}') log_info "Available disk space: $available_space" } # Main execution main() { echo -e "${BLUE}+================================================================+${NC}" echo -e "${BLUE}| PLEX DATABASE CLEANUP TOOL |${NC}" echo -e "${BLUE}+================================================================+${NC}" echo if [[ "$DRY_RUN" == "true" ]]; then log_warning "DRY-RUN MODE: No files will actually be removed" echo fi preflight_checks cleanup_databases echo if [[ "$DRY_RUN" == "true" ]]; then log_info "Dry-run completed. Run without --dry-run to actually remove files." else log_success "Database cleanup completed successfully!" log_info "You can now restart Plex Media Server if it was stopped." fi } # Execute main function main "$@"