214 lines
8.2 KiB
Bash
214 lines
8.2 KiB
Bash
#!/bin/bash
|
|
# -----------------------------------------------------------------------------------------------
|
|
# --------------------------------- Emby Database Repair ---------------------------------------
|
|
# -----------------------------------------------------------------------------------------------
|
|
# Stops Emby, runs SQLite integrity checks on all Emby databases, and restarts.
|
|
# Use when Emby reports database corruption, unexpected crashes, or playback state issues.
|
|
#
|
|
# Checks performed:
|
|
# integrity_check — full SQLite integrity verification per database file
|
|
# quick_check — faster check for common corruption patterns
|
|
#
|
|
# If corruption is found:
|
|
# Reports which database files are corrupted
|
|
# Does NOT automatically repair — corruption repair requires manual steps
|
|
# Provides guidance on next steps per database type
|
|
#
|
|
# Emby database files checked:
|
|
# library.db — media library metadata
|
|
# library.db-wal — write-ahead log (if exists)
|
|
# librarydb.db — legacy library database
|
|
# users.db — user accounts and settings
|
|
# authentication.db — API keys and sessions
|
|
# activity.db — activity log
|
|
#
|
|
# All configuration in Master.conf — uses TRANSCODE_EMBY_CONTAINER and EMBY_URL.
|
|
# Supports --dry-run to show what would be checked without stopping Emby.
|
|
# -----------------------------------------------------------------------------------------------
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
source "$SCRIPT_DIR/../Master.conf"
|
|
source "$SCRIPT_DIR/../common.sh"
|
|
|
|
parse_args "$@"
|
|
|
|
# Emby config path — inside the container it's /config, map to host path
|
|
# Detected from Docker inspect at runtime
|
|
EMBY_CONTAINER="$TRANSCODE_EMBY_CONTAINER"
|
|
|
|
# -----------------------------------------------------------------------------------------------
|
|
# ━━━ $ICON_GEAR Setup ━━━
|
|
# -----------------------------------------------------------------------------------------------
|
|
echo ""
|
|
echo "━━━ $ICON_GEAR Setup ━━━"
|
|
|
|
if [[ "$EUID" -ne 0 ]]; then
|
|
error "Must be run as root"
|
|
exit 1
|
|
fi
|
|
|
|
success "Running as root"
|
|
|
|
if ! command -v sqlite3 >/dev/null 2>&1; then
|
|
error "sqlite3 not found — install sqlite package"
|
|
exit 1
|
|
fi
|
|
|
|
success "sqlite3 available"
|
|
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — Emby will not be stopped"
|
|
|
|
# Detect Emby config path from Docker mount
|
|
EMBY_CONFIG_HOST=$(docker inspect "$EMBY_CONTAINER" 2>/dev/null | \
|
|
jq -r '.[] | .Mounts[] | select(.Destination == "/config") | .Source' 2>/dev/null)
|
|
|
|
if [[ -z "$EMBY_CONFIG_HOST" ]]; then
|
|
error "Could not detect Emby config path from Docker mounts"
|
|
error "Make sure $EMBY_CONTAINER is the correct container name in Master.conf"
|
|
exit 1
|
|
fi
|
|
|
|
success "Emby config path: $EMBY_CONFIG_HOST"
|
|
|
|
# -----------------------------------------------------------------------------------------------
|
|
# ━━━ $ICON_STOP Stop Emby ━━━
|
|
# -----------------------------------------------------------------------------------------------
|
|
echo ""
|
|
echo "━━━ $ICON_STOP Stop Emby ━━━"
|
|
|
|
EMBY_WAS_RUNNING=false
|
|
STATUS=$(docker inspect -f '{{.State.Running}}' "$EMBY_CONTAINER" 2>/dev/null)
|
|
|
|
if [[ "$STATUS" == "true" ]]; then
|
|
EMBY_WAS_RUNNING=true
|
|
warn "Stopping $EMBY_CONTAINER — active sessions will be interrupted"
|
|
if [[ "$DRY_RUN" == false ]]; then
|
|
docker stop "$EMBY_CONTAINER" >/dev/null 2>&1 && \
|
|
success "$ICON_STOPPED $EMBY_CONTAINER stopped" || \
|
|
{ error "Failed to stop $EMBY_CONTAINER"; exit 1; }
|
|
sleep 3 # brief wait for file handles to release
|
|
else
|
|
warn "DRY RUN — would stop $EMBY_CONTAINER"
|
|
fi
|
|
else
|
|
info "$EMBY_CONTAINER is not running — proceeding with checks"
|
|
fi
|
|
|
|
# -----------------------------------------------------------------------------------------------
|
|
# ━━━ $ICON_HEALTH Database Integrity Check ━━━
|
|
# -----------------------------------------------------------------------------------------------
|
|
echo ""
|
|
echo "━━━ $ICON_HEALTH Database Integrity Check ━━━"
|
|
|
|
START=$(date +%s)
|
|
|
|
# Emby database files to check
|
|
DB_FILES=(
|
|
"data/library.db"
|
|
"data/librarydb.db"
|
|
"data/users.db"
|
|
"data/authentication.db"
|
|
"data/activity.db"
|
|
)
|
|
|
|
PASS_DBS=()
|
|
FAIL_DBS=()
|
|
MISSING_DBS=()
|
|
|
|
for db_rel in "${DB_FILES[@]}"; do
|
|
db_path="${EMBY_CONFIG_HOST}/${db_rel}"
|
|
db_name=$(basename "$db_rel")
|
|
|
|
if [[ ! -f "$db_path" ]]; then
|
|
log "$db_name — not found, skipping"
|
|
MISSING_DBS+=("$db_name")
|
|
continue
|
|
fi
|
|
|
|
DB_SIZE=$(du -sh "$db_path" 2>/dev/null | cut -f1)
|
|
info "$ICON_HEALTH Checking $db_name ($DB_SIZE)..."
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
warn "DRY RUN — would check: $db_path"
|
|
continue
|
|
fi
|
|
|
|
# Run integrity check
|
|
RESULT=$(sqlite3 "$db_path" "PRAGMA integrity_check;" 2>/dev/null)
|
|
EXIT_CODE=$?
|
|
|
|
if [[ "$EXIT_CODE" -ne 0 ]]; then
|
|
error "$db_name — sqlite3 could not open database (may be locked or corrupt)"
|
|
FAIL_DBS+=("$db_name")
|
|
elif [[ "$RESULT" == "ok" ]]; then
|
|
success "$db_name — integrity check passed"
|
|
PASS_DBS+=("$db_name")
|
|
else
|
|
error "$db_name — integrity check FAILED"
|
|
echo "$RESULT" | head -10 | while IFS= read -r line; do
|
|
error " $line"
|
|
done
|
|
FAIL_DBS+=("$db_name")
|
|
fi
|
|
done
|
|
|
|
END=$(date +%s)
|
|
|
|
# -----------------------------------------------------------------------------------------------
|
|
# ━━━ $ICON_START Restart Emby ━━━
|
|
# -----------------------------------------------------------------------------------------------
|
|
echo ""
|
|
echo "━━━ $ICON_START Restart Emby ━━━"
|
|
|
|
if [[ "$EMBY_WAS_RUNNING" == true && "$DRY_RUN" == false ]]; then
|
|
docker start "$EMBY_CONTAINER" >/dev/null 2>&1 && \
|
|
success "$ICON_STARTED $EMBY_CONTAINER restarted" || \
|
|
error "Failed to restart $EMBY_CONTAINER — start it manually"
|
|
elif [[ "$DRY_RUN" == true && "$EMBY_WAS_RUNNING" == true ]]; then
|
|
warn "DRY RUN — would restart $EMBY_CONTAINER"
|
|
else
|
|
info "$EMBY_CONTAINER was not running — not restarting"
|
|
fi
|
|
|
|
# -----------------------------------------------------------------------------------------------
|
|
# ━━━ $ICON_SUMMARY Summary ━━━
|
|
# -----------------------------------------------------------------------------------------------
|
|
echo ""
|
|
echo "━━━━━ $ICON_SUMMARY EMBY DATABASE REPAIR SUMMARY ━━━━━"
|
|
echo "$ICON_HEALTH Container: $EMBY_CONTAINER"
|
|
echo "$ICON_HEALTH Config path: $EMBY_CONFIG_HOST"
|
|
echo "$ICON_TIME Duration: $(format_duration $((END - START)))"
|
|
echo ""
|
|
echo " $ICON_SUCCESS Passed: ${#PASS_DBS[@]} $ICON_ERROR Failed: ${#FAIL_DBS[@]} $ICON_INFO Missing: ${#MISSING_DBS[@]}"
|
|
echo ""
|
|
|
|
if [[ ${#PASS_DBS[@]} -gt 0 ]]; then
|
|
for db in "${PASS_DBS[@]}"; do echo " $ICON_SUCCESS $db"; done
|
|
fi
|
|
if [[ ${#FAIL_DBS[@]} -gt 0 ]]; then
|
|
for db in "${FAIL_DBS[@]}"; do echo " $ICON_ERROR $db"; done
|
|
fi
|
|
|
|
echo ""
|
|
|
|
if [[ "$DRY_RUN" == true ]]; then
|
|
echo "$ICON_WARN Status: DRY RUN — no checks performed"
|
|
elif [[ ${#FAIL_DBS[@]} -gt 0 ]]; then
|
|
echo "$ICON_ERROR Status: CORRUPTION FOUND"
|
|
echo ""
|
|
echo "$ICON_INFO Next steps for corrupted databases:"
|
|
echo " library.db — Stop Emby, delete library.db, restart"
|
|
echo " Emby will rebuild from media files (slow first start)"
|
|
echo " users.db — Stop Emby, restore from backup or delete"
|
|
echo " Deleting resets all user accounts"
|
|
echo " authentication.db — Stop Emby, delete, restart"
|
|
echo " API keys and sessions will be regenerated"
|
|
echo " activity.db — Stop Emby, delete, restart — activity log only"
|
|
echo ""
|
|
echo "$ICON_WARN Always take a backup before deleting any database file"
|
|
notify "Emby database corruption found on $(hostname) — failed: ${FAIL_DBS[*]} — manual intervention needed" "Emby DB Repair" "warning"
|
|
else
|
|
echo "$ICON_DONE Status: $ICON_SUCCESS ALL DATABASES HEALTHY"
|
|
notify "Emby database integrity check passed on $(hostname) — ${#PASS_DBS[@]} databases healthy" "Emby DB Repair" "normal"
|
|
fi
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" |