mirror of
https://github.com/acedanger/shell.git
synced 2025-12-06 00:00:13 -08:00
- Changed inline variable assignments to separate declaration and assignment for clarity. - Updated condition checks and log messages for better readability and consistency. - Added a backup of validate-plex-recovery.sh for safety. - Introduced a new script run-docker-tests.sh for testing setup in Docker containers. - Enhanced ssh-login.sh to improve condition checks and logging functionality.
366 lines
12 KiB
Bash
Executable File
366 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
################################################################################
|
|
# Nuclear Plex Database Recovery Script
|
|
################################################################################
|
|
#
|
|
# Author: Peter Wood <peter@peterwood.dev>
|
|
# Description: Last-resort database recovery script that completely replaces
|
|
# corrupted Plex databases with known good backups. This script
|
|
# is used when all other repair methods have failed and a complete
|
|
# database replacement is the only remaining option.
|
|
#
|
|
# ⚠️ WARNING: This script will completely replace existing databases!
|
|
# All data since the backup was created will be lost.
|
|
# Use only when standard repair methods have failed.
|
|
#
|
|
# Features:
|
|
# - Complete database replacement from backups
|
|
# - Automatic backup of current (corrupted) databases
|
|
# - Service management and safety checks
|
|
# - Comprehensive logging of all operations
|
|
# - Rollback capability if replacement fails
|
|
# - Verification of restored database integrity
|
|
#
|
|
# Related Scripts:
|
|
# - backup-plex.sh: Creates backups used by this recovery script
|
|
# - icu-aware-recovery.sh: ICU-specific recovery methods
|
|
# - restore-plex.sh: Standard restoration procedures
|
|
# - validate-plex-recovery.sh: Validates recovery results
|
|
# - plex.sh: General Plex service management
|
|
#
|
|
# Usage:
|
|
# ./nuclear-plex-recovery.sh # Interactive recovery
|
|
# ./nuclear-plex-recovery.sh --auto # Automated recovery
|
|
# ./nuclear-plex-recovery.sh --dry-run # Show what would be done
|
|
# ./nuclear-plex-recovery.sh --verify-only # Verify backup integrity
|
|
#
|
|
# Dependencies:
|
|
# - Valid Plex backup files
|
|
# - sqlite3 or Plex SQLite binary
|
|
# - systemctl (for service management)
|
|
# - tar (for backup extraction)
|
|
#
|
|
# Exit Codes:
|
|
# 0 - Recovery successful
|
|
# 1 - General error
|
|
# 2 - Backup file issues
|
|
# 3 - Database replacement failure
|
|
# 4 - Service management failure
|
|
# 5 - Rollback performed due to failure
|
|
#
|
|
################################################################################
|
|
|
|
# Nuclear Plex Database Recovery Script
|
|
# This script completely replaces corrupted databases with known good backups
|
|
# Use this when standard repair methods have failed
|
|
|
|
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"
|
|
PLEX_USER="plex"
|
|
PLEX_GROUP="plex"
|
|
BACKUP_TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
|
RECOVERY_LOG="/home/acedanger/shell/plex/logs/nuclear-recovery-${BACKUP_TIMESTAMP}.log"
|
|
|
|
# Ensure log directory exists
|
|
mkdir -p "$(dirname "$RECOVERY_LOG")"
|
|
|
|
# Function to log messages
|
|
log_message() {
|
|
local level="$1"
|
|
local message="$2"
|
|
local timestamp
|
|
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
echo "[$timestamp] [$level] $message" | tee -a "$RECOVERY_LOG"
|
|
}
|
|
|
|
# Function to print colored output
|
|
print_status() {
|
|
local color="$1"
|
|
local message="$2"
|
|
echo -e "${color}${message}${NC}"
|
|
log_message "INFO" "$message"
|
|
}
|
|
|
|
# Function to check if running as root
|
|
check_root() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
print_status "$RED" "This script must be run as root or with sudo"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Function to stop Plex service
|
|
stop_plex() {
|
|
print_status "$YELLOW" "Stopping Plex Media Server..."
|
|
|
|
if systemctl is-active --quiet plexmediaserver; then
|
|
systemctl stop plexmediaserver
|
|
sleep 5
|
|
|
|
# Verify it's stopped
|
|
if systemctl is-active --quiet plexmediaserver; then
|
|
print_status "$RED" "Failed to stop Plex service"
|
|
exit 1
|
|
fi
|
|
print_status "$GREEN" "Plex service stopped successfully"
|
|
else
|
|
print_status "$YELLOW" "Plex service was already stopped"
|
|
fi
|
|
}
|
|
|
|
# Function to start Plex service
|
|
start_plex() {
|
|
print_status "$YELLOW" "Starting Plex Media Server..."
|
|
|
|
systemctl start plexmediaserver
|
|
sleep 10
|
|
|
|
# Verify it's running
|
|
if systemctl is-active --quiet plexmediaserver; then
|
|
print_status "$GREEN" "Plex service started successfully"
|
|
|
|
# Check if it's actually responding
|
|
local max_attempts=30
|
|
local attempt=1
|
|
|
|
while [[ $attempt -le $max_attempts ]]; do
|
|
if curl -s -f "http://localhost:32400/web/index.html" > /dev/null 2>&1; then
|
|
print_status "$GREEN" "Plex web interface is responding"
|
|
return 0
|
|
fi
|
|
|
|
print_status "$YELLOW" "Waiting for Plex to fully start... (attempt $attempt/$max_attempts)"
|
|
sleep 5
|
|
((attempt++))
|
|
done
|
|
|
|
print_status "$YELLOW" "Plex service is running but web interface may still be starting"
|
|
else
|
|
print_status "$RED" "Failed to start Plex service"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to backup current corrupted databases
|
|
backup_corrupted_databases() {
|
|
print_status "$YELLOW" "Backing up current corrupted databases..."
|
|
|
|
local backup_dir="${PLEX_DB_DIR}/corrupted-${BACKUP_TIMESTAMP}"
|
|
mkdir -p "$backup_dir"
|
|
|
|
# Backup main database if it exists
|
|
if [[ -f "${PLEX_DB_DIR}/com.plexapp.plugins.library.db" ]]; then
|
|
cp "${PLEX_DB_DIR}/com.plexapp.plugins.library.db" "$backup_dir/"
|
|
print_status "$GREEN" "Backed up corrupted main database"
|
|
fi
|
|
|
|
# Backup blobs database if it exists
|
|
if [[ -f "${PLEX_DB_DIR}/com.plexapp.plugins.library.blobs.db" ]]; then
|
|
cp "${PLEX_DB_DIR}/com.plexapp.plugins.library.blobs.db" "$backup_dir/"
|
|
print_status "$GREEN" "Backed up corrupted blobs database"
|
|
fi
|
|
|
|
print_status "$GREEN" "Corrupted databases backed up to: $backup_dir"
|
|
}
|
|
|
|
# Function to find best backup
|
|
find_best_backup() {
|
|
local backup_type="$1"
|
|
local latest_backup=""
|
|
|
|
# Find the most recent backup that exists and has reasonable size
|
|
for backup_file in "${PLEX_DB_DIR}/${backup_type}"-????-??-??*; do
|
|
if [[ -f "$backup_file" ]]; then
|
|
local file_size
|
|
file_size=$(stat -f%z "$backup_file" 2>/dev/null || stat -c%s "$backup_file" 2>/dev/null)
|
|
|
|
# Check if file size is reasonable (> 100MB for main DB, > 500MB for blobs)
|
|
if [[ "$backup_type" == "com.plexapp.plugins.library.db" && $file_size -gt 104857600 ]] || \
|
|
[[ "$backup_type" == "com.plexapp.plugins.library.blobs.db" && $file_size -gt 524288000 ]]; then
|
|
latest_backup="$backup_file"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo "$latest_backup"
|
|
}
|
|
|
|
# Function to restore from backup
|
|
restore_from_backup() {
|
|
print_status "$YELLOW" "Finding and restoring from best available backups..."
|
|
|
|
# Find best main database backup
|
|
local main_backup
|
|
main_backup=$(find_best_backup "com.plexapp.plugins.library.db")
|
|
if [[ -n "$main_backup" ]]; then
|
|
print_status "$GREEN" "Found main database backup: $(basename "$main_backup")"
|
|
|
|
# Remove corrupted main database
|
|
rm -f "${PLEX_DB_DIR}/com.plexapp.plugins.library.db"
|
|
|
|
# Copy backup to main location
|
|
cp "$main_backup" "${PLEX_DB_DIR}/com.plexapp.plugins.library.db"
|
|
|
|
# Set proper ownership and permissions
|
|
chown "$PLEX_USER:$PLEX_GROUP" "${PLEX_DB_DIR}/com.plexapp.plugins.library.db"
|
|
chmod 644 "${PLEX_DB_DIR}/com.plexapp.plugins.library.db"
|
|
|
|
print_status "$GREEN" "Main database restored successfully"
|
|
else
|
|
print_status "$RED" "No suitable main database backup found!"
|
|
exit 1
|
|
fi
|
|
|
|
# Find best blobs database backup
|
|
local blobs_backup
|
|
blobs_backup=$(find_best_backup "com.plexapp.plugins.library.blobs.db")
|
|
if [[ -n "$blobs_backup" ]]; then
|
|
print_status "$GREEN" "Found blobs database backup: $(basename "$blobs_backup")"
|
|
|
|
# Remove corrupted blobs database
|
|
rm -f "${PLEX_DB_DIR}/com.plexapp.plugins.library.blobs.db"
|
|
|
|
# Copy backup to main location
|
|
cp "$blobs_backup" "${PLEX_DB_DIR}/com.plexapp.plugins.library.blobs.db"
|
|
|
|
# Set proper ownership and permissions
|
|
chown "$PLEX_USER:$PLEX_GROUP" "${PLEX_DB_DIR}/com.plexapp.plugins.library.blobs.db"
|
|
chmod 644 "${PLEX_DB_DIR}/com.plexapp.plugins.library.blobs.db"
|
|
|
|
print_status "$GREEN" "Blobs database restored successfully"
|
|
else
|
|
print_status "$RED" "No suitable blobs database backup found!"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Function to verify restored databases
|
|
verify_databases() {
|
|
print_status "$YELLOW" "Verifying restored databases..."
|
|
|
|
# Check main database
|
|
if sqlite3 "${PLEX_DB_DIR}/com.plexapp.plugins.library.db" "PRAGMA integrity_check;" | grep -q "ok"; then
|
|
print_status "$GREEN" "Main database integrity check: PASSED"
|
|
else
|
|
print_status "$RED" "Main database integrity check: FAILED"
|
|
return 1
|
|
fi
|
|
|
|
# Check blobs database
|
|
if sqlite3 "${PLEX_DB_DIR}/com.plexapp.plugins.library.blobs.db" "PRAGMA integrity_check;" | grep -q "ok"; then
|
|
print_status "$GREEN" "Blobs database integrity check: PASSED"
|
|
else
|
|
print_status "$RED" "Blobs database integrity check: FAILED"
|
|
return 1
|
|
fi
|
|
|
|
print_status "$GREEN" "All database integrity checks passed!"
|
|
}
|
|
|
|
# Function to fix ownership issues
|
|
fix_ownership() {
|
|
print_status "$YELLOW" "Fixing file ownership in Plex database directory..."
|
|
|
|
# Fix ownership of all files in the database directory
|
|
chown -R "$PLEX_USER:$PLEX_GROUP" "$PLEX_DB_DIR"
|
|
|
|
# Verify critical files have correct ownership
|
|
local main_db="${PLEX_DB_DIR}/com.plexapp.plugins.library.db"
|
|
local blobs_db="${PLEX_DB_DIR}/com.plexapp.plugins.library.blobs.db"
|
|
|
|
if [[ -f "$main_db" ]]; then
|
|
local main_owner
|
|
main_owner=$(stat -f%Su:%Sg "$main_db" 2>/dev/null || stat -c%U:%G "$main_db" 2>/dev/null)
|
|
if [[ "$main_owner" == "$PLEX_USER:$PLEX_GROUP" ]]; then
|
|
print_status "$GREEN" "Main database ownership: CORRECT ($main_owner)"
|
|
else
|
|
print_status "$RED" "Main database ownership: INCORRECT ($main_owner)"
|
|
chown "$PLEX_USER:$PLEX_GROUP" "$main_db"
|
|
fi
|
|
fi
|
|
|
|
if [[ -f "$blobs_db" ]]; then
|
|
local blobs_owner=$(stat -f%Su:%Sg "$blobs_db" 2>/dev/null || stat -c%U:%G "$blobs_db" 2>/dev/null)
|
|
if [[ "$blobs_owner" == "$PLEX_USER:$PLEX_GROUP" ]]; then
|
|
print_status "$GREEN" "Blobs database ownership: CORRECT ($blobs_owner)"
|
|
else
|
|
print_status "$RED" "Blobs database ownership: INCORRECT ($blobs_owner)"
|
|
chown "$PLEX_USER:$PLEX_GROUP" "$blobs_db"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Function to clean up temporary files
|
|
cleanup_temp_files() {
|
|
print_status "$YELLOW" "Cleaning up temporary and lock files..."
|
|
|
|
# Remove any SQLite temporary files
|
|
rm -f "${PLEX_DB_DIR}"/*.db-shm
|
|
rm -f "${PLEX_DB_DIR}"/*.db-wal
|
|
rm -f "${PLEX_DB_DIR}"/*.tmp
|
|
|
|
print_status "$GREEN" "Temporary files cleaned up"
|
|
}
|
|
|
|
# Main recovery function
|
|
main() {
|
|
print_status "$BLUE" "=== NUCLEAR PLEX DATABASE RECOVERY STARTED ==="
|
|
print_status "$BLUE" "Timestamp: $(date)"
|
|
print_status "$BLUE" "Log file: $RECOVERY_LOG"
|
|
|
|
# Pre-flight checks
|
|
check_root
|
|
|
|
# Confirm with user
|
|
print_status "$YELLOW" "WARNING: This will completely replace your Plex databases with backups!"
|
|
print_status "$YELLOW" "This will result in some data loss (recent changes since last backup)."
|
|
read -p "Are you sure you want to continue? (yes/no): " -r
|
|
|
|
if [[ ! $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
|
|
print_status "$YELLOW" "Recovery cancelled by user"
|
|
exit 0
|
|
fi
|
|
|
|
# Stop Plex service
|
|
stop_plex
|
|
|
|
# Backup current corrupted databases
|
|
backup_corrupted_databases
|
|
|
|
# Restore from backup
|
|
restore_from_backup
|
|
|
|
# Fix ownership issues
|
|
fix_ownership
|
|
|
|
# Clean up temporary files
|
|
cleanup_temp_files
|
|
|
|
# Verify databases
|
|
verify_databases
|
|
|
|
# Start Plex service
|
|
start_plex
|
|
|
|
print_status "$GREEN" "=== NUCLEAR RECOVERY COMPLETED SUCCESSFULLY ==="
|
|
print_status "$GREEN" "Your Plex Media Server should now be functional."
|
|
print_status "$GREEN" "Check the web interface at: http://localhost:32400"
|
|
print_status "$YELLOW" "Note: You may need to re-scan your libraries to pick up recent changes."
|
|
print_status "$BLUE" "Recovery log saved to: $RECOVERY_LOG"
|
|
}
|
|
|
|
# Script usage
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
main "$@"
|
|
fi
|