diff --git a/jellyfin/restore_corrupted_database.md b/jellyfin/restore_corrupted_database.md new file mode 100644 index 0000000..78981b6 --- /dev/null +++ b/jellyfin/restore_corrupted_database.md @@ -0,0 +1,91 @@ +# Jellyfin SQLite Database Repair Guide + +This document explains how to use the `fix_jellyfin_db.sh` script to repair a corrupted Jellyfin `library.db` file. + +**Warning:** Repeated database corruption is a strong indicator of an underlying issue, most commonly a failing hard drive or SSD. If you have to run this script more than once, you should immediately investigate the health of your storage device using tools like `smartctl`. + +## How to Use the Script + +1. **Save the Script:** + Save the script content to a file named `fix_jellyfin_db.sh` on your server. + +2. **Make it Executable:** + Open a terminal and navigate to the directory where you saved the file. Run the following command to make it executable: + ```bash + chmod +x fix_jellyfin_db.sh + ``` + +3. **Run the Script:** + The script must be run with `sudo` because it needs to stop/start system services and modify files in `/var/lib/jellyfin/`. + ```bash + sudo ./fix_jellyfin_db.sh + ``` + +The script will print its progress as it executes each step. + +## What the Script Does: A Step-by-Step Breakdown + +The script automates the standard "dump and restore" method for SQLite recovery. + +#### Step 1: Stops the Jellyfin Service +To prevent any other process from reading or writing to the database during the repair, the script first stops Jellyfin. +```bash +systemctl stop jellyfin +``` + +#### Step 2: Backs Up the Corrupted Database +Your corrupted database is never deleted. It is copied to a new file with a timestamp, ensuring you have a fallback. +```bash +# Example backup name: library.db.corrupt.2023-10-27-14:30:00 +cp library.db library.db.corrupt.[timestamp] +``` + +#### Step 3: Dumps Data to an SQL File +It uses the `sqlite3` command-line tool to read every piece of data it can from the corrupted database and write it as a series of SQL commands to a text file named `library_dump.sql`. +```bash +sqlite3 library.db .dump > library_dump.sql +``` + +#### Step 4: Patches the Dump File +If the dump process hit a severe error, it writes `ROLLBACK;` at the end of the dump file. This would cause the import to fail. The script checks for this exact line and replaces it with `COMMIT;`, forcing SQLite to save all the data it was able to salvage. +```bash +sed -i '$ s/ROLLBACK; -- due to errors/COMMIT;/' library_dump.sql +``` + +#### Step 5: Restores the Database +The script renames the original corrupted file and then creates a brand new, empty `library.db` by feeding it the `library_dump.sql` file. This rebuilds the entire database structure from scratch, leaving all corruption behind. +```bash +# Move old DB +mv library.db library.db.repaired-from + +# Create new DB from dump +sqlite3 library.db < library_dump.sql +``` + +#### Step 6: Verifies the New Database +The script checks that the new database file is not empty. It then runs `PRAGMA integrity_check`, which should return `ok` on a healthy database. +```bash +sqlite3 library.db "PRAGMA integrity_check;" +``` + +#### Step 7: Sets Permissions and Restarts Jellyfin +Finally, it sets the correct `jellyfin:jellyfin` ownership and file permissions on the new database file and restarts the Jellyfin service. +```bash +chown jellyfin:jellyfin library.db +chmod 664 library.db +systemctl start jellyfin +``` + +## Post-Repair Actions + +After the script completes successfully, you should verify that your Jellyfin library, users, and watch history are intact. + +The script leaves the backup files in `/var/lib/jellyfin/data/` for safety: +- `library.db.corrupt.[timestamp]` +- `library.db.repaired-from` +- `library_dump.sql` + +Once you have confirmed Jellyfin is working correctly for a day or two, you can safely delete these files to save space: +```bash +sudo rm /var/lib/jellyfin/data/library.db.corrupt.* /var/lib/jellyfin/data/library.db.repaired-from /var/lib/jellyfin/data/library_dump.sql +``` \ No newline at end of file diff --git a/jellyfin/restore_corrupted_database.sh b/jellyfin/restore_corrupted_database.sh new file mode 100644 index 0000000..7681bac --- /dev/null +++ b/jellyfin/restore_corrupted_database.sh @@ -0,0 +1,124 @@ +#!/bin/bash + +# ============================================================================== +# Jellyfin SQLite Database Repair Script +# +# This script automates the process of recovering a corrupted Jellyfin +# library.db file by dumping its content to an SQL file and re-importing +# it into a new, clean database. +# +# MUST BE RUN AS ROOT OR WITH SUDO. +# ============================================================================== + +# --- Configuration --- +JELLYFIN_DATA_DIR="/var/lib/jellyfin/data" +DB_FILE="library.db" +DUMP_FILE="library_dump.sql" +# --- End Configuration --- + +# --- Safety Checks --- +# Check if running as root +if [ "$EUID" -ne 0 ]; then + echo "ERROR: This script must be run as root or with sudo." + exit 1 +fi + +# Check if sqlite3 is installed +if ! command -v sqlite3 &> /dev/null; then + echo "ERROR: sqlite3 is not installed. Please install it first." + echo "On Debian/Ubuntu: sudo apt-get install sqlite3" + exit 1 +fi + +# Navigate to the data directory or exit if it doesn't exist +cd "$JELLYFIN_DATA_DIR" || { echo "ERROR: Could not find Jellyfin data directory at $JELLYFIN_DATA_DIR"; exit 1; } + +echo "--- Jellyfin DB Repair Initialized ---" + +# --- Step 1: Stop Jellyfin and Backup --- +echo "[1/8] Stopping the Jellyfin service..." +systemctl stop jellyfin +echo "Service stopped." + +# Create a timestamped backup +TIMESTAMP=$(date +%F-%T) +CORRUPT_DB_BACKUP="library.db.corrupt.$TIMESTAMP" +echo "[2/8] Backing up corrupted database to $CORRUPT_DB_BACKUP..." +if [ -f "$DB_FILE" ]; then + cp "$DB_FILE" "$CORRUPT_DB_BACKUP" + echo "Backup created." +else + echo "ERROR: $DB_FILE not found! Cannot proceed." + systemctl start jellyfin # Try to start the service again + exit 1 +fi + + +# --- Step 2: Dump the Database --- +echo "[3/8] Dumping data from the corrupted database to $DUMP_FILE..." +# We use .dump, which will try to read everything possible. +# Using 'tee' to avoid permission issues with redirection. +sqlite3 "$DB_FILE" .dump | tee "$DUMP_FILE" > /dev/null +echo "Dump complete." + + +# --- Step 3: Fix the Dump File if Necessary --- +echo "[4/8] Checking dump file for errors..." +# If the dump process encountered an unrecoverable error, it ends with ROLLBACK. +# We must change it to COMMIT to save the salvaged data. +if grep -q "ROLLBACK;" "$DUMP_FILE"; then + echo "-> Found 'ROLLBACK'. Changing to 'COMMIT' to salvage data..." + sed -i '$ s/ROLLBACK; -- due to errors/COMMIT;/' "$DUMP_FILE" + echo "-> Dump file patched." +else + echo "-> No 'ROLLBACK' found. Dump file appears clean." +fi + + +# --- Step 4: Restore from Dump --- +echo "[5/8] Moving old corrupted database aside..." +mv "$DB_FILE" "${DB_FILE}.repaired-from" +echo "[6/8] Importing data into a new, clean database. This may take a moment..." +sqlite3 "$DB_FILE" < "$DUMP_FILE" + + +# --- Step 5: Verification and Cleanup --- +# Check if the new database file was created and is not empty +if [ ! -s "$DB_FILE" ]; then + echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + echo "!! CRITICAL ERROR: The new database is empty! !!" + echo "!! The repair has FAILED. Restoring old DB. !!" + echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + mv "${DB_FILE}.repaired-from" "$DB_FILE" # Restore the moved file + systemctl start jellyfin + exit 1 +fi + +echo "-> New database created successfully." + +# Run integrity check +echo "[7/8] Verifying integrity of the new database..." +INTEGRITY_CHECK=$(sqlite3 "$DB_FILE" "PRAGMA integrity_check;") + +if [ "$INTEGRITY_CHECK" == "ok" ]; then + echo "-> SUCCESS! Integrity check passed." +else + echo "-> WARNING: Integrity check on new DB reported: $INTEGRITY_CHECK" + echo "-> The database may still have issues, but is likely usable." +fi + + +# --- Step 6: Finalize --- +echo "[8/8] Setting correct file permissions and restarting Jellyfin..." +chown jellyfin:jellyfin "$DB_FILE" +chmod 664 "$DB_FILE" +systemctl start jellyfin +echo "-> Jellyfin service started." + +echo "" +echo "--- Repair Process Complete ---" +echo "Your Jellyfin database has been repaired and the service restarted." +echo "Please check your Jellyfin web interface to ensure everything is working." +echo "Backup files ($CORRUPT_DB_BACKUP, ${DB_FILE}.repaired-from, $DUMP_FILE) have been kept in $JELLYFIN_DATA_DIR for safety." +echo "" +echo "IMPORTANT: Repeated corruption is a sign of a failing disk. Please check your disk health." \ No newline at end of file