From cf4b54cf0ad6ff65f65ca25bc460b103606cb2c4 Mon Sep 17 00:00:00 2001 From: Peter Wood Date: Sat, 21 Jun 2025 07:52:16 -0400 Subject: [PATCH] feat: Add cleanup script for temporary and corrupted Plex database files --- plex/README.md | 30 ++++ plex/cleanup-plex-databases.sh | 310 +++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100755 plex/cleanup-plex-databases.sh diff --git a/plex/README.md b/plex/README.md index 1b9c575..666114c 100644 --- a/plex/README.md +++ b/plex/README.md @@ -307,6 +307,36 @@ $ ./check-plex-builtin-backups.sh ./plex-recent-additions.sh # Generate recent additions report ``` +#### `cleanup-plex-databases.sh` ⭐ **NEW** +**Safe cleanup of temporary and corrupted database files** + +**Features:** +- Removes temporary files, recovery files, and corrupted directories +- Preserves active databases and legitimate backups +- Dry-run mode for safe preview +- Comprehensive safety checks and validation + +**Usage:** +```bash +./cleanup-plex-databases.sh --dry-run # Preview what will be removed +sudo ./cleanup-plex-databases.sh # Perform actual cleanup +./cleanup-plex-databases.sh --help # Show all options +``` + +**What it removes:** +- Temporary files (`*-tmp`, `*-2025-*-tmp`) +- MD5 checksum files (`*.md5`) +- Recovery files (`*recovery*`) +- Repaired files (`*repaired*`) +- Empty backup files (`*empty-backup*`) +- Repair log files (`DBRepair.log`) +- Corrupted database directories (`corrupted-*`) + +**What it preserves:** +- Active database files (`*.db`, `*.db-shm`, `*.db-wal`) +- Plex built-in backups (`*.backup.*`) +- Historical dated backups (`*.db.YYYYMMDD`) +- EPG databases (`tv.plex.providers.epg.cloud-*.db`) ### 🧪 Testing & Integration #### `test-plex-backup.sh` diff --git a/plex/cleanup-plex-databases.sh b/plex/cleanup-plex-databases.sh new file mode 100755 index 0000000..a35c867 --- /dev/null +++ b/plex/cleanup-plex-databases.sh @@ -0,0 +1,310 @@ +#!/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 "$@"