Compare commits

...

48 Commits

Author SHA1 Message Date
Chuck
abc552fb12
Merge pull request #253 from ChuckPa/chuckpa/readme
Minor Update & Correct documentation for v1.12.00
2025-10-21 17:33:14 -04:00
ChuckPa
aa76cbfefd
Update & Correct documentation for v1.12 2025-10-21 17:26:46 -04:00
Chuck
d79b5e2b9d
Merge pull request #252 from ChuckPa/chuckpa/dodeflate
v1.12.00 - Add  Deflate command

Reconstruct bandwidth statistics table  row  by row instead of previous bulk copy of non-null values
Regenerate new IDs during reconstruction for new indexes and reindex
2025-10-20 22:28:24 -04:00
ChuckPa
3bfb510ef7
Documentation correction
ASUSTOR - Incorrect location
2025-10-20 22:12:45 -04:00
ChuckPa
247338278b
Add Deflate command
Deflate
- Create new bandwidth_statistics table with proper schema.
- Transfer only valid data from existing bandwidth statistics into new.
- Drop old table.
- Vacuum into new database.
Merge Prune & Purge as one proper command
Update ASUSTOR documentation error.

Finalize Deflate integration & reporting.

Update Release Notes
2025-10-20 19:23:22 -04:00
Chuck
dea8a805ce
Merge pull request #239 from ChuckPa/chuckpa/Hotio-Cache-Dir
HotIO -  Path to Cache dir incorrect
2025-07-31 20:20:46 -04:00
ChuckPa
6d8bafbf99
HotIO - Path to Cache dir incorrect
Fixes path (working around silly symlink)
2025-07-31 20:18:21 -04:00
Chuck
e2acd24593
Merge pull request #232 from ChuckPa/chuckpa/restart-path
Correct path issue with restart
2025-07-07 20:23:33 -04:00
ChuckPa
24b746db1b
Correct path issue with restart 2025-07-06 19:29:25 -04:00
Chuck
32d5f8f737
Merge pull request #228 from ChuckPa/chuckpa/Freebsd-releases
Add support for FreeBSD (14+)
2025-06-26 00:03:35 -04:00
ChuckPa
06c0f810dd
Add support for FreeBSD (14+)
Thanks @cdf-eagles
2025-06-25 20:39:07 -04:00
Chuck
ac6058dd48
Merge pull request #226 from cdf-eagles/fix-freebsd-startstop
Fixed bug for FreeBSD Plex service start/stop commands
2025-06-25 18:37:55 -04:00
Christopher Fernando
019fd197f8
Fixed bug for FreeBSD Plex service start/stop commands 2025-06-25 14:07:00 -05:00
Chuck
ebf170b1eb
Merge pull request #225 from cdf-eagles/freebsd-compat
FreeBSD 14+ Compatibility Added.
2025-06-25 12:07:54 -04:00
Christopher Fernando
38cd4ded5c
FreeBSD 14+ Compatibility Added.
See closed PR "Freebsd compat #224" for discussion.
Updated version.
Uses FreeBSD Ports (pkg command) to determine which plexmediaserver package is installed and sets paths.
2025-06-25 10:58:43 -05:00
Chuck
44f722166d
Merge pull request #222 from ChuckPa/chuckpa/unitialized
Correct missing variable initialization
2025-06-22 16:06:59 -04:00
ChuckPa
2264ee89be
Correct missing variable initialization
Restart after update had missing default value.
2025-06-22 16:03:17 -04:00
Chuck
93886de20f
Merge pull request #215 from danrahn/master
Add 98=quit/99=exit to PowerShell script
2025-06-05 21:59:42 -04:00
danrahn
a3ba41b668 Copy DBRepair.sh's new 98=quit and 99=exit
Also remove the temporary deflate code and other minor refactoring.
2025-06-05 18:44:54 -07:00
Chuck
f96032e9c4
Merge pull request #218 from ChuckPa/chuckpa/menu
v1.11.05 - Cleanup menu

Thanks @kimpenhaus
2025-06-05 13:38:43 -04:00
ChuckPa
ea78ea663e
v1.11.05 - Cleanup menu 2025-06-05 13:30:24 -04:00
Chuck
f2a821c170
Merge pull request #216 from ChuckPa/chuckpa/relauch
v1.11.04

1.  Add Binhex start/stop support
2.  Correct 98/99 menu options
3.  Remove Deflate
2025-06-04 10:14:05 -04:00
ChuckPa
baf8398085
v1.11.04
1.  Add  Start/Stop support for Binhex containers
1.  Restart after update (optional)
2.  Remove DEFLATE (PMS 1.41.8)
2025-06-03 12:39:29 -04:00
Chuck
65f4e5d33d
911 - Deflate 2025-05-31 23:12:59 -04:00
Chuck
4872b82815
Merge pull request #211 from ChuckPa/chuckpa/add-log
v1.11.03 -Add summary logfile messages
2025-05-30 23:25:49 -04:00
ChuckPa
859f2bdbe1
Add Log entries to Deflate 2025-05-30 23:25:04 -04:00
Chuck
0e1797a4c0
Merge pull request #210 from ChuckPa/chuckpa/add-log
v1.11.03 -Add summary logfile messages
2025-05-30 23:21:38 -04:00
ChuckPa
cf54baa5c4
v1.11.03 -Add summary logfile messages
v1.11.03
1.  Add DEFLATE command to provide fast database cleanup while Plex engineering fixes the root problems.
2.  Handle Databases not on same storage as AppSuppDir
3.  Calculate SpaceNeeded based on $DBDIR
4.  Fix menu items
5.  Fix reporting of SpaceNeeded when unable to process.
6.  Add summary logging for DEFLATE actions in case disk full.
2025-05-30 23:19:34 -04:00
Chuck
b431e49455
Merge pull request #208 from ChuckPa/chuckpa/plex-bloat
Provide temporary DB bloat deflate capability for huge databases.

Documentation in the Release Notes
2025-05-30 19:31:42 -04:00
ChuckPa
c5c1f7b683
v1.11.02
1.  Handle Databases not on same storage as AppSuppDir
2.  Calculate SpaceNeeded based on $DBDIR
3.  Fix menu items

4.  Fix reporting of SpaceNeeded when unable to process.

v1.11.02

Add DEFLATE command to provide fast database cleanup while Plex engineering fixes the root problems.
2025-05-30 19:22:34 -04:00
Chuck
8c5f7606a7
Merge pull request #202 from danrahn/master
Add statistics_bandwidth Cleanup to Windows Scripts
2025-05-24 19:17:45 -04:00
danrahn
3bb22f56cd Bump version 2025-05-24 14:34:44 -07:00
danrahn
481814ed2c Add statistics_bandwidth cleanup to Windows scripts 2025-05-24 10:34:41 -07:00
Chuck
d6f4dbf263
Merge pull request #201 from danrahn/master
Update Windows scripts to reflect name change
2025-05-24 10:39:30 -04:00
danrahn
1c5c4b6fbc Update Windows scripts to reflect name change 2025-05-23 19:51:46 -07:00
ChuckPa
98c5274d86
Update Repo name URL and reissue 2025-05-23 21:17:40 -04:00
ChuckPa
1c1ed5a8c1
Comply with Plex, inc. Trademark Policy
Comply with Plex,inc. Trademark Policy
2025-05-23 19:55:51 -04:00
Chuck
be74c6f85e
Merge pull request #199 from ChuckPa/chuckpa/final-tags
Refactor version tags
2025-05-23 01:37:15 -04:00
ChuckPa
865da1cd3c
Refactor version tags 2025-05-23 01:36:00 -04:00
Chuck
ca489c6c3f
Merge pull request #198 from ChuckPa/chuckpa/final-tags
Refactor version tags
2025-05-23 01:30:10 -04:00
ChuckPa
75481e41d3
Refactor version tags 2025-05-23 01:26:33 -04:00
Chuck
3262ec7f7a
Cleanup update tag handling. Inform users of DB cleanup tasks.
Correct version tag handling (remove junk)
2025-05-22 19:40:14 -04:00
ChuckPa
8aed201782
Correct version tag handling (remove junk)
Users would see multiple versions' tag info.  This is undesirable.
2025-05-22 19:38:05 -04:00
Chuck
21196a3cc3
Merge pull request #196 from ChuckPa/chuckpa/may-cleanup
v1.10.05
2025-05-20 20:26:59 -04:00
ChuckPa
a34511a219
May 2025 cleanup
Minor DB Cleanup extras.
2025-05-20 20:19:14 -04:00
Chuck
e2a3d1d04b
Merge pull request #194 from danrahn/master
[Windows] Check PMS state in more places
2025-04-30 20:06:45 -04:00
danrahn
82f1575293 [Windows] Check PMS state in more places
While it probably won't address #184 since the batch script works without issue,
but I was unable to replicate this on my system, so this is at least an
intermediate step. Also do some refactoring around the export process, and don't
remove temp files in scripted mode if the last operation failed.
2025-04-26 10:53:17 -07:00
Chuck
19b9b5bf6f
Update README.md 2025-04-01 19:16:46 -04:00
9 changed files with 823 additions and 322 deletions

View File

@ -10,7 +10,7 @@ To contribute to the project, please follow the following instructions:
### When submitting your work for review and merge: ### When submitting your work for review and merge:
1. Create an issue in the PlexDBRepair repo against the current release 1. Create an issue in the DBRepair repo against the current release
- Describe the deficiency to be addressed in sufficient detail - Describe the deficiency to be addressed in sufficient detail
2. Complete your work in your branch 2. Complete your work in your branch
@ -26,7 +26,7 @@ To contribute to the project, please follow the following instructions:
5. In the pull request, provide a description of what change(s) where made 5. In the pull request, provide a description of what change(s) where made
- As last text added, on a blank line, - As last text added, on a blank line,
- Add the text: `Fixes:` followed by the URL of the open Issue - Add the text: `Fixes:` followed by the URL of the open Issue
eg: Fixes: https://ChuckPa/PlexDBRepair/issues/12 (if we were fixing issue 12) eg: Fixes: https://github.com/ChuckPa/DBRepair/issues/12 (if we were fixing issue 12)
- Adding the above text & URL has the following impact: - Adding the above text & URL has the following impact:
-- The Issue which prompted the change is forever linked to the PR making documentation easy. -- The Issue which prompted the change is forever linked to the PR making documentation easy.

View File

@ -1,13 +1,13 @@
#!/bin/sh #!/bin/bash
######################################################################### #########################################################################
# Plex Media Server database check and repair utility script. # # Database Repair Utility for Plex Media Server. #
# Maintainer: ChuckPa # # Maintainer: ChuckPa #
# Version: v1.10.03 # # Version: v1.12.01 #
# Date: 17-Mar-2025 # # Date: 21-Oct-2025 #
######################################################################### #########################################################################
# Version for display purposes # Version for display purposes
Version="v1.10.03" Version="v1.12.01"
# Have the databases passed integrity checks # Have the databases passed integrity checks
CheckedDB=0 CheckedDB=0
@ -65,6 +65,9 @@ DFFLAGS="-m"
# If LC_ALL is null, default to C # If LC_ALL is null, default to C
[ "$LC_ALL" = "" ] && export LC_ALL=C [ "$LC_ALL" = "" ] && export LC_ALL=C
# Check Restart
[ "$DBRepairRestartedAfterUpdate" = "" ] && DBRepairRestartedAfterUpdate=0
# Universal output function # Universal output function
Output() { Output() {
if [ $Scripted -gt 0 ]; then if [ $Scripted -gt 0 ]; then
@ -219,11 +222,11 @@ FreeSpaceAvailable() {
[ "$1" != "" ] && Multiplier=$1 [ "$1" != "" ] && Multiplier=$1
# Available space where DB resides # Available space where DB resides
SpaceAvailable=$(df $DFFLAGS "$AppSuppDir" | tail -1 | awk '{print $4}') SpaceAvailable=$(df $DFFLAGS "$DBDIR" | tail -1 | awk '{print $4}')
# Get size of DB and blobs, Minimally needing sum of both # Get size of DB and blobs, Minimally needing sum of both
LibSize="$(stat $STATFMT $STATBYTES "$CPPL.db")" LibSize="$(stat $STATFMT $STATBYTES "${DBDIR}/$CPPL.db")"
BlobsSize="$(stat $STATFMT $STATBYTES "$CPPL.blobs.db")" BlobsSize="$(stat $STATFMT $STATBYTES "${DBDIR}/$CPPL.blobs.db")"
SpaceNeeded=$((LibSize + BlobsSize)) SpaceNeeded=$((LibSize + BlobsSize))
# Compute need (minimum $Multiplier existing; current, backup, temp and room to write new) # Compute need (minimum $Multiplier existing; current, backup, temp and room to write new)
@ -277,21 +280,25 @@ ConfirmYesNo() {
Answer="" Answer=""
while [ "$Answer" != "Y" ] && [ "$Answer" != "N" ] while [ "$Answer" != "Y" ] && [ "$Answer" != "N" ]
do do
printf "%s (Y/N) ? " "$1" if [ $Scripted -eq 1 ]; then
read Input Answer=Y
else
printf "%s (Y/N) ? " "$1"
read Input
# EOF = No # EOF = No
case "$Input" in case "$Input" in
YES|YE|Y|yes|ye|y) YES|YE|Y|yes|ye|y)
Answer=Y Answer=Y
;; ;;
NO|N|no|n) NO|N|no|n)
Answer=N Answer=N
;; ;;
*) *)
Answer="" Answer=""
;; ;;
esac esac
fi
# Unrecognized # Unrecognized
if [ "$Answer" != "Y" ] && [ "$Answer" != "N" ]; then if [ "$Answer" != "Y" ] && [ "$Answer" != "N" ]; then
@ -370,7 +377,7 @@ GetOverride() {
# Determine which host we are running on and set variables # Determine which host we are running on and set variables
HostConfig() { HostConfig() {
# On all hosts except Mac # On all hosts except Mac/FreeBSD
PIDOF="pidof" PIDOF="pidof"
STATFMT="-c" STATFMT="-c"
STATBYTES="%s" STATBYTES="%s"
@ -619,6 +626,66 @@ HostConfig() {
HostType="Mac" HostType="Mac"
return 0 return 0
# FreeBSD 14+
elif [ -e /etc/os-release ] && [ "$(cat /etc/os-release | grep FreeBSD)" != "" ]; then
# Load functions for interacting with FreeBSD RC System
. /etc/rc.subr
# Find PMS
PLEXPKG=$(pkg info | grep plexmediaserver | awk '{print $1}')
if [ "x$PLEXPKG" != "x" ]; then # Plex ports package is installed
BsdRcFile=$(pkg list $PLEXPKG | grep "/usr/local/etc/rc.d")
BsdService=$(basename $BsdRcFile)
# FreeBSD Ports has two packages for Plex - determine which one is installed
BsdPlexPass="$(pkg info $PLEXPKG | grep ^Name | awk '{print $3}' | sed -e 's/plexmediaserver//')"
# Load FreeBSD RC configuration for Plex
load_rc_config $BsdService
# Use FreeBSD RC configuration to set paths
if [ "x$plexmediaserver_plexpass_support_path" != "x" ]; then
DBDIR="${plexmediaserver_plexpass_support_path}/Plex Media Server/Plug-in Support/Databases"
CACHEDIR="${plexmediaserver_plexpass_support_path}/Plex Media Server/Cache"
elif [ "x$plexmediaserver_support_path" != "x" ]; then
DBDIR="${plexmediaserver_support_path}/Plex Media Server/Plug-in Support/Databases"
CACHEDIR="${plexmediaserver_support_path}/Plex Media Server/Cache"
else
# System is using default Ports package configuration paths
DBDIR="/usr/local/plexdata${BsdPlexPass}/Plex Media Server/Plug-in Support/Databases"
CACHEDIR="/usr/local/plexdata${BsdPlexPass}/Plex Media Server/Cache"
fi
# Where is the software
AppSuppDir=$(dirname `pkg list $PLEXPKG | grep Plex_Media_Server`)
PLEX_SQLITE="${AppSuppDir}/Plex SQLite"
LOGFILE="$DBDIR/DBRepair.log"
LOG_TOOL="logger"
TMPDIR="/tmp"
SYSTMP="$TMPDIR"
else
Output "Plex Media Server FreeBSD PKG is not installed!"
Fail=1
return 1
fi
# FreeBSD uses pgrep and uses different stat options
PIDOF="pgrep"
STATFMT="-f"
STATBYTES="%z"
STATPERMS="%Lp"
# User 'plex' exists on FreeBSD, but the tool may not be run as that service account.
RootRequired=1
HaveStartStop=1
StartCommand="/usr/sbin/service ${BsdService} start"
StopCommand="/usr/sbin/service ${BsdService} stop"
HostType="FreeBSD"
return 0
# Western Digital (OS5) # Western Digital (OS5)
elif [ -f /etc/system.conf ] && [ -d /mnt/HD/HD_a2/Nas_Prog/plexmediaserver ] && \ elif [ -f /etc/system.conf ] && [ -d /mnt/HD/HD_a2/Nas_Prog/plexmediaserver ] && \
grep "Western Digital Corp" /etc/system.conf >/dev/null; then grep "Western Digital Corp" /etc/system.conf >/dev/null; then
@ -652,7 +719,7 @@ HostConfig() {
AppSuppDir="/config" AppSuppDir="/config"
PID_FILE="$AppSuppDir/plexmediaserver.pid" PID_FILE="$AppSuppDir/plexmediaserver.pid"
DBDIR="$AppSuppDir/Plug-in Support/Databases" DBDIR="$AppSuppDir/Plug-in Support/Databases"
CACHEDIR="$AppSuppDir/Plex Media Server/Cache/PhotoTranscoder" CACHEDIR="$AppSuppDir/Cache/PhotoTranscoder"
LOGFILE="$DBDIR/DBRepair.log" LOGFILE="$DBDIR/DBRepair.log"
LOG_TOOL="logger" LOG_TOOL="logger"
@ -712,6 +779,12 @@ HostConfig() {
LOGFILE="$DBDIR/DBRepair.log" LOGFILE="$DBDIR/DBRepair.log"
LOG_TOOL="logger" LOG_TOOL="logger"
if grep rpcinterface /etc/supervisor.conf > /dev/null; then
HaveStartStop=1
StartCommand="supervisorctl start plexmediaserver"
StopCommand="supervisorctl stop plexmediaserver"
fi
HostType="BINHEX" HostType="BINHEX"
return 0 return 0
@ -1093,7 +1166,7 @@ DoRepair() {
[ -e $CPPL.blobs.db ] && mv $CPPL.blobs.db "$TMPDIR/$CPPL.blobs.db-BACKUP-$TimeStamp" [ -e $CPPL.blobs.db ] && mv $CPPL.blobs.db "$TMPDIR/$CPPL.blobs.db-BACKUP-$TimeStamp"
Output "Making repaired databases active" Output "Making repaired databases active"
WriteLog "Making repaired databases active" WriteLog "Repair - Making repaired databases active"
mv "$TMPDIR/$CPPL.db-REPAIR-$TimeStamp" $CPPL.db mv "$TMPDIR/$CPPL.db-REPAIR-$TimeStamp" $CPPL.db
mv "$TMPDIR/$CPPL.blobs.db-REPAIR-$TimeStamp" $CPPL.blobs.db mv "$TMPDIR/$CPPL.blobs.db-REPAIR-$TimeStamp" $CPPL.blobs.db
@ -1332,6 +1405,183 @@ DoReplace() {
fi fi
} }
##### Deflate
DoDeflate() {
Damaged=0
Fail=0
# Verify DBs are here
if [ ! -e $CPPL.db ]; then
Output "No main Plex database exists to deflate. Exiting."
WriteLog "Deflate - No main database - FAIL"
Fail=1
return 1
fi
# Check size
Size=$(stat $STATFMT $STATBYTES $CPPL.db)
# Exit if not valid
if [ $Size -lt 300000 ]; then
Output "Main database is too small/truncated, deflate is not possible. Please try restoring a backup. "
WriteLog "Deflate - Main databse too small - FAIL"
Fail=1
return 1
fi
# Calculate DBsize in GB
DBSize=$(( $Size / 1000000000 + 2 ))
# Continue
DoUpdateTimestamp
#Output "Backing up databases using timestamp: $TimeStamp"
# Make a backup
if ! MakeBackups "Deflate"; then
Output "Error making backups. Cannot continue."
WriteLog "Deflate - MakeBackups - FAIL"
Fail=1
return 1
else
WriteLog "Deflate - MakeBackups - PASS"
fi
# Inform user
Output "Starting Deflate (Part 1 of 2 - Repair database table)"
Output "Estimated completion is $((DBSize / 3)) minutes but is CPU & I/O speed dependent"
Output ""
WriteLog "Deflate - Start Deflate Pass 1"
# Library and blobs successfully exported, create new
"$PLEX_SQLITE" "$TMPDIR/$CPPL.db-BACKUP-$TimeStamp" << EOF
-- Exclusive DB access
BEGIN IMMEDIATE;
-- Create new table
CREATE TABLE temp_bandwidth (
id INTEGER PRIMARY KEY,
account_id INTEGER,
device_id INTEGER,
timespan INTEGER,
at INTEGER,
lan INTEGER,
bytes INTEGER
);
-- Copy good data to new table
INSERT INTO temp_bandwidth (
account_id, device_id, timespan, at, lan, bytes
)
SELECT account_id, device_id, timespan, at, COALESCE(lan, 0), bytes
FROM statistics_bandwidth WHERE account_id not null;
-- Swap new for old
DROP TABLE statistics_bandwidth;
ALTER TABLE temp_bandwidth RENAME TO statistics_bandwidth;
-- Create Indexes
CREATE INDEX IF NOT EXISTS index_statistics_bandwidth_on_at
ON statistics_bandwidth(at);
CREATE INDEX IF NOT EXISTS index_statistics_bandwidth_on_account_id_and_timespan_and_at
ON statistics_bandwidth(account_id, timespan, at);
-- Make it so
COMMIT;
EOF
Result=$?
if [ $Result -ne 0 ]; then
Output "Error: Could not correct statistics_bandwidth table (error $Result)"
Output " Please seek additional help"
WriteLog "Deflate: Error $Result during dodeflate."
Fail=1
return $Fail
fi
# Vacuum the DB to the new DB
Output "PMS main database successfully repaired."
Output "Starting Deflate (Part 2 of 2 - Reduce size)"
WriteLog "Deflate - Start Deflate Pass 2"
"$PLEX_SQLITE" "$TMPDIR/$CPPL.db-BACKUP-$TimeStamp" \
"VACUUM main into '$TMPDIR/$CPPL.db-DEFLATE-$TimeStamp'"
Result=$?
# Good result?
if [ $Result -eq 0 ]; then
Output "PMS main database size reduced."
WriteLog "Deflate - PMS main vacuum successful."
Output "Verifying PMS main database."
if CheckDB "$TMPDIR/$CPPL.db-DEFLATE-$TimeStamp" ; then
SizeStart=$(GetSize "$CPPL.db")
SizeFinish=$(GetSize "$TMPDIR/$CPPL.db-DEFLATE-$TimeStamp")
Output "Verification complete. PMS main database is OK."
Output "PMS main database reduced from $SizeStart MB to $SizeFinish MB"
WriteLog "Deflate - Verify main database - PASS (Size: ${SizeStart} MB / ${SizeFinish} MB."
else
Output "Verification complete. PMS main database import failed."
WriteLog "Deflate - Verify main database - FAIL ($SQLerror)"
Fail=1
fi
else
Output "Error: Error code $Result while vacuuming PMS main DB file."
Output " Please seek additional help."
return $Fail
fi
# If not failed, move files normally
if [ $Fail -eq 0 ]; then
Output "Saving current main database with '-BLOATED-$TimeStamp'"
[ -e $CPPL.db ] && mv $CPPL.db "$TMPDIR/$CPPL.db-BLOATED-$TimeStamp"
#[ -e $CPPL.blobs.db ] && mv $CPPL.blobs.db "$TMPDIR/$CPPL.blobs.db-BLOATED-$TimeStamp"
Output "Making deflated database active"
WriteLog "Deflate - Making deflated database active"
mv "$TMPDIR/$CPPL.db-DEFLATE-$TimeStamp" $CPPL.db
# Ensure WAL and SHM are gone
[ -e $CPPL.blobs.db-wal ] && rm -f $CPPL.blobs.db-wal
[ -e $CPPL.blobs.db-shm ] && rm -f $CPPL.blobs.db-shm
[ -e $CPPL.db-wal ] && rm -f $CPPL.db-wal
[ -e $CPPL.db-shm ] && rm -f $CPPL.db-shm
# Set ownership on new files
chmod $Perms $CPPL.db $CPPL.blobs.db
chown $Owner $CPPL.db $CPPL.blobs.db
Result=$?
if [ $Result -ne 0 ]; then
Output "ERROR: Cannot set permissions on new databases. Error $Result"
Output " Please exit tool, keeping temp files, seek assistance."
Output " Use files: $TMPDIR/*-DEFLATE-$TimeStamp"
WriteLog "Deflate - Move files - FAIL"
Fail=1
return 1
fi
# We didn't fail, set CheckedDB status true (passed above checks)
CheckedDB=1
WriteLog "Deflate - Move files - PASS"
WriteLog "Deflate - PASS"
Output "PMS main database deflate completed."
SetLast "Deflate" "$TimeStamp"
return 0
else
rm -f "$TMPDIR/$CPPL.db-REPAIR-$TimeStamp"
rm -f "$TMPDIR/$CPPL.blobs.db-REPAIR-$TimeStamp"
Output "Deflate has failed. No files changed"
WriteLog "Deflate - $TimeStamp - FAIL"
CheckedDB=0
return 1
fi
}
##### VACUUM ##### VACUUM
DoVacuum(){ DoVacuum(){
@ -1582,7 +1832,7 @@ DoStop(){
else else
if IsRunning; then if IsRunning; then
Output "Stopping PMS." Output "Stopping PMS. (60 second max delay)"
else else
Output "PMS already stopped." Output "PMS already stopped."
return 0 return 0
@ -1599,7 +1849,7 @@ DoStop(){
Count=10 Count=10
while IsRunning && [ $Count -gt 0 ] while IsRunning && [ $Count -gt 0 ]
do do
sleep 3 sleep 6
Count=$((Count - 1)) Count=$((Count - 1))
done done
@ -1609,7 +1859,7 @@ DoStop(){
return 0 return 0
else else
WriteLog "Stop - FAIL (Timeout)" WriteLog "Stop - FAIL (Timeout)"
Output "Could not stop PMS. PMS did not shutdown within 30 second limit." Output "Could not stop PMS. PMS did not shutdown within 60 second limit."
fi fi
fi fi
return $Result return $Result
@ -1634,9 +1884,9 @@ DoUpdateTimestamp() {
# Get latest version from Github # Get latest version from Github
GetLatestRelease() { GetLatestRelease() {
Response=$(curl -s "https://api.github.com/repos/ChuckPa/PlexDBRepair/tags") Response=$(curl -sL "https://api.github.com/repos/ChuckPa/DBRepair/tags")
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
LatestVersion="$(echo "$Response" | awk -F : '{print $2}' | awk -F \, '{print $1}' | tr -d \")" LatestVersion="$(echo "$Response" | grep name | awk -F: '{print $2}' | sort -r | head -1 | tr -d \" | tr -d ' ' | tr -d ',')"
else else
LatestVersion="$Version" LatestVersion="$Version"
fi fi
@ -1649,7 +1899,7 @@ DownloadAndUpdate() {
Filename="$2" Filename="$2"
# Download the file and check if the download was successful # Download the file and check if the download was successful
if curl -s "$Url" --output "${Filename}.tmp"; then if curl -sL "$Url" --output "${Filename}.tmp"; then
# Check if the file was written to and at least 50000 bytes # Check if the file was written to and at least 50000 bytes
if [ -f "${Filename}.tmp" ]; then if [ -f "${Filename}.tmp" ]; then
if [ $(stat $STATFMT $STATBYTES "${Filename}.tmp") -gt 50000 ]; then if [ $(stat $STATFMT $STATBYTES "${Filename}.tmp") -gt 50000 ]; then
@ -1734,7 +1984,6 @@ DoPrunePhotoTranscoder() {
} }
############################################################# #############################################################
# Main utility begins here # # Main utility begins here #
############################################################# #############################################################
@ -1822,7 +2071,7 @@ Scripted=0
# Identify this host # Identify this host
if [ $ManualConfig -eq 0 ] && ! HostConfig; then if [ $ManualConfig -eq 0 ] && ! HostConfig; then
Output 'Error: Unknown host. Current supported hosts are: QNAP, Syno, Netgear, Mac, ASUSTOR, WD (OS5), Linux wkstn/svr, SNAP' Output 'Error: Unknown host. Current supported hosts are: QNAP, Syno, Netgear, Mac, ASUSTOR, WD (OS5), Linux wkstn/svr, SNAP, FreeBSD 14+'
Output ' Current supported container images: Plexinc, LinuxServer, HotIO, & BINHEX' Output ' Current supported container images: Plexinc, LinuxServer, HotIO, & BINHEX'
Output ' Manual host configuration is available in most use cases.' Output ' Manual host configuration is available in most use cases.'
Output ' ' Output ' '
@ -1907,7 +2156,7 @@ do
echo " " echo " "
echo " " echo " "
echo " Plex Media Server Database Repair Utility ($HostType)" echo " Database Repair Utility for Plex Media Server ($HostType)"
echo " Version $Version" echo " Version $Version"
echo " " echo " "
@ -1945,16 +2194,16 @@ do
echo " 10 - 'show' - Show logfile." echo " 10 - 'show' - Show logfile."
echo " 11 - 'status' - Report status of PMS (run-state and databases)." echo " 11 - 'status' - Report status of PMS (run-state and databases)."
echo " 12 - 'undo' - Undo last successful command." echo " 12 - 'undo' - Undo last successful command."
echo "" echo ""
echo " 21 - 'prune' - Remove old image files (jpeg,jpg,png) from PhotoTranscoder cache & all temp files left by PMS." echo " 21 - 'prune' - Remove old image files from PhotoTranscoder cache & all temp files left by PMS."
echo " 23 - 'deflate' - Deflate a bloated PMS main database."
[ $IgnoreErrors -eq 0 ] && echo " 42 - 'ignore' - Ignore duplicate/constraint errors." [ $IgnoreErrors -eq 0 ] && echo " 42 - 'ignore' - Ignore duplicate/constraint errors."
[ $IgnoreErrors -eq 1 ] && echo " 42 - 'honor' - Honor all database errors." [ $IgnoreErrors -eq 1 ] && echo " 42 - 'honor' - Honor all database errors."
echo "" echo ""
echo " 88 - 'update' - Check for updates." echo " 88 - 'update' - Check for updates."
echo " 99 - 'quit' - Quit immediately. Keep all temporary files." echo " 98 - 'quit' - Quit immediately. Keep all temporary files."
echo " 'exit' - Exit with cleanup options." echo " 99 - 'exit' - Exit with cleanup options."
fi fi
if [ $Scripted -eq 0 ]; then if [ $Scripted -eq 0 ]; then
@ -2010,12 +2259,8 @@ do
# Automatic of all common operations # Automatic of all common operations
2|auto*) 2|auto*)
# Get current status
RunState=0
# Check if PMS running # Check if PMS running
if IsRunning; then if IsRunning; then
RunState=1
WriteLog "Auto - FAIL - PMS runnning" WriteLog "Auto - FAIL - PMS runnning"
Output "Unable to run automatic sequence. PMS is running. Please stop PlexMediaServer." Output "Unable to run automatic sequence. PMS is running. Please stop PlexMediaServer."
continue continue
@ -2025,7 +2270,7 @@ do
if ! FreeSpaceAvailable; then if ! FreeSpaceAvailable; then
WriteLog "Auto - FAIL - Insufficient free space on $AppSuppDir" WriteLog "Auto - FAIL - Insufficient free space on $AppSuppDir"
Output "Error: Unable to run automatic sequence. Insufficient free space available on $AppSuppDir" Output "Error: Unable to run automatic sequence. Insufficient free space available on $AppSuppDir"
Output " Space needed = $SpaceNeeded MB, Space available = $SpaveAvailable MB" Output " Space needed = $SpaceNeeded MB, Space available = $SpaceAvailable MB"
continue continue
fi fi
@ -2041,6 +2286,7 @@ do
else else
WriteLog "Check - FAIL" WriteLog "Check - FAIL"
CheckedDB=0 CheckedDB=0
continue
fi fi
# Now Repair # Now Repair
@ -2098,7 +2344,6 @@ do
fi fi
;; ;;
# Vacuum # Vacuum
4|vacu*) 4|vacu*)
@ -2268,6 +2513,89 @@ do
WriteLog "Prune - PASS" WriteLog "Prune - PASS"
;; ;;
# Deflate the DB because Plex isn't doing a good job during scheduled tasks.
23|defl*)
# Check if PMS running
if IsRunning; then
WriteLog "Deflate - FAIL - PMS runnning"
Output "Unable to deflate. PMS is running. Please stop PlexMediaServer."
continue
fi
# Is there enough room to work
if ! FreeSpaceAvailable; then
WriteLog "Deflate - FAIL - Insufficient free space on $AppSuppDir"
Output "Error: Unable to deflate. Insufficient free space available on $AppSuppDir"
Output " Space needed = $SpaceNeeded MB, Space available = $SpaceAvailable MB"
continue
fi
# Start auto
Output "Check and Deflate started."
WriteLog "Deflate - START"
# Check the databases (forced)
Output ""
if CheckDatabases "Check " force ; then
WriteLog "Check - PASS"
CheckedDB=1
else
WriteLog "Check - FAIL"
CheckedDB=0
fi
# Now Deflate
Output ""
if ! DoDeflate; then
WriteLog "Deflate - FAIL"
CheckedDB=0
Output "Deflate failed. Please repair using Automatic mode."
continue
else
WriteLog "Deflate - PASS"
CheckedDB=1
fi
# All good to here
WriteLog "Deflate - PASS"
Output "Deflate successful."
Output "Recommend running "Auto" next to complete optimization of new database."
;;
# Records count
30|coun*)
Temp="$DBDIR/DBRepair.tab1"
Temp2="$DBDIR/DBRepair.tab2"
# Ensure clean
rm -f "$Temp" "$Temp2"
# Get list of tables
Tables="$("$PLEX_SQLITE" "$DBDIR/com.plexapp.plugins.library.db" .tables | sed 's/ /\n/g')"
# Separate and sort tables
for i in $Tables
do
echo $i >> "$Temp"
done
sort < "$Temp" > "$Temp2"
Tables="$(cat "$Temp2")"
# Get counts
for Table in $Tables
do
Records=$("$PLEX_SQLITE" "$DBDIR/com.plexapp.plugins.library.db" "select count(*) from $Table;")
printf "%36s %-15d\n" $Table $Records
done
;;
# Ignore/Honor errors # Ignore/Honor errors
42|igno*|hono*) 42|igno*|hono*)
@ -2278,6 +2606,13 @@ do
88|upda*) 88|upda*)
# Don't update again after restarting after updating
if [ $DBRepairRestartedAfterUpdate -eq 1 ]; then
Output "Already updated. Continuing."
WriteLog "Update - Ignore Update request after updating."
continue
fi
DoUpdate=0 DoUpdate=0
Output "Checking for update" Output "Checking for update"
GetLatestRelease GetLatestRelease
@ -2295,12 +2630,19 @@ do
if [ $DoUpdate -eq 1 ]; then if [ $DoUpdate -eq 1 ]; then
if [ -w "$ScriptWorkingDirectory" ]; then if [ -w "$ScriptWorkingDirectory" ]; then
Output "Updating from $Version to $LatestVersion" Output "Updating from $Version to $LatestVersion"
DownloadAndUpdate "https://raw.githubusercontent.com/ChuckPa/PlexDBRepair/master/DBRepair.sh" "$ScriptWorkingDirectory/$ScriptName" DownloadAndUpdate "https://raw.githubusercontent.com/ChuckPa/DBRepair/master/DBRepair.sh" "$ScriptWorkingDirectory/$ScriptName"
Result=$? Result=$?
if [ $Result -eq 0 ]; then if [ $Result -eq 0 ]; then
chmod +x "$ScriptWorkingDirectory/$ScriptName" chmod +x "$ScriptWorkingDirectory/$ScriptName"
Output "Restart to launch updated DBRepair.sh ($LatestVersion)" if [ $Scripted -eq 0 ] && ConfirmYesNo "Restart and use $LatestVersion ?" ; then
WriteLog "Update - Updated to version $LatestVersion." WriteLog "Restarting after upgrade"
Output "Restarting"
export DBRepairRestartedAfterUpdate=1
exec "$ScriptWorkingDirectory/$ScriptName" "$*"
else
Output "Restart to launch updated DBRepair.sh ($LatestVersion)"
WriteLog "Update - Updated to version $LatestVersion."
fi
exit 0 exit 0
else else
Output "Unable to download and update. Error $Result." Output "Unable to download and update. Error $Result."
@ -2314,7 +2656,7 @@ do
;; ;;
# Quit # Quit
99|quit) 98|quit)
Output "Retaining all temporary work files." Output "Retaining all temporary work files."
WriteLog "Exit - Retain temp files." WriteLog "Exit - Retain temp files."
@ -2322,7 +2664,7 @@ do
;; ;;
# Orderly Exit # Orderly Exit
exit) 99|exit)
# If forced exit set, exit and retain # If forced exit set, exit and retain
if [ $Exit -eq 1 ]; then if [ $Exit -eq 1 ]; then
@ -2363,4 +2705,4 @@ do
esac esac
done done
done done
exit 0 exit 0

View File

@ -1,7 +1,9 @@
Copyright (c) 2022, ChuckPa. Copyright (c) 2025, ChuckPa.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software for personal use only. The Software may not be modified, merged, published, distributed, sublicensed, and/or used in other form without the express written consent of the author. This software is the intellectual property of ChuckPa
and used in conjunction with Plex Media Server (which is Copyright & Trademark of Plex, Inc.)
It may not be copied, modified, or redistributed in any way without expressly written permission of ChuckPa.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

236
README.md
View File

@ -1,9 +1,9 @@
# PlexDBRepair # DBRepair (for Plex Media Server)
[![GitHub issues](https://img.shields.io/github/issues/ChuckPa/PlexDBRepair.svg?style=flat)](https://github.com/ChuckPa/PlexDBRepair/issues) [![GitHub issues](https://img.shields.io/github/issues/ChuckPa/DBRepair.svg?style=flat)](https://github.com/ChuckPa/DBRepair/issues)
[![Release](https://img.shields.io/github/release/ChuckPa/PlexDBRepair.svg?style=flat)](https://github.com/ChuckPa/PlexDBRepair/releases/latest) [![Release](https://img.shields.io/github/release/ChuckPa/DBRepair.svg?style=flat)](https://github.com/ChuckPa/DBRepair/releases/latest)
[![Download latest release](https://img.shields.io/github/downloads/ChuckPa/PlexDBRepair/latest/total.svg)](https://github.com/ChuckPa/PlexDBRepair/releases/latest) [![Download latest release](https://img.shields.io/github/downloads/ChuckPa/DBRepair/latest/total.svg)](https://github.com/ChuckPa/DBRepair/releases/latest)
[![Download total](https://img.shields.io/github/downloads/ChuckPa/PlexDBRepair/total.svg)](https://github.com/ChuckPa/PlexDBRepair/releases) [![Download total](https://img.shields.io/github/downloads/ChuckPa/DBRepair/total.svg)](https://github.com/ChuckPa/DBRepair/releases)
[![master](https://img.shields.io/badge/master-stable-green.svg?maxAge=2592000)]('') [![master](https://img.shields.io/badge/master-stable-green.svg?maxAge=2592000)]('')
![Maintenance](https://img.shields.io/badge/Maintained-Yes-green.svg) ![Maintenance](https://img.shields.io/badge/Maintained-Yes-green.svg)
@ -31,6 +31,7 @@ If sufficient privleges exist (root), and supported by the environment, the opti
``` ```
AUTO(matic) - Automatically check, repair/optimize, and reindex the databases in one step. AUTO(matic) - Automatically check, repair/optimize, and reindex the databases in one step.
CHEC(k) - Check the main and blob databases integrity CHEC(k) - Check the main and blob databases integrity
DEFL(ate) - Deflate a bloated PMS database (faulty statistics data)
EXIT - Exit the utility EXIT - Exit the utility
IGNOre/HONOr - Ignore/Honor constraint errors when IMPORTing additional data into DB. IGNOre/HONOr - Ignore/Honor constraint errors when IMPORTing additional data into DB.
IMPO(rt) - Import viewstate / watch history from another database IMPO(rt) - Import viewstate / watch history from another database
@ -51,7 +52,7 @@ If sufficient privleges exist (root), and supported by the environment, the opti
For clarity, each command's name is 'quoted'. For clarity, each command's name is 'quoted'.
``` ```
Plex Media Server Database Repair Utility (_host_configuration_name_) Database Repair Utility for Plex Media Server (_host_configuration_name_)
Version v1.09.00 Version v1.09.00
Select Select
@ -72,11 +73,12 @@ If sufficient privleges exist (root), and supported by the environment, the opti
21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache. 21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache.
22 - 'purge' - Purge (delete) all temporary files left behind by PMS & the transcoder. 22 - 'purge' - Purge (delete) all temporary files left behind by PMS & the transcoder.
23 - 'deflate' - Deflate a bloated PMS main database.
42 - 'ignore' - Ignore duplicate/constraint errors. 42 - 'ignore' - Ignore duplicate/constraint errors.
88 - 'update' - Check for updates. 88 - 'update' - Check for updates.
99 - 'quit' - Quit immediately. Keep all temporary files. 98 - 'quit' - Quit immediately. Keep all temporary files.
'exit' - Exit with cleanup options. 99 'exit' - Exit with cleanup options.
Enter command # -or- command name (4 char min) : Enter command # -or- command name (4 char min) :
@ -92,12 +94,13 @@ Enter command # -or- command name (4 char min) :
- BINHEX - BINHEX
- HOTIO - HOTIO
- Podman (libgpod) - Podman (libgpod)
4. Linux workstation & server 4. FreeBSD (14+)
5. MacOS 5. Linux workstation & server
6. Netgear (OS5 Linux-based systems) 6. MacOS
7. QNAP (QTS & QuTS) 7. Netgear (OS5 Linux-based systems)
8. Synology (DSM 6 & DSM 7) 8. QNAP (QTS & QuTS)
9. Western Digital (OS5) 9. Synology (DSM 6 & DSM 7)
10. Western Digital (OS5)
``` ```
# Installation # Installation
@ -112,10 +115,11 @@ Enter command # -or- command name (4 char min) :
-------------------+---------------------+------------------------------------------ -------------------+---------------------+------------------------------------------
Apple | Downloads | ~/Downloads Apple | Downloads | ~/Downloads
Arch Linux | N/A | Anywhere Arch Linux | N/A | Anywhere
ASUSTOR | Public | /volume1/Public ASUSTOR | Plex | /volume1/Plex
Binhex | N/A | Container root (adjacent /config) Binhex | N/A | Container root (adjacent /config)
Docker (Plex,LSIO) | N/A | Container root (adjacent /config) Docker (Plex,LSIO) | N/A | Container root (adjacent /config)
Hotio | N/A | Container root (adjacent /config) Hotio | N/A | Container root (adjacent /config)
FreeBSD (14+) | N/A | Anywhere
Kubernetes | N/A | Container root (adjacent /config) Kubernetes | N/A | Container root (adjacent /config)
Linux (wkstn/svr) | N/A | Anywhere Linux (wkstn/svr) | N/A | Anywhere
MacOS | N/A | Anywhere MacOS | N/A | Anywhere
@ -134,10 +138,10 @@ Enter command # -or- command name (4 char min) :
### General installation and usage instructions ### General installation and usage instructions
1. Open your browser to https://github.com/ChuckPa/PlexDBRepair/releases/latest 1. Open your browser to https://github.com/ChuckPa/DBRepair/releases/latest
2. Download the source code (tar.gz or ZIP) file 2. Download the source code (tar.gz or ZIP) file
3. Knowing the file name will always be of the form 'PlexDBRepair-X.Y.Z.tar.gz' 3. Knowing the file name will always be of the form 'DBRepair-X.Y.Z.tar.gz'
-- where X.Y.Z is the release number. Use the real values in place of X, Y, and Z. -- where X.Y.Z is the release number. Use the real values in place of X, Y, and Z.
4. Place the tar.gz file in the appropriate directory on the system you'll use it. 4. Place the tar.gz file in the appropriate directory on the system you'll use it.
5. Open a command line session (usually Terminal or SSH) 5. Open a command line session (usually Terminal or SSH)
@ -156,8 +160,8 @@ Enter command # -or- command name (4 char min) :
cd /volume1/Plex # use /volume1/PlexMediaServer on DSM 7 cd /volume1/Plex # use /volume1/PlexMediaServer on DSM 7
sudo bash sudo bash
tar xf PlexDBRepair-x.y.z.tar.gz tar xf DBRepair-x.y.z.tar.gz
cd PlexDBRepair-x.y.z cd DBRepair-x.y.z
chmod +x DBRepair.sh chmod +x DBRepair.sh
./DBRepair.sh ./DBRepair.sh
@ -168,8 +172,8 @@ Enter command # -or- command name (4 char min) :
sudo docker exec -it plex /bin/bash sudo docker exec -it plex /bin/bash
# extract from downloaded version file name then cd into directory # extract from downloaded version file name then cd into directory
tar xf PlexDBRepair-x.y.z.tar.gz tar xf DBRepair-x.y.z.tar.gz
cd PlexDBRepair-x.y.z cd DBRepair-x.y.z
chmod +x DBRepair.sh chmod +x DBRepair.sh
./DBRepair.sh ./DBRepair.sh
``` ```
@ -177,8 +181,8 @@ Enter command # -or- command name (4 char min) :
``` ```
sudo bash sudo bash
cd /path/to/DBRepair.tar cd /path/to/DBRepair.tar
tar xf PlexDBRepair-x.y.z.tar.gz tar xf DBRepair-x.y.z.tar.gz
cd PlexDBRepair-x.y.z cd DBRepair-x.y.z
chmod +x DBRepair.sh chmod +x DBRepair.sh
./DBRepair.sh stop auto start exit ./DBRepair.sh stop auto start exit
``` ```
@ -187,8 +191,8 @@ Enter command # -or- command name (4 char min) :
``` ```
osascript -e 'quit app "Plex Media Server"' osascript -e 'quit app "Plex Media Server"'
cd ~/Downloads cd ~/Downloads
tar xvf PlexDBRepai PlexDBRepair-x.y.z.tar.gz tar xf DBRepair-x.y.z.tar.gz
cd PlexDBRepair-x.y.z cd DBRepair-x.y.z
chmod +x DBRepair.sh chmod +x DBRepair.sh
./DBRepair.sh ./DBRepair.sh
@ -220,23 +224,22 @@ These examples
C. Database is malformed - No Backups C. Database is malformed - No Backups
1. (3) Check - Confirm either main or blobs database is damaged 1. (3) Check - Confirm either main or blobs database is damaged
2. (5) Repair - Salavage as much as possible from the databases and rebuild them into a usable database. 2. (5) Repair - Salvage as much as possible from the databases and rebuild them into a usable database.
3. (6) Reindex - Generate new indexes so PMS doesn't need to at startup 3. (6) Reindex - Generate new indexes so PMS doesn't need to at startup
4. (99) Exit 4. (99) Exit
C. Database sizes excessively large when compared to amount of media indexed (item count) D. Database sizes excessively large/bloated when compared to amount of media indexed (item count)
1. (3) Check - Make certain both databases are fully intact (repair if needed) 1. (23) Deflate - Correct the known problem with a database table and recover the wasted space.
2. (4) Vacuum - Instruct SQLite to rebuild its tables and recover unused space. 2. (2) Auto - Perform automated check, repair, and reindex of the deflated database
3. (6) Reindex - Rebuild Indexes.
4. (99) Exit 4. (99) Exit
D. User interface has become 'sluggish' as more media was added E. User interface has become 'sluggish' as more media was added
1. (3) Check - Confirm there is no database damage 1. (3) Check - Confirm there is no database damage
2. (5) Repair - You are not really repairing. You are rebuilding the DB in perfect sorted order. 2. (5) Repair - You are not really repairing. You are rebuilding the DB in perfect sorted order.
3. (6) Reindex - Rebuild Indexes. 3. (6) Reindex - Rebuild Indexes.
4. (99) Exit 4. (99) Exit
E. Undo F. Undo
Undo is a special case where you need the utility to backup ONE step. Undo is a special case where you need the utility to backup ONE step.
This is rarely needed. The only time you might want/need to backup one step is if Replace leaves you worse off This is rarely needed. The only time you might want/need to backup one step is if Replace leaves you worse off
than you were before. In this case, UNDO then Repair. Undo can only undo the single most-recent action. than you were before. In this case, UNDO then Repair. Undo can only undo the single most-recent action.
@ -266,14 +269,10 @@ Attention:
-- This is for when DB operations keep getting worse and you don't know what to do. -- This is for when DB operations keep getting worse and you don't know what to do.
"99" is an old 'Get Smart' TV series reference where agent 99 would try to save agent 86 from harm. "99" is an old 'Get Smart' TV series reference where agent 99 would try to save agent 86 from harm.
"99" was originally going to be "Quit immediately save all files" but development feedback Community feedback has resulted in:
resulted in this configuration
"Exit" is the preferred method to leave. "99" or "Exit" - Preferred way to exit and cleanup temp databases
"98" or "Quit" - Get out now without deleting the temp databases (Usually used only during unexpected failures)
"Quit" was desired instead of "99" but there are those who didn't understand the difference or references.
If community feedback wants both "Quit. save temps" and "Exit, delete temps", behavior is easily changed.
Also please be aware the script understands interactive versus scripted mode. Also please be aware the script understands interactive versus scripted mode.
@ -331,7 +330,7 @@ bash-4.4# ./DBRepair.sh
Plex Media Server Database Repair Utility (Ubuntu 20.04.6 LTS) Database Repair Utility for Plex Media Server (Ubuntu 20.04.6 LTS)
Version v1.03.01 Version v1.03.01
Select Select
@ -350,12 +349,14 @@ Select
11 - 'status' - Report status of PMS (run-state and databases). 11 - 'status' - Report status of PMS (run-state and databases).
12 - 'undo' - Undo last successful command. 12 - 'undo' - Undo last successful command.
21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache. 21 - 'prune' - Remove old image files (jpeg,jpg,png) from PhotoTranscoder cache & all temp files left by PMS.
22 - 'purge' - Remove unused temp files.
23 - 'deflate' - Deflate a bloated PMS main database.
42 - 'ignore' - Ignore duplicate/constraint errors. 42 - 'ignore' - Ignore duplicate/constraint errors.
88 - 'update' - Check for updates. 88 - 'update' - Check for updates.
99 - 'quit' - Quit immediately. Keep all temporary files. 98 - 'quit' - Quit immediately. Keep all temporary files.
'exit' - Exit with cleanup options. 99 - 'exit' - Exit with cleanup options.
Enter command # -or- command name (4 char min) : 1 Enter command # -or- command name (4 char min) : 1
@ -378,12 +379,14 @@ Select
11 - 'status' - Report status of PMS (run-state and databases). 11 - 'status' - Report status of PMS (run-state and databases).
12 - 'undo' - Undo last successful command. 12 - 'undo' - Undo last successful command.
21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache. 21 - 'prune' - Remove old image files (jpeg,jpg,png) from PhotoTranscoder cache & all temp files left by PMS.
22 - 'purge' - Remove unused temp files.
23 - 'deflate' - Deflate a bloated PMS main database.
42 - 'ignore' - Ignore duplicate/constraint errors. 42 - 'ignore' - Ignore duplicate/constraint errors.
88 - 'update' - Check for updates. 88 - 'update' - Check for updates.
99 - 'quit' - Quit immediately. Keep all temporary files. 98 - 'quit' - Quit immediately. Keep all temporary files.
'exit' - Exit with cleanup options. 99 - 'exit' - Exit with cleanup options.
Enter command # -or- command name (4 char min) : auto Enter command # -or- command name (4 char min) : auto
@ -432,12 +435,14 @@ Select
11 - 'status' - Report status of PMS (run-state and databases). 11 - 'status' - Report status of PMS (run-state and databases).
12 - 'undo' - Undo last successful command. 12 - 'undo' - Undo last successful command.
21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache. 21 - 'prune' - Remove old image files (jpeg,jpg,png) from PhotoTranscoder cache & all temp files left by PMS.
22 - 'purge' - Remove unused temp files.
23 - 'deflate' - Deflate a bloated PMS main database.
42 - 'ignore' - Ignore duplicate/constraint errors. 42 - 'ignore' - Ignore duplicate/constraint errors.
88 - 'update' - Check for updates. 88 - 'update' - Check for updates.
99 - 'quit' - Quit immediately. Keep all temporary files. 98 - 'quit' - Quit immediately. Keep all temporary files.
'exit' - Exit with cleanup options. 99 - 'exit' - Exit with cleanup options.
Enter command # -or- command name (4 char min) : start Enter command # -or- command name (4 char min) : start
@ -460,12 +465,14 @@ Select
11 - 'status' - Report status of PMS (run-state and databases). 11 - 'status' - Report status of PMS (run-state and databases).
12 - 'undo' - Undo last successful command. 12 - 'undo' - Undo last successful command.
21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache. 21 - 'prune' - Remove old image files (jpeg,jpg,png) from PhotoTranscoder cache & all temp files left by PMS.
22 - 'purge' - Remove unused temp files.
23 - 'deflate' - Deflate a bloated PMS main database.
42 - 'ignore' - Ignore duplicate/constraint errors. 42 - 'ignore' - Ignore duplicate/constraint errors.
88 - 'update' - Check for updates. 88 - 'update' - Check for updates.
99 - 'quit' - Quit immediately. Keep all temporary files. 98 - 'quit' - Quit immediately. Keep all temporary files.
'exit' - Exit with cleanup options. 99 - 'exit' - Exit with cleanup options.
Enter command # -or- command name (4 char min) : stat Enter command # -or- command name (4 char min) : stat
@ -491,12 +498,14 @@ Select
11 - 'status' - Report status of PMS (run-state and databases). 11 - 'status' - Report status of PMS (run-state and databases).
12 - 'undo' - Undo last successful command. 12 - 'undo' - Undo last successful command.
21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache. 21 - 'prune' - Remove old image files (jpeg,jpg,png) from PhotoTranscoder cache & all temp files left by PMS.
22 - 'purge' - Remove unused temp files.
23 - 'deflate' - Deflate a bloated PMS main database.
42 - 'ignore' - Ignore duplicate/constraint errors. 42 - 'ignore' - Ignore duplicate/constraint errors.
88 - 'update' - Check for updates. 88 - 'update' - Check for updates.
99 - 'quit' - Quit immediately. Keep all temporary files. 98 - 'quit' - Quit immediately. Keep all temporary files.
'exit' - Exit with cleanup options. 99 - 'exit' - Exit with cleanup options.
Enter command # -or- command name (4 char min) : exit Enter command # -or- command name (4 char min) : exit
@ -514,7 +523,7 @@ root@lizum:/sata/plex/Plex Media Server/Plug-in Support/Databases# ./DBRepair.sh
Plex Media Server Database Repair Utility (Ubuntu 20.04.5 LTS) Database Repair Utility for Plex Media Server (Ubuntu 20.04.5 LTS)
Version v1.03.01 Version v1.03.01
@ -638,6 +647,13 @@ root@lizum:/sata/plex/Plex Media Server/Plug-in Support/Databases#
Checks the integrity of the Plex main and blobs databases. Checks the integrity of the Plex main and blobs databases.
### Deflate
Repairs a known error in the PMS main database "statistics_bandwidth" table.
After repairing it, it purges all the errant data from the table (reducing DB size)
This task can take a significant amount of time. It's frequently used when the DB size is an order of magnitude above what it should be (e.g. 31 GB vs 206 MB). Reductions from 134 GB to 210 MB have been realized.
### Exit ### Exit
Exits the utility and removes all temporary database files created during processing. Exits the utility and removes all temporary database files created during processing.
@ -815,55 +831,77 @@ root@lizum:/sata/plex/Plex Media Server/Plug-in Support/Databases#
1. Remove the environment variable. 1. Remove the environment variable.
2. Run DBRepair again using "automatic". Your databases will revert to the host OS's default. 2. Run DBRepair again using "automatic". Your databases will revert to the host OS's default.
### Usage: (Linux example shown) ### Usage: (QNAP example shown)
``` ```
# export DBREPAIR_PAGESIZE=65534 # export DBREPAIR_PAGESIZE=65534
# ./DBRepair.sh stop auto start exit # ./DBRepair.sh stop deflate auto start exit
Plex Media Server Database Repair Utility (Ubuntu 22.04.3 LTS) Database Repair Utility for Plex Media Server (QNAP)
Version v1.03.01 Version v1.12.00
[2024-01-14 17.25.35] Stopping PMS. [2025-10-21 16.54.00] PMS already stopped.
[2024-01-14 17.25.35] Stopped PMS.
[2024-01-14 17.25.35] Automatic Check,Repair,Index started. [2025-10-21 16.54.00] Check and Deflate started.
[2024-01-14 17.25.35] [2025-10-21 16.54.00]
[2024-01-14 17.25.35] Checking the PMS databases [2025-10-21 16.54.00] Checking the PMS databases
[2024-01-14 17.25.48] Check complete. PMS main database is OK. [2025-10-21 16.54.19] Check complete. PMS main database is OK.
[2024-01-14 17.25.48] Check complete. PMS blobs database is OK. [2025-10-21 16.54.21] Check complete. PMS blobs database is OK.
[2024-01-14 17.25.48] [2025-10-21 16.54.21]
[2024-01-14 17.25.48] Exporting current databases using timestamp: 2024-01-14_17.25.35 [2025-10-21 16.54.21] Backup current databases with '-BACKUP-2025-10-21_16.54.21' timestamp.
[2024-01-14 17.25.48] Exporting Main DB [2025-10-21 16.56.29] Starting Deflate (Part 1 of 2 - Repair database table)
[2024-01-14 17.25.59] Exporting Blobs DB [2025-10-21 16.56.29] Estimated completion is approx 6 minutes but is CPU & I/O speed dependent
[2024-01-14 17.26.00] Successfully exported the main and blobs databases. Proceeding to import into new databases. [2025-10-21 16.56.29]
[2024-01-14 17.26.00] Importing Main DB. [2025-10-21 16.56.30] PMS main database successfully repaired.
[2024-01-14 17.26.00] Setting Plex SQLite page size (65536) [2025-10-21 16.56.30] Starting Deflate (Part 2 of 2 - Reduce size)
[2024-01-14 17.26.29] Importing Blobs DB. [2025-10-21 16.56.35] PMS main database size reduced.
[2024-01-14 17.26.29] Setting Plex SQLite page size (65536) [2025-10-21 16.56.35] Verifying PMS main database.
[2024-01-14 17.26.30] Successfully imported databases. [2025-10-21 16.56.50] Verification complete. PMS main database is OK.
[2024-01-14 17.26.30] Verifying databases integrity after importing. [2025-10-21 16.56.50] PMS main database reduced from 31586 MB to 206 MB
[2024-01-14 17.27.43] Verification complete. PMS main database is OK. [2025-10-21 16.56.51] Saving current main database with '-BLOATED-2025-10-21_16.54.21'
[2024-01-14 17.27.43] Verification complete. PMS blobs database is OK. [2025-10-21 16.56.51] Making deflated database active
[2024-01-14 17.27.43] Saving current databases with '-BACKUP-2024-01-14_17.25.35' [2025-10-21 16.56.51] PMS main database deflate completed.
[2024-01-14 17.27.43] Making repaired databases active [2025-10-21 16.56.51] Deflate successful.
[2024-01-14 17.27.43] Repair complete. Please check your library settings and contents for completeness. [2025-10-21 16.56.51] Recommend running Auto next to complete optimization of new database.
[2024-01-14 17.27.43] Recommend: Scan Files and Refresh all metadata for each library section.
[2024-01-14 17.27.43]
[2024-01-14 17.27.43] Backing up of databases
[2024-01-14 17.27.43] Backup current databases with '-BACKUP-2024-01-14_17.27.43' timestamp.
[2024-01-14 17.27.44] Reindexing main database
[2024-01-14 17.28.08] Reindexing main database successful.
[2024-01-14 17.28.08] Reindexing blobs database
[2024-01-14 17.28.08] Reindexing blobs database successful.
[2024-01-14 17.28.08] Reindex complete.
[2024-01-14 17.28.08] Automatic Check, Repair/optimize, & Index successful.
[2024-01-14 17.28.08] Starting PMS. [2025-10-21 16.56.51] Automatic Check,Repair,Index started.
[2024-01-14 17.28.08] Started PMS [2025-10-21 16.56.51]
[2025-10-21 16.56.51] Checking the PMS databases
[2025-10-21 16.57.04] Check complete. PMS main database is OK.
[2025-10-21 16.57.05] Check complete. PMS blobs database is OK.
[2025-10-21 16.57.05]
[2025-10-21 16.57.05] Exporting current databases using timestamp: 2025-10-21_16.56.51
[2025-10-21 16.57.05] Exporting Main DB
[2025-10-21 16.57.24] Exporting Blobs DB
[2025-10-21 16.59.18] Successfully exported the main and blobs databases.
[2025-10-21 16.59.18] Start importing into new databases.
[2025-10-21 16.59.18] Importing Main DB.
[2025-10-21 16.59.18] Setting Plex SQLite page size (65536)
[2025-10-21 17.00.19] Importing Blobs DB.
[2025-10-21 17.00.19] Setting Plex SQLite page size (65536)
[2025-10-21 17.00.32] Successfully imported databases.
[2025-10-21 17.00.32] Verifying databases integrity after importing.
[2025-10-21 17.01.59] Verification complete. PMS main database is OK.
[2025-10-21 17.02.01] Verification complete. PMS blobs database is OK.
[2025-10-21 17.02.01] Saving current databases with '-BACKUP-2025-10-21_16.56.51'
[2025-10-21 17.02.01] Making repaired databases active
[2025-10-21 17.02.01] Repair complete. Please check your library settings and contents for completeness.
[2025-10-21 17.02.01] Recommend: Scan Files and Refresh all metadata for each library section.
[2025-10-21 17.02.01]
[2025-10-21 17.02.01] Backing up of databases
[2025-10-21 17.02.01] Backup current databases with '-BACKUP-2025-10-21_17.02.01' timestamp.
[2025-10-21 17.02.02] Reindexing main database
[2025-10-21 17.02.13] Reindexing main database successful.
[2025-10-21 17.02.13] Reindexing blobs database
[2025-10-21 17.02.14] Reindexing blobs database successful.
[2025-10-21 17.02.14] Reindex complete.
[2025-10-21 17.02.14] Automatic Check, Repair/optimize, & Index successful.
[2025-10-21 17.02.14] Starting PMS.
[2025-10-21 17.02.14] Started PMS
# #
``` ```
@ -913,7 +951,7 @@ root@Jasper:/mnt/user/appdata/PlexMediaServer# /tmp/DBRepair.sh --databases /mnt
Plex Media Server Database Repair Utility (User Defined) Database Repair Utility for Plex Media Server (User Defined)
Version v1.09.00 Version v1.09.00
PlexSQLite = '/var/lib/docker/btrfs/subvolumes/4bb78fb70589d4d2ba56754f4d6bc0edd4cdaa8eab7986943767e09a66cefd19/usr/lib/plexmediaserver//Plex SQLite' PlexSQLite = '/var/lib/docker/btrfs/subvolumes/4bb78fb70589d4d2ba56754f4d6bc0edd4cdaa8eab7986943767e09a66cefd19/usr/lib/plexmediaserver//Plex SQLite'
@ -937,12 +975,14 @@ Select
21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache older than specific age. 21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache older than specific age.
22 - 'purge' - Purge (remove) all temporary files left by PMS & Transcoder in Temp Dir.' 22 - 'purge' - Purge (remove) all temporary files left by PMS & Transcoder in Temp Dir.'
23 - 'deflate' - Deflate a bloated PMS main database.
42 - 'ignore' - Ignore duplicate/constraint errors. 42 - 'ignore' - Ignore duplicate/constraint errors.
88 - 'update' - Check for updates. 88 - 'update' - Check for updates.
99 - 'quit' - Quit immediately. Keep all temporary files. 98 - 'quit' - Quit immediately. Keep all temporary files.
'exit' - Exit with cleanup options. 99 - 'exit' - Exit with cleanup options.
Enter command # -or- command name (4 char min) : Enter command # -or- command name (4 char min) :
``` ```

View File

@ -1,13 +1,69 @@
# PlexDBRepair # DBRepair
[![GitHub issues](https://img.shields.io/github/issues/ChuckPa/PlexDBRepair.svg?style=flat)](https://github.com/ChuckPa/PlexDBRepair/issues) [![GitHub issues](https://img.shields.io/github/issues/ChuckPa/DBRepair.svg?style=flat)](https://github.com/ChuckPa/DBRepair/issues)
[![Release](https://img.shields.io/github/release/ChuckPa/PlexDBRepair.svg?style=flat)](https://github.com/ChuckPa/PlexDBRepair/releases/latest) [![Release](https://img.shields.io/github/release/ChuckPa/DBRepair.svg?style=flat)](https://github.com/ChuckPa/DBRepair/releases/latest)
[![Download latest release](https://img.shields.io/github/downloads/ChuckPa/PlexDBRepair/latest/total.svg)](https://github.com/ChuckPa/PlexDBRepair/releases/latest) [![Download latest release](https://img.shields.io/github/downloads/ChuckPa/DBRepair/latest/total.svg)](https://github.com/ChuckPa/DBRepair/releases/latest)
[![Download total](https://img.shields.io/github/downloads/ChuckPa/PlexDBRepair/total.svg)](https://github.com/ChuckPa/PlexDBRepair/releases) [![Download total](https://img.shields.io/github/downloads/ChuckPa/DBRepair/total.svg)](https://github.com/ChuckPa/DBRepair/releases)
[![master](https://img.shields.io/badge/master-stable-green.svg?maxAge=2592000)]('') [![master](https://img.shields.io/badge/master-stable-green.svg?maxAge=2592000)]('')
![Maintenance](https://img.shields.io/badge/Maintained-Yes-green.svg) ![Maintenance](https://img.shields.io/badge/Maintained-Yes-green.svg)
# Release Info: # Release Info:
v1.12.00
1. Deflate capability - Deflate a bloated PMS main database and retain bandwidth statistics.
Recommended usage: "Deflate" followed by "Auto" to optimize the DB after reduction.
- Method changed to reconstruction of bandwidth table versus selective copy.
This results in correct operation of bandwidth statistics functionality
as well as significantly improved performance.
2. ASUSTOR - Documentation error README.md corrected
v1.11.09
1. HotIO Paths - Path defined for Cache dir (and PhotoTranscoder) incorrect. Fixed.
v1.11.08
1. Restart after update - Sometimes restart after update would reference the wrong path. Fixed.
v1.11.07
1. Add support FreeBSD - Add support for FreeBSD (14+)
Thanks to @cdf-eagles for the work.
v1.11.06
1. Restart after update - Correct missing variable initialization.
v1.11.05
1. Remove menu option - Deflate menu option wasn't previously removed. Now removed.
v1.11.04
1. Binhex start/stop - Add support for stopping and starting PMS in Binhex containers.
2. Restart after update - Add option to restart after live updating.
3. Remove temp Deflate - Remove deflate function as of PMS 1.41.8 availability
v1.11.01 - v1.11.03 - Temporary versions to assist PMS database bloat issue.
v1.11.00
1. Rename Utility - Rename this tool to be compliant with Plex inc. Trademark Policy.
Update all documentation
Update Github repository
v1.10.06
1. Update tags - When updating, DBRepair would not format cleanly. This update corrects that formatting.
It would often show the tags for multiple previous versions. This is undesirable.
v1.10.05
1. DB Cleanup - Temporary assist with PMS database cleanups
2. Record Count report - Report the number of records in each main DB table. (Monitoring growth)
v1.10.03 v1.10.03
1. LC_ALL - When LC_ALL="", set LC_ALL=C (MacOS now needs this) 1. LC_ALL - When LC_ALL="", set LC_ALL=C (MacOS now needs this)
@ -262,7 +318,7 @@ These type changes can only be performed by PMS.
For clarity, each command's name is 'quoted'. For clarity, each command's name is 'quoted'.
Plex Media Server Database Repair Utility (_host_configuration_name_) Database Repair Utility for Plex Media Server (_host_configuration_name_)
Version v1.0.0 Version v1.0.0
Select Select
@ -327,10 +383,10 @@ These type changes can only be performed by PMS.
### General installation and usage instructions ### General installation and usage instructions
1. Open your browser to https://github.com/ChuckPa/PlexDBRepair/releases/latest 1. Open your browser to https://github.com/ChuckPa/DBRepair/releases/latest
2. Download the source code (tar.gz or ZIP) file 2. Download the source code (tar.gz or ZIP) file
3. Knowing the file name will always be of the form 'PlexDBRepair-X.Y.Z.tar.gz' 3. Knowing the file name will always be of the form 'DBRepair-X.Y.Z.tar.gz'
-- where X.Y.Z is the release number. Use the real values in place of X, Y, and Z. -- where X.Y.Z is the release number. Use the real values in place of X, Y, and Z.
4. Place the tar.gz file in the appropriate directory on the system you'll use it. 4. Place the tar.gz file in the appropriate directory on the system you'll use it.
5. Open a command line session (usually Terminal or SSH) 5. Open a command line session (usually Terminal or SSH)
@ -347,8 +403,8 @@ These type changes can only be performed by PMS.
cd /volume1/Plex cd /volume1/Plex
sudo bash sudo bash
tar xf PlexDBRepair-x.y.z.tar.gz tar xf DBRepair-x.y.z.tar.gz
cd PlexDBRepair-x.y.z cd DBRepair-x.y.z
chmod +x DBRepair.sh chmod +x DBRepair.sh
./DBRepair.sh ./DBRepair.sh
@ -360,8 +416,8 @@ These type changes can only be performed by PMS.
sudo docker exec -it plex /bin/bash sudo docker exec -it plex /bin/bash
# extract from downloaded version file name then cd into directory # extract from downloaded version file name then cd into directory
tar xf PlexDBRepair-1.0.0.tar.gz tar xf DBRepair-1.0.0.tar.gz
cd PlexDBRepair-1.0.0 cd DBRepair-1.0.0
chmod +x DBRepair.sh chmod +x DBRepair.sh
./DBRepair.sh ./DBRepair.sh
``` ```
@ -369,8 +425,8 @@ These type changes can only be performed by PMS.
``` ```
sudo bash sudo bash
cd /path/to/DBRepair.tar cd /path/to/DBRepair.tar
tar xf PlexDBRepair-1.0.0.tar.gz tar xf DBRepair-1.0.0.tar.gz
cd PlexDBRepair-1.0.0 cd DBRepair-1.0.0
chmod +x DBRepair.sh chmod +x DBRepair.sh
./DBRepair.sh stop auto start exit ./DBRepair.sh stop auto start exit
``` ```
@ -379,8 +435,8 @@ These type changes can only be performed by PMS.
``` ```
osascript -e 'quit app "Plex Media Server"' osascript -e 'quit app "Plex Media Server"'
cd ~/Downloads cd ~/Downloads
tar xvf PlexDBRepai PlexDBRepair-1.0.0.tar.gz tar xvf PlexDBRepai DBRepair-1.0.0.tar.gz
cd PlexDBRepai PlexDBRepair-1.0.0 cd PlexDBRepai DBRepair-1.0.0
chmod +x DBRepair.sh chmod +x DBRepair.sh
./DBRepair.sh ./DBRepair.sh
@ -485,7 +541,7 @@ bash-4.4# ./DBRepair.sh
Plex Media Server Database Repair Utility (Synology (DSM 7)) Database Repair Utility for Plex Media Server (Synology (DSM 7))
Version v1.0.0 Version v1.0.0
@ -638,7 +694,7 @@ root@lizum:/sata/plex/Plex Media Server/Plug-in Support/Databases# ./DBRepair.sh
Plex Media Server Database Repair Utility (Ubuntu 20.04.5 LTS) Database Repair Utility for Plex Media Server (Ubuntu 20.04.5 LTS)
Version v1.0.0 Version v1.0.0

View File

@ -1,5 +1,5 @@
@echo off @echo off
REM PlexDBRepair.bat - Database maintenance / rebuild tool for Windows. REM DBRepair.bat - Database maintenance / rebuild tool for Windows.
REM REM
REM This tool currently works as a "full shot" service. REM This tool currently works as a "full shot" service.
REM - everything is done without need to interact. REM - everything is done without need to interact.
@ -12,7 +12,7 @@ setlocal enabledelayedexpansion
echo. echo.
echo NOTE: This script is being replaced with the PowerShell script DBRepair-Windows.ps1, echo NOTE: This script is being replaced with the PowerShell script DBRepair-Windows.ps1,
echo which aims to better emulate DBRepair.sh (more options, interative mode, etc). echo which aims to better emulate DBRepair.sh (more options, interactive mode, etc).
echo Consider moving over to the new script. echo Consider moving over to the new script.
echo. echo.
@ -78,13 +78,13 @@ set "TmpFile=%DBtmp%\results.tmp"
REM Time now. REM Time now.
echo %time% -- ====== Session begins. (%date%) ====== echo %time% -- ====== Session begins. (%date%) ======
echo %time% -- ====== Session begins. (%date%) ====== >> "%PlexData%\PlexDBRepair.log" echo %time% -- ====== Session begins. (%date%) ====== >> "%PlexData%\DBRepair.log"
REM Make certain Plex is NOT running. REM Make certain Plex is NOT running.
tasklist | find /I "Plex Media Server.exe" >NUL tasklist | find /I "Plex Media Server.exe" >NUL
if %ERRORLEVEL%==0 ( if %ERRORLEVEL%==0 (
echo %time% -- Plex is running. Please stop Plex Media Server and try again. echo %time% -- Plex is running. Please stop Plex Media Server and try again.
echo %time% -- Plex is running. Please stop Plex Media Server and try again. >> "%PlexData%\PlexDBRepair.log" echo %time% -- Plex is running. Please stop Plex Media Server and try again. >> "%PlexData%\DBRepair.log"
exit /B 1 exit /B 1
) )
@ -94,8 +94,12 @@ cd "%PlexData%"
md "%PlexData%\dbtmp" 2>NUL md "%PlexData%\dbtmp" 2>NUL
del "%TmpFile%" 2>NUL del "%TmpFile%" 2>NUL
echo %time% -- Performing DB cleanup tasks
echo %time% -- Performing DB cleanup tasks >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db" "DELETE FROM statistics_bandwidth WHERE account_id IS NULL;"
echo %time% -- Exporting Main DB echo %time% -- Exporting Main DB
echo %time% -- Exporting Main DB >> "%PlexData%\PlexDBRepair.log" echo %time% -- Exporting Main DB >> "%PlexData%\DBRepair.log"
echo .dump | "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db" > "%DBtmp%\library.sql_%TimeStamp%" echo .dump | "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db" > "%DBtmp%\library.sql_%TimeStamp%"
if not %ERRORLEVEL%==0 ( if not %ERRORLEVEL%==0 (
echo %time% -- ERROR: Cannot export Main DB. Aborting. echo %time% -- ERROR: Cannot export Main DB. Aborting.
@ -103,7 +107,7 @@ if not %ERRORLEVEL%==0 (
) )
echo %time% -- Exporting Blobs DB echo %time% -- Exporting Blobs DB
echo %time% -- Exporting Blobs DB >> "%PlexData%\PlexDBRepair.log" echo %time% -- Exporting Blobs DB >> "%PlexData%\DBRepair.log"
echo .dump | "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db" > "%DBtmp%\blobs.sql_%TimeStamp%" echo .dump | "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db" > "%DBtmp%\blobs.sql_%TimeStamp%"
if not %ERRORLEVEL%==0 ( if not %ERRORLEVEL%==0 (
echo %time% -- ERROR: Cannot export Blobs DB. Aborting. echo %time% -- ERROR: Cannot export Blobs DB. Aborting.
@ -111,75 +115,75 @@ if not %ERRORLEVEL%==0 (
REM Now create new databases from SQL statements REM Now create new databases from SQL statements
echo %time% -- Exporting Complete. echo %time% -- Exporting Complete.
echo %time% -- Exporting Complete. >> "%PlexData%\PlexDBRepair.log" echo %time% -- Exporting Complete. >> "%PlexData%\DBRepair.log"
echo %time% -- Creating Main DB echo %time% -- Creating Main DB
echo %time% -- Creating Main DB >> "%PlexData%\PlexDBRepair.log" echo %time% -- Creating Main DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" < "%DBtmp%\library.sql_%TimeStamp%" "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" < "%DBtmp%\library.sql_%TimeStamp%"
if not %ERRORLEVEL%==0 ( if not %ERRORLEVEL%==0 (
echo %time% -- ERROR: Cannot create Main DB. Aborting. echo %time% -- ERROR: Cannot create Main DB. Aborting.
echo %time% -- ERROR: Cannot create Main DB. Aborting. >> "%PlexData%\PlexDBRepair.log" echo %time% -- ERROR: Cannot create Main DB. Aborting. >> "%PlexData%\DBRepair.log"
exit /b 3 exit /b 3
) )
echo %time% -- Verifying Main DB echo %time% -- Verifying Main DB
echo %time% -- Verifying Main DB >> "%PlexData%\PlexDBRepair.log" echo %time% -- Verifying Main DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" "PRAGMA integrity_check(1)" >"%TmpFile%" "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" "PRAGMA integrity_check(1)" >"%TmpFile%"
set /p Result= < "%TmpFile%" set /p Result= < "%TmpFile%"
del "%TmpFile%" del "%TmpFile%"
echo %time% -- Main DB verification check is: %Result% echo %time% -- Main DB verification check is: %Result%
echo %time% -- Main DB verification check is: %Result% >> "%PlexData%\PlexDBRepair.log" echo %time% -- Main DB verification check is: %Result% >> "%PlexData%\DBRepair.log"
if not "%Result%" == "ok" ( if not "%Result%" == "ok" (
echo %time% -- ERROR: Main DB verificaion failed. Exiting. echo %time% -- ERROR: Main DB verification failed. Exiting.
echo %time% -- ERROR: Main DB verificaion failed. Exiting. >> "%PlexData%\PlexDBRepair.log" echo %time% -- ERROR: Main DB verification failed. Exiting. >> "%PlexData%\DBRepair.log"
exit /B 4 exit /B 4
) )
echo %time% -- Main DB verification successful. echo %time% -- Main DB verification successful.
echo %time% -- Main DB verification successful. >> "%PlexData%\PlexDBRepair.log" echo %time% -- Main DB verification successful. >> "%PlexData%\DBRepair.log"
echo %time% -- Creating Blobs DB echo %time% -- Creating Blobs DB
echo %time% -- Creating Blobs DB >> "%PlexData%\PlexDBRepair.log" echo %time% -- Creating Blobs DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" < "%DBtmp%\blobs.sql_%TimeStamp%" "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" < "%DBtmp%\blobs.sql_%TimeStamp%"
if not %ERRORLEVEL%==0 ( if not %ERRORLEVEL%==0 (
echo %time% -- ERROR: Cannot create Blobs DB. Aborting. echo %time% -- ERROR: Cannot create Blobs DB. Aborting.
echo %time% -- ERROR: Cannot create Blobs DB. Aborting. >> "%PlexData%\PlexDBRepair.log" echo %time% -- ERROR: Cannot create Blobs DB. Aborting. >> "%PlexData%\DBRepair.log"
exit /b 5 exit /b 5
) )
echo %time% -- Verifying Blobs DB echo %time% -- Verifying Blobs DB
echo %time% -- Verifying Blobs DB >> "%PlexData%\PlexDBRepair.log" echo %time% -- Verifying Blobs DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" "PRAGMA integrity_check(1)" > "%TmpFile%" "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" "PRAGMA integrity_check(1)" > "%TmpFile%"
set /p Result= < "%TmpFile%" set /p Result= < "%TmpFile%"
del "%TmpFile%" del "%TmpFile%"
echo %time% -- Blobs DB verification check is: %Result% echo %time% -- Blobs DB verification check is: %Result%
echo %time% -- Blobs DB verification check is: %Result% >> "%PlexData%\PlexDBRepair.log" echo %time% -- Blobs DB verification check is: %Result% >> "%PlexData%\DBRepair.log"
if not "%Result%" == "ok" ( if not "%Result%" == "ok" (
echo %time% -- ERROR: Blobs DB verificaion failed. Exiting. echo %time% -- ERROR: Blobs DB verification failed. Exiting.
echo %time% -- ERROR: Blobs DB verificaion failed. Exiting. >> "%PlexData%\PlexDBRepair.log" echo %time% -- ERROR: Blobs DB verification failed. Exiting. >> "%PlexData%\DBRepair.log"
exit /B 6 exit /B 6
) )
echo %time% -- Blobs DB verification successful. echo %time% -- Blobs DB verification successful.
echo %time% -- Blobs DB verification successful. >> "%PlexData%\PlexDBRepair.log" echo %time% -- Blobs DB verification successful. >> "%PlexData%\DBRepair.log"
echo %time% -- Import and verification complete. echo %time% -- Import and verification complete.
echo %time% -- Import and verification complete. >> "%PlexData%\PlexDBRepair.log" echo %time% -- Import and verification complete. >> "%PlexData%\DBRepair.log"
REM Import complete, now reindex REM Import complete, now reindex
echo %time% -- Reindexing Main DB echo %time% -- Reindexing Main DB
echo %time% -- Reindexing Main DB >> "%PlexData%\PlexDBRepair.log" echo %time% -- Reindexing Main DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" "REINDEX;" "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" "REINDEX;"
echo %time% -- Reindexing Blobs DB echo %time% -- Reindexing Blobs DB
echo %time% -- Reindexing Blobs DB >> "%PlexData%\PlexDBRepair.log" echo %time% -- Reindexing Blobs DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" "REINDEX;" "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" "REINDEX;"
REM Index complete, make active REM Index complete, make active
echo %time% -- Reindexing complete. echo %time% -- Reindexing complete.
echo %time% -- Reindexing complete. >> "%PlexData%\PlexDBRepair.log" echo %time% -- Reindexing complete. >> "%PlexData%\DBRepair.log"
echo %time% -- Moving current DBs to DBTMP and making new databases active echo %time% -- Moving current DBs to DBTMP and making new databases active
echo %time% -- Moving current DBs to DBTMP and making new databases active >> "%PlexData%\PlexDBRepair.log" echo %time% -- Moving current DBs to DBTMP and making new databases active >> "%PlexData%\DBRepair.log"
move "%PlexData%\com.plexapp.plugins.library.db" "%PlexData%\dbtmp\com.plexapp.plugins.library.db_%TimeStamp%" move "%PlexData%\com.plexapp.plugins.library.db" "%PlexData%\dbtmp\com.plexapp.plugins.library.db_%TimeStamp%"
move "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" "%PlexData%\com.plexapp.plugins.library.db" move "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" "%PlexData%\com.plexapp.plugins.library.db"
@ -188,9 +192,9 @@ move "%PlexData%\com.plexapp.plugins.library.blobs.db" "%PlexData%\d
move "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" "%PlexData%\com.plexapp.plugins.library.blobs.db" move "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" "%PlexData%\com.plexapp.plugins.library.blobs.db"
echo %time% -- Database repair/rebuild/reindex completed. echo %time% -- Database repair/rebuild/reindex completed.
echo %time% -- Database repair/rebuild/reindex completed. >> "%PlexData%\PlexDBRepair.log" echo %time% -- Database repair/rebuild/reindex completed. >> "%PlexData%\DBRepair.log"
echo %time% -- ====== Session completed. ====== echo %time% -- ====== Session completed. ======
echo %time% -- ====== Session completed. ====== >> "%PlexData%\PlexDBRepair.log" echo %time% -- ====== Session completed. ====== >> "%PlexData%\DBRepair.log"
exit /b exit /b
@ -201,5 +205,5 @@ REM Output - Write text to the console and the log file
:Output :Output
echo %time% %~1 echo %time% %~1
echo %time% %~1 >> "%PlexData%\PlexDBRepair.log" echo %time% %~1 >> "%PlexData%\DBRepair.log"
exit /B exit /B

View File

@ -1,12 +1,12 @@
######################################################################### #########################################################################
# Plex Media Server database check and repair utility script. # # Database check and repair utility script for Plex Media Server #
# # # #
######################################################################### #########################################################################
$PlexDBRepairVersion = 'v1.00.01' $DBRepairVersion = 'v1.01.02'
class PlexDBRepair { class DBRepair {
[PlexDBRepairOptions] $Options [DBRepairOptions] $Options
[string] $PlexDBDir # Path to Plex's Databases directory [string] $PlexDBDir # Path to Plex's Databases directory
[string] $PlexCache # Path to the PhotoTranscoder directory [string] $PlexCache # Path to the PhotoTranscoder directory
@ -14,10 +14,15 @@ class PlexDBRepair {
[string] $Timestamp # Timestamp used for temporary database files [string] $Timestamp # Timestamp used for temporary database files
[string] $LogFile # Path of our log file [string] $LogFile # Path of our log file
[string] $Version # Current script version [string] $Version # Current script version
[string] $Stage # Current stage of the script (e.g. "Auto", "Prune", etc.)
[bool] $IsError # Whether we're currently in an error state
[string] $MainDB = "com.plexapp.plugins.library.db"
[string] $BlobsDB = "com.plexapp.plugins.library.blobs.db"
PlexDBRepair($Arguments, $Version) { DBRepair($Arguments, $Version) {
$this.Options = [PlexDBRepairOptions]::new() $this.Options = [DBRepairOptions]::new()
$this.Version = $Version $this.Version = $Version
$this.IsError = $false
$Commands = $this.PreprocessArgs($Arguments) $Commands = $this.PreprocessArgs($Arguments)
if ($null -eq $Commands) { if ($null -eq $Commands) {
return return
@ -40,8 +45,8 @@ class PlexDBRepair {
} }
Write-Host "`n" Write-Host "`n"
Write-Host " Plex Media Server Database Repair Utility (Windows $($OS.Major), Build $($OS.Build))" Write-Host " Database Repair Utility for Plex Media Server (Windows $($OS.Major), Build $($OS.Build))"
Write-Host " Version $($this.Version) " Write-Host " Version $($this.Version) "
Write-Host Write-Host
} }
@ -83,8 +88,8 @@ class PlexDBRepair {
Write-Host " 42 - 'ignore' - Ignore duplicate/constraint errors." Write-Host " 42 - 'ignore' - Ignore duplicate/constraint errors."
} }
Write-Host Write-Host
Write-Host " 99 - 'quit' - Quit immediately. Keep all temporary files." Write-Host " 98 - 'quit' - Quit immediately. Keep all temporary files."
Write-Host " 'exit' - Exit with cleanup options." Write-Host " 99 'exit' - Exit with cleanup options."
Write-Host Write-Host
Write-Host " 'menu x' - Show this menu in interactive mode, where x is on/off/yes/no" Write-Host " 'menu x' - Show this menu in interactive mode, where x is on/off/yes/no"
} }
@ -136,7 +141,7 @@ class PlexDBRepair {
$AppData = $this.GetAppDataDir() $AppData = $this.GetAppDataDir()
$Success = $this.GetPlexDBDir($AppData) -and $this.GetPlexSQL() -and $this.GetPhotoTranscoderDir($AppData) $Success = $this.GetPlexDBDir($AppData) -and $this.GetPlexSQL() -and $this.GetPhotoTranscoderDir($AppData)
if ($Success) { if ($Success) {
$this.LogFile = Join-Path $this.PlexDBDir -ChildPath "PlexDBRepair.log" $this.LogFile = Join-Path $this.PlexDBDir -ChildPath "DBRepair.log"
} }
return $Success return $Success
@ -187,9 +192,15 @@ class PlexDBRepair {
switch -Regex ($Choice) { switch -Regex ($Choice) {
"^(1|stop)$" { $this.DoStop() } "^(1|stop)$" { $this.DoStop() }
"^(2|autom?a?t?i?c?)$" { $this.RunAutomaticDatabaseMaintenance() } "^(2|autom?a?t?i?c?)$" {
$this.SetStage("Auto")
$this.IsError = !$this.RunAutomaticDatabaseMaintenance()
}
"^(7|start?)$" { $this.StartPMS() } "^(7|start?)$" { $this.StartPMS() }
"^(21|(prune?|remov?e?))$" { $this.PrunePhotoTranscoderCache() } "^(21|(prune?|remov?e?))$" {
$this.SetStage("Prune")
$this.PrunePhotoTranscoderCache()
}
"^(42|ignor?e?|honor?)$" { "^(42|ignor?e?|honor?)$" {
if (($this.Options.IgnoreErrors -and ($Choice[0] -eq 'i')) -or (!$this.Options.IgnoreErrors -and ($Choice[0] -eq 'h'))) { if (($this.Options.IgnoreErrors -and ($Choice[0] -eq 'i')) -or (!$this.Options.IgnoreErrors -and ($Choice[0] -eq 'h'))) {
Write-Host "Honor/Ignore setting unchanged." Write-Host "Honor/Ignore setting unchanged."
@ -200,19 +211,27 @@ class PlexDBRepair {
$msg = if ($this.Options.IgnoreErrors) { "Ignoring database errors." } else { "Honoring database errors." } $msg = if ($this.Options.IgnoreErrors) { "Ignoring database errors." } else { "Honoring database errors." }
$this.WriteOutputLog($msg) $this.WriteOutputLog($msg)
} }
"^(99|quit)$" { "^(98|quit)$" {
$this.Output("Retaining all remporary work files.") $this.Output("Retaining all temporary work files.")
$this.WriteLog("Exit - Retain temp files.") $this.WriteLog("Exit - Retain temp files.")
$this.WriteEnd() $this.WriteEnd()
return return
} }
"^exit$" { "^(99|exit)$" {
if ($EOFExit) { if ($EOFExit) {
$this.Output("Unexpected exit command. Keeping all temporary work files.") $this.Output("Unexpected exit command. Keeping all temporary work files.")
$this.WriteLog("EOFExit - Retain temp files.") $this.WriteLog("EOFExit - Retain temp files.")
return return
} }
# If our last DB operation failed, we don't want to automatically delete
# temporary files when in scripted mode.
if ($this.IsError -and $this.Options.Scripted) {
$this.Output("Exiting with errors. Keeping all temporary work files.")
$this.WriteLog("Exit - Retain temp files.")
return
}
$this.CleanDBTemp(!$this.Options.Scripted) $this.CleanDBTemp(!$this.Options.Scripted)
$this.WriteEnd() $this.WriteEnd()
return return
@ -242,13 +261,12 @@ class PlexDBRepair {
[void] DoStop() { [void] DoStop() {
$this.WriteLog("Stop - START") $this.WriteLog("Stop - START")
$PMS = $this.GetPMS() $PMS = $this.GetPMS()
if ($PMS) { if ($null -eq $PMS) {
$this.Output("Stopping PMS.")
} else {
$this.Output("PMS already stopped.") $this.Output("PMS already stopped.")
return return
} }
$this.Output("Stopping PMS.")
# Plex doesn't respond to CloseMainWindow because it doesn't have a window, # Plex doesn't respond to CloseMainWindow because it doesn't have a window,
# and Stop-Process does a forced exit of the process, so use taskkill to ask # and Stop-Process does a forced exit of the process, so use taskkill to ask
@ -265,10 +283,11 @@ class PlexDBRepair {
if ($PMS.HasExited) { if ($PMS.HasExited) {
$this.WriteLog("Stop - PASS") $this.WriteLog("Stop - PASS")
$this.Output("Stopped PMS.") $this.Output("Stopped PMS.")
} else { return
$this.OutputWarn("Could not stop PMS. PMS did not shutdown within 30 second limit.")
$this.WriteLog("Stop - FAIL (Timeout)")
} }
$this.OutputWarn("Could not stop PMS. PMS did not shutdown within 30 second limit.")
$this.WriteLog("Stop - FAIL (Timeout)")
} }
# Start Plex Media Server if it isn't already running # Start Plex Media Server if it isn't already running
@ -293,14 +312,14 @@ class PlexDBRepair {
} }
# All-in-one database utility - Repair/Check/Reindex # All-in-one database utility - Repair/Check/Reindex
[void] RunAutomaticDatabaseMaintenance() { [bool] RunAutomaticDatabaseMaintenance() {
$this.Output("Automatic Check,Repair,Index started.") $this.Output("Automatic Check,Repair,Index started.")
$this.WriteLog("Auto - START") $this.WriteLog($this.StageLog("START"))
if ($this.PMSRunning()) { if ($this.PMSRunning()) {
$this.WriteLog("Auto - FAIL - PMS running") $this.WriteLog($this.StageLog("FAIL - PMS running"))
$this.OutputWarn("Unable to run automatic sequence. PMS is running. Please stop PlexMediaServer.") $this.OutputWarn("Unable to run automatic sequence. PMS is running. Please stop PlexMediaServer.")
return return $false
} }
# Create temporary backup directory # Create temporary backup directory
@ -310,85 +329,113 @@ class PlexDBRepair {
New-Item -Path $DBTemp -ItemType "directory" -ErrorVariable tempDirError *>$null New-Item -Path $DBTemp -ItemType "directory" -ErrorVariable tempDirError *>$null
if ($TempDirError) { if ($TempDirError) {
$this.ExitDBMaintenance("Unable to create temporary database directory", $false) $this.ExitDBMaintenance("Unable to create temporary database directory", $false)
return return $false
} }
} }
$this.Output("Exporting Main DB") $this.Output("Exporting Main DB")
$MainDBName = "com.plexapp.plugins.library.db" $MainDBPath = Join-Path $this.PlexDBDir -ChildPath $this.MainDB
$MainDB = Join-Path $this.PlexDBDir -ChildPath $MainDBName
$MainDBSQL = Join-Path $DBTemp -ChildPath "library.sql_$($this.TimeStamp)" $MainDBSQL = Join-Path $DBTemp -ChildPath "library.sql_$($this.TimeStamp)"
if (!$this.FileExists($MainDB)) { if (!$this.FileExists($MainDBPath)) {
$this.ExitDBMaintenance("Could not find $MainDBName in database directory", $false) $this.ExitDBMaintenance("Could not find $($this.MainDB) in database directory", $false)
return return $false
} }
if (!$this.ExportPlexDB($MainDB, $MainDBSQL)) { return } if (!$this.ExportPlexDB($MainDBPath, $MainDBSQL)) { return $false }
$this.Output("Exporting Blobs DB") $this.Output("Exporting Blobs DB")
$BlobsDBName = "com.plexapp.plugins.library.blobs.db" $BlobsDBPath = Join-Path $this.PlexDBDir -ChildPath $this.BlobsDB
$BlobsDB = Join-Path $this.PlexDBDir -ChildPath $BlobsDBName
$BlobsDBSQL = Join-Path $DBTemp -ChildPath "blobs.sql_$($this.Timestamp)" $BlobsDBSQL = Join-Path $DBTemp -ChildPath "blobs.sql_$($this.Timestamp)"
if (!$this.FileExists($BlobsDB)) { if (!$this.FileExists($BlobsDBPath)) {
$this.ExitDBMaintenance("Could not find $BlobsDBName in database directory", $false) $this.ExitDBMaintenance("Could not find $($this.BlobsDB) in database directory", $false)
return return $false
} }
if (!$this.ExportPlexDB($BlobsDB, $BlobsDBSQL)) { return } if (!$this.ExportPlexDB($BlobsDBPath, $BlobsDBSQL)) { return $false }
$this.Output("Successfully exported the main and blobs databases. Proceeding to import into new database.") $this.Output("Successfully exported the main and blobs databases. Proceeding to import into new database.")
$this.WriteLog("Repair - Export databases - PASS") $this.WriteLog("Repair - Export databases - PASS")
# Make sure Plex hasn't been started while we were exporting
if (!$this.CheckPMS("export")) { return $false }
$this.Output("Importing Main DB.") $this.Output("Importing Main DB.")
$MainDBImport = Join-Path $this.PlexDBDir -ChildPath "${MainDBName}_$($this.Timestamp)" $MainDBImport = Join-Path $this.PlexDBDir -ChildPath "$($this.MainDB)_$($this.Timestamp)"
if (!$this.ImportPlexDB($MainDBSQL, $MainDBImport)) { return } if (!$this.ImportPlexDB($MainDBSQL, $MainDBImport)) { return $false }
$this.Output("Creating Blobs DB") $this.Output("Importing Blobs DB.")
$BlobsDBImport = Join-Path $this.PlexDBDir -ChildPath "${BlobsDBName}_$($this.Timestamp)" $BlobsDBImport = Join-Path $this.PlexDBDir -ChildPath "$($this.BlobsDB)_$($this.Timestamp)"
if (!$this.ImportPlexDB($BlobsDBSQL, $BlobsDBImport)) { return } if (!$this.ImportPlexDB($BlobsDBSQL, $BlobsDBImport)) { return $false }
$this.Output("Successfully imported databases.") $this.Output("Successfully imported databases.")
$this.WriteLog("Repair - Import - PASS") $this.WriteLog("Repair - Import - PASS")
$this.Output("Verifying databases integrity after importing.") $this.Output("Verifying databases integrity after importing.")
if (!$this.IntegrityCheck($MainDBImport, "Main")) { return } if (!$this.IntegrityCheck($MainDBImport, "Main")) { return $false }
$this.Output("Verification complete. PMS main database is OK.") $this.Output("Verification complete. PMS main database is OK.")
$this.WriteLog("Repair - Verify main database - PASS") $this.WriteLog("Repair - Verify main database - PASS")
if (!$this.IntegrityCheck($BlobsDBImport, "Blobs")) { return } if (!$this.IntegrityCheck($BlobsDBImport, "Blobs")) { return $false }
$this.Output("Verification complete. PMS blobs database is OK.") $this.Output("Verification complete. PMS blobs database is OK.")
$this.WriteLog("Repair - Verify blobs database - PASS") $this.WriteLog("Repair - Verify blobs database - PASS")
if (!$this.CheckPMS("import")) { return $false }
# Import complete, now reindex # Import complete, now reindex
$this.WriteOutputLog("Reindexing Main DB") $this.WriteOutputLog("Reindexing Main DB")
if (!$this.RunSQLCommand("""$MainDBImport"" ""REINDEX;""", "Failed to reindex Main DB")) { return } if (!$this.RunSQLCommand("""$MainDBImport"" ""REINDEX;""", "Failed to reindex Main DB")) { return $false }
$this.WriteOutputLog("Reindexing Blobs DB") $this.WriteOutputLog("Reindexing Blobs DB")
if (!$this.RunSQLCommand("""$BlobsDBImport"" ""REINDEX;""", "Failed to reindex Blobs DB")) { return } if (!$this.RunSQLCommand("""$BlobsDBImport"" ""REINDEX;""", "Failed to reindex Blobs DB")) { return $false }
$this.WriteOutputLog("Reindexing complete.") $this.WriteOutputLog("Reindexing complete.")
$this.WriteOutputLog("Moving current DBs to DBTMP and making new databases active") $this.WriteOutputLog("Moving current DBs to DBTMP and making new databases active")
if (!$this.CheckPMS("new database copy")) { return $false }
$MoveError = $null try {
Move-Item -Path $MainDB -Destination (Join-Path $DBTemp -ChildPath "${MainDBName}_$($this.TimeStamp)") -ErrorVariable moveError *>$null $this.MoveDatabase($MainDBPath, (Join-Path $DBTemp -ChildPath "$($this.MainDB)_$($this.Timestamp)"), "move Main DB to DBTMP")
if ($MoveError) { $this.ExitDBMaintenance("Unable to move Main DB to DBTMP: $MoveError", $false); return } $this.MoveDatabase($MainDBImport, $MainDBPath, "replace Main DB with rebuilt DB")
Move-Item -Path $MainDBImport -Destination $MainDB -ErrorVariable moveError *>$null
if ($MoveError) { $this.ExitDBMaintenance("Unable to replace Main DB with rebuilt DB: $MoveError", $false); return } $this.MoveDatabase($BlobsDBPath, (Join-Path $DBTemp -ChildPath "$($this.BlobsDB)_$($this.Timestamp)"), "move Blobs DB to DBTMP")
$this.MoveDatabase($BlobsDBImport, $BlobsDBPath, "replace Blobs DB with rebuilt DB")
Move-Item -Path $BlobsDB -Destination (Join-Path $DBTemp -ChildPath "${BlobsDBName}_$($this.TimeStamp)") -ErrorVariable moveError *>$null } catch {
if ($MoveError) { $this.ExitDBMaintenance("Unable to move Blobs DB to DBTMP: $MoveError", $false) } $Error.Clear()
Move-Item -Path $BlobsDBImport -Destination $BlobsDB -ErrorVariable moveError *>$null return $false
if ($MoveError) { $this.ExitDBMaintenance("Unable to replace Blobs DB with rebuilt DB: $MoveError", $false); return } }
$this.ExitDBMaintenance("Database repair/rebuild/reindex completed.", $true) $this.ExitDBMaintenance("Database repair/rebuild/reindex completed.", $true)
return $true
}
# Return whether we can continue DB repair (i.e. whether PMS is running) at the given stage in the process.
[bool] CheckPMS([string] $SubStage) {
if ($this.PMSRunning()) {
$SubMessage = if ($SubStage) { "during $SubStage" } else { "" }
$this.WriteLog($this.StageLog("FAIL - PMS running $SubMessage"))
$this.OutputWarn("Unable to run $($this.Stage.TrimEnd()). PMS is running. Please stop PlexMediaServer.")
return $false
}
return $true
}
# Try to move the source file to the destination. If it fails, attempt to find
# open file handles (requires handle.exe on PATH) and throw.
[void] MoveDatabase([string] $Source, [string] $Destination, [string] $FriendlyString) {
$MoveError = $null
Move-Item -Path $Source -Destination $Destination -ErrorVariable MoveError *>$null
if ($MoveError) {
$this.ExitDBMaintenance("Unable to $($FriendlyString): $MoveError", $false)
throw "Unable to move database"
}
} }
# Attempts to prune PhotoTranscoder images that are older than the specified date cutoff (30 days by default) # Attempts to prune PhotoTranscoder images that are older than the specified date cutoff (30 days by default)
[void] PrunePhotoTranscoderCache() { [void] PrunePhotoTranscoderCache() {
$this.WriteLog("Prune - START") $this.WriteLog($this.StageLog("START"))
if ($this.PMSRunning()) { if ($this.PMSRunning()) {
$this.OutputWarn("Unable to prune Phototranscoder cache. PMS is running.") $this.OutputWarn("Unable to prune Phototranscoder cache. PMS is running.")
$this.WriteLog("Prune - FAIL - PMS running") $this.WriteLog($this.StageLog("FAIL - PMS running"))
return return
} }
@ -402,7 +449,7 @@ class PlexDBRepair {
if ($Prunable -eq 0) { if ($Prunable -eq 0) {
$this.Output("No files found to prune.") $this.Output("No files found to prune.")
$this.WriteLog("Prune - PASS (no files found to prune)") $this.WriteLog($this.StageLog("PASS (no files found to prune)"))
return return
} }
@ -415,13 +462,13 @@ class PlexDBRepair {
$Pruned = $PruneResult.PrunableFiles $Pruned = $PruneResult.PrunableFiles
$Total = $PruneResult.TotalFiles $Total = $PruneResult.TotalFiles
$Saved = $PruneResult.SpaceSavings $Saved = $PruneResult.SpaceSavings
$this.WriteOutputLog("Prune - Removed $Pruned files over $Cutoff days old ($Saved), out of $Total total files") $this.WriteOutputLog($this.StageLog("Removed $Pruned files over $Cutoff days old ($Saved), out of $Total total files"))
$this.Output("Pruning completed.") $this.Output("Pruning completed.")
} else { } else {
$this.WriteOutputLog("Prune - Prune cancelled by user") $this.WriteOutputLog($this.StageLog("Prune cancelled by user"))
} }
$this.WriteLog("Prune - PASS") $this.WriteLog($this.StageLog("PASS"))
} }
# Traverses PhotoTranscoder cache to find and delete files older than the specified max age. # Traverses PhotoTranscoder cache to find and delete files older than the specified max age.
@ -494,6 +541,16 @@ class PlexDBRepair {
$this.WriteLog("============================================================") $this.WriteLog("============================================================")
} }
# Set the current stage (with the right amount of padding)
[void] SetStage([string] $Stage) {
$this.Stage = $Stage + (" " * [math]::Max(0, 8 - $Stage.Length))
}
# Prepend the current stage to the given text
[string] StageLog([string] $text) {
return "$($this.Stage) - $text"
}
### File Helpers ### ### File Helpers ###
# Check whether the given directory exists (and is a directory) # Check whether the given directory exists (and is a directory)
@ -516,7 +573,7 @@ class PlexDBRepair {
### Setup Helpers ### ### Setup Helpers ###
# Retrieve Plex's data directory, exiting the script on falure # Retrieve Plex's data directory, exiting the script on failure
[string] GetAppDataDir() { [string] GetAppDataDir() {
$PMSRegistry = $this.GetHKCU() $PMSRegistry = $this.GetHKCU()
$PlexAppData = $PMSRegistry.LocalAppDataPath $PlexAppData = $PMSRegistry.LocalAppDataPath
@ -631,14 +688,18 @@ class PlexDBRepair {
[void] ExitDBMaintenance([string] $Message, [boolean] $Success) { [void] ExitDBMaintenance([string] $Message, [boolean] $Success) {
if ($Success) { if ($Success) {
$this.Output("Automatic Check,Repair,Index succeeded.") $this.Output("Automatic Check,Repair,Index succeeded.")
$this.WriteLog("Auto - PASS") $this.WriteLog($this.StageLog("PASS"))
} else { } else {
$this.OutputWarn("Automatic maintenance failed - $Message") $this.OutputWarn("Database maintenance failed - $Message")
$this.WriteLog("Auto - $Message, cannot continue.") $this.WriteLog($this.StageLog("$Message, cannot continue."))
$this.WriteLog("Auto - FAIL") $this.WriteLog($this.StageLog("FAIL"))
} }
} }
[bool] ExportPlexDB([string] $Source, [string] $Destination) {
return $this.RunSQLCommand("""$Source"" "".output '$Destination'"" .dump", "Failed to export '$Source' to '$Destination'")
}
# Run an SQL command. # Run an SQL command.
# ErrorMessage is the message to output/write to the log on failure # ErrorMessage is the message to output/write to the log on failure
[bool] RunSQLCommand([string] $Command, [string] $ErrorMessage) { [bool] RunSQLCommand([string] $Command, [string] $ErrorMessage) {
@ -689,35 +750,15 @@ class PlexDBRepair {
return $true return $true
} }
[bool] ExportPlexDB([string] $Source, [string] $Destination) {
$SqlError = $null
$Command = """$Source"" .dump | Set-Content ""$Destination"" -Encoding utf8"
try {
Invoke-Expression "& ""$($this.PlexSQL)"" $Command" -ev SqlError -EA Stop *>$null
} catch {
$Err = $Error -join "`n"
# Even if we ignore errors, we can't continue if the export failed.
$this.ExitDBMaintenance("Failed to export '$Source' to '$Destination': '$Err'", $false)
$Error.Clear()
return $false
}
if ($SqlError) {
$Err = $SqlError -join "`n"
if ($this.Options.IgnoreErrors) {
$this.OutputWarn("Ignoring database errors during export: $Err")
} else {
$this.ExitDBMaintenance("Failed to export '$Source' to '$Destination': '$Err'", $false)
return $false
}
}
return $true
}
# Import an exported .sql file into a new database # Import an exported .sql file into a new database
[bool] ImportPlexDB($Source, $Destination) { [bool] ImportPlexDB($Source, $Destination) {
# SQLite's .read can't handle files larger than 2GB on versions <3.45.0 (https://sqlite.org/forum/forumpost/9af57ba66fbb5349),
# and Plex SQLite is currently on 3.39.4 (as of PMS 1.41.6).
# If the source is smaller than 2GB we can .read it directly, otherwise do things in a more roundabout way.
if ($this.FileExists($Source) -and (Get-Item $Source).Length -lt 2GB) {
return $this.RunSQLCommand("""$Destination"" "".read '$Source'""", "Failed to import Plex database (importing '$Source' into '$Destination')")
}
$ImportError = $null $ImportError = $null
$ExitCode = 0 $ExitCode = 0
$Err = $null $Err = $null
@ -760,7 +801,7 @@ class PlexDBRepair {
} }
} }
$this.Options.CanIgnore = $false $this.Options.CanIgnore = $true
return $result return $result
} }
@ -791,7 +832,7 @@ class PlexDBRepair {
# Return whether PMS is running # Return whether PMS is running
[bool] PMSRunning() { [bool] PMSRunning() {
return !!$this.GetPMS() return $null -ne $this.GetPMS()
} }
# Retrieve the PMS process, if running # Retrieve the PMS process, if running
@ -815,14 +856,14 @@ class PlexDBRepair {
} }
# Contains miscellaneous options/state over the course of a session. # Contains miscellaneous options/state over the course of a session.
class PlexDBRepairOptions { class DBRepairOptions {
[bool] $Scripted # Whether we're running in scripted or interactive mode [bool] $Scripted # Whether we're running in scripted or interactive mode
[bool] $ShowMenu # Whether to show the menu after each command executes [bool] $ShowMenu # Whether to show the menu after each command executes
[bool] $IgnoreErrors # Whether to honor or ignore constraint errors on import [bool] $IgnoreErrors # Whether to honor or ignore constraint errors on import
[bool] $CanIgnore # Some errors can't be ignored (e.g. integrity_check) [bool] $CanIgnore # Some errors can't be ignored (e.g. integrity_check)
[int32] $CacheAge # The date cutoff for pruning PhotoTranscoder cached images [int32] $CacheAge # The date cutoff for pruning PhotoTranscoder cached images
PlexDBRepairOptions() { DBRepairOptions() {
$this.CacheAge = 30 $this.CacheAge = 30
$this.ShowMenu = $true $this.ShowMenu = $true
$this.Scripted = $false $this.Scripted = $false
@ -857,7 +898,7 @@ $InputEncodingSave = [console]::InputEncoding
$OutputEncodingSave = [console]::OutputEncoding $OutputEncodingSave = [console]::OutputEncoding
[console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
[void]([PlexDBRepair]::new($args, $PlexDBRepairVersion)) [void]([DBRepair]::new($args, $DBRepairVersion))
[console]::OutputEncoding = $OutputEncodingSave [console]::OutputEncoding = $OutputEncodingSave
[console]::InputEncoding = $InputEncodingSave [console]::InputEncoding = $InputEncodingSave

View File

@ -1,4 +1,4 @@
# PlexDBRepair-Windows # DBRepair-Windows
DBRepair-Windows.ps1 (and DBRepair-Windows.bat) are scripts run from the command line, which have DBRepair-Windows.ps1 (and DBRepair-Windows.bat) are scripts run from the command line, which have
sufficient privilege to read/write the Plex databases in the sufficient privilege to read/write the Plex databases in the
@ -9,13 +9,13 @@ sufficient privilege to read/write the Plex databases in the
Currently, there are two separate Windows scripts, a batch script (.bat) and a PowerShell script Currently, there are two separate Windows scripts, a batch script (.bat) and a PowerShell script
(.ps1). The batch script is a one-shot, zero-input script that attempts automatic database (.ps1). The batch script is a one-shot, zero-input script that attempts automatic database
maintenance (repair/rebuild, check, and reindex). The PowerShell script is intended to align with maintenance (repair/rebuild, check, and reindex). The PowerShell script is intended to align with
PlexDBRepair.sh, offering command-name-based functionality that can either be scripted or DBRepair.sh, offering command-name-based functionality that can either be scripted or
interactive. interactive.
In the future, DBRepair-Windows.bat will be removed in favor of DBRepair-Windows.ps1. The batch In the future, DBRepair-Windows.bat will be removed in favor of DBRepair-Windows.ps1. The batch
file is currently kept as a backup while the PowerShell script continues to be expanded and file is currently kept as a backup while the PowerShell script continues to be expanded and
tested. If any unexpected issues arise with the PowerShell script, please open an tested. If any unexpected issues arise with the PowerShell script, please open an
[issue](https://github.com/ChuckPa/PlexDBRepair/issues) so it can be investigated. [issue](https://github.com/ChuckPa/DBRepair/issues) so it can be investigated.
## Functions provided ## Functions provided

View File

@ -1,17 +1,33 @@
# PlexDBRepair-Windows # DBRepair-Windows
Release notes for the Windows counterpart to DBRepair.sh (DBRepair-Windows.ps1) Release notes for the Windows counterpart to DBRepair.sh (DBRepair-Windows.ps1)
# Release Info # Release Info
v1.00.01 v1.01.02
- Bug Fix: Ensure UTF-8 characters get exported/imported properly. - Remove `statistics_bandwidth` pruning, as it's now part of PMS 1.41.8
- Change `quit` to 98 and `exit` to 99
v1.00.00 - Minor logging refactoring
- Initial Windows PowerShell script release, aiming to provide a similar experience as DBRepair.sh, with command-name-based input.
- Initial command support: v1.01.01
- AUTO(matic) - Add `staticstics_bandwidth` pruning during automatic repair.
- EXIT
- PRUN(e) v1.01.00
- STAR(t) - Rename this tool to be compliant with Plex inc. Trademark Policy.
- STOP
v1.00.02
- Check whether PMS is running at more points in the process.
- Don't remove temp files in scripted mode if the last operation failed.
- Better export process that improves upon the UTF-8 fix in v1.00.01.
v1.00.01
- Bug Fix: Ensure UTF-8 characters get exported/imported properly.
v1.00.00
- Initial Windows PowerShell script release, aiming to provide a similar experience as DBRepair.sh, with command-name-based input.
- Initial command support:
- AUTO(matic)
- EXIT
- PRUN(e)
- STAR(t)
- STOP