mirror of
https://github.com/ChuckPa/PlexDBRepair.git
synced 2025-11-06 11:18:54 -05:00
Merge pull request #188 from danrahn/capture_constraint_errors
[Windows] Add Honor/Ignore options and ensure all import errors are captured
This commit is contained in:
commit
d505486e95
@ -77,6 +77,11 @@ class PlexDBRepair {
|
|||||||
Write-Host " 7 - 'start' - Start PMS"
|
Write-Host " 7 - 'start' - Start PMS"
|
||||||
Write-Host
|
Write-Host
|
||||||
Write-Host " 21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache."
|
Write-Host " 21 - 'prune' - Prune (remove) old image files (jpeg,jpg,png) from PhotoTranscoder cache."
|
||||||
|
if ($this.Options.IgnoreErrors) {
|
||||||
|
Write-Host " 42 - 'honor' - Honor all database errors."
|
||||||
|
} else {
|
||||||
|
Write-Host " 42 - 'ignore' - Ignore duplicate/constraint errors."
|
||||||
|
}
|
||||||
Write-Host
|
Write-Host
|
||||||
Write-Host " 99 - 'quit' - Quit immediately. Keep all temporary files."
|
Write-Host " 99 - 'quit' - Quit immediately. Keep all temporary files."
|
||||||
Write-Host " 'exit' - Exit with cleanup options."
|
Write-Host " 'exit' - Exit with cleanup options."
|
||||||
@ -185,6 +190,16 @@ class PlexDBRepair {
|
|||||||
"^(2|autom?a?t?i?c?)$" { $this.RunAutomaticDatabaseMaintenance() }
|
"^(2|autom?a?t?i?c?)$" { $this.RunAutomaticDatabaseMaintenance() }
|
||||||
"^(7|start?)$" { $this.StartPMS() }
|
"^(7|start?)$" { $this.StartPMS() }
|
||||||
"^(21|(prune?|remov?e?))$" { $this.PrunePhotoTranscoderCache() }
|
"^(21|(prune?|remov?e?))$" { $this.PrunePhotoTranscoderCache() }
|
||||||
|
"^(42|ignor?e?|honor?)$" {
|
||||||
|
if (($this.Options.IgnoreErrors -and ($Choice[0] -eq 'i')) -or (!$this.Options.IgnoreErrors -and ($Choice[0] -eq 'h'))) {
|
||||||
|
Write-Host "Honor/Ignore setting unchanged."
|
||||||
|
Break
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.Options.IgnoreErrors = !$this.Options.IgnoreErrors
|
||||||
|
$msg = if ($this.Options.IgnoreErrors) { "Ignoring database errors." } else { "Honoring database errors." }
|
||||||
|
$this.WriteOutputLog($msg)
|
||||||
|
}
|
||||||
"^(99|quit)$" {
|
"^(99|quit)$" {
|
||||||
$this.Output("Retaining all remporary work files.")
|
$this.Output("Retaining all remporary work files.")
|
||||||
$this.WriteLog("Exit - Retain temp files.")
|
$this.WriteLog("Exit - Retain temp files.")
|
||||||
@ -308,7 +323,7 @@ class PlexDBRepair {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this.RunSQLCommand("""$MainDB"" .dump | Set-Content ""$MainDBSQL"" -Encoding utf8", "Failed to export main database")) { return }
|
if (!$this.ExportPlexDB($MainDB, $MainDBSQL)) { return }
|
||||||
|
|
||||||
$this.Output("Exporting Blobs DB")
|
$this.Output("Exporting Blobs DB")
|
||||||
$BlobsDBName = "com.plexapp.plugins.library.blobs.db"
|
$BlobsDBName = "com.plexapp.plugins.library.blobs.db"
|
||||||
@ -319,7 +334,7 @@ class PlexDBRepair {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this.RunSQLCommand("""$BlobsDB"" .dump | Set-Content ""$BlobsDBSQL"" -Encoding utf8", "Failed to export blobs database")) { return }
|
if (!$this.ExportPlexDB($BlobsDB, $BlobsDBSQL)) { return }
|
||||||
|
|
||||||
$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")
|
||||||
@ -337,23 +352,11 @@ class PlexDBRepair {
|
|||||||
|
|
||||||
$this.Output("Verifying databases integrity after importing.")
|
$this.Output("Verifying databases integrity after importing.")
|
||||||
|
|
||||||
$VerifyResult = ""
|
if (!$this.IntegrityCheck($MainDBImport, "Main")) { return }
|
||||||
if (!$this.GetSQLCommandResult("""$MainDBImport"" ""PRAGMA integrity_check(1)""", "Failed to verify main DB", [ref]$VerifyResult)) { return }
|
|
||||||
$this.Output("Main DB verification check is: $VerifyResult")
|
|
||||||
if ($VerifyResult -ne "ok") {
|
|
||||||
$this.ExitDBMaintenance("Main DB verification failed: $VerifyResult", $false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
$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.GetSQLCommandResult("""$BlobsDBImport"" ""PRAGMA integrity_check(1)""", "Failed to verify main DB", [ref]$VerifyResult)) { return }
|
if (!$this.IntegrityCheck($BlobsDBImport, "Blobs")) { return }
|
||||||
if ($VerifyResult -ne "ok") {
|
|
||||||
$this.ExitDBMaintenance("Blobs DB verification failed: $VerifyResult", $false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
$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")
|
||||||
|
|
||||||
@ -644,7 +647,7 @@ class PlexDBRepair {
|
|||||||
|
|
||||||
# Run an SQL command and retrieve the output of said command
|
# Run an SQL command and retrieve the output of said 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] GetSQLCommandResult([string] $Command, [string] $ErrorMessage, [ref]$Output) {
|
[bool] GetSQLCommandResult([string] $Command, [string] $ErrorMessage, [ref] $Output) {
|
||||||
return $this.RunSQLCommandCore($Command, $ErrorMessage, $Output)
|
return $this.RunSQLCommandCore($Command, $ErrorMessage, $Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,8 +655,10 @@ class PlexDBRepair {
|
|||||||
[bool] RunSQLCommandCore([string] $Command, [string] $ErrorMessage, [ref] $Output) {
|
[bool] RunSQLCommandCore([string] $Command, [string] $ErrorMessage, [ref] $Output) {
|
||||||
$SqlError = $null
|
$SqlError = $null
|
||||||
$SqlResult = $null
|
$SqlResult = $null
|
||||||
|
$ExitCode = 0
|
||||||
try {
|
try {
|
||||||
Invoke-Expression "& ""$($this.PlexSQL)"" $Command" -ev sqlError -OutVariable sqlResult -EA Stop *>$null
|
Invoke-Expression "& ""$($this.PlexSQL)"" $Command" -ev sqlError -OutVariable sqlResult -EA Stop *>$null
|
||||||
|
$ExitCode = $LASTEXITCODE
|
||||||
} catch {
|
} catch {
|
||||||
$Err = $Error -join "`n"
|
$Err = $Error -join "`n"
|
||||||
$this.ExitDBMaintenance("Failed to run command '$Command': '$Err'", $false)
|
$this.ExitDBMaintenance("Failed to run command '$Command': '$Err'", $false)
|
||||||
@ -661,16 +666,21 @@ class PlexDBRepair {
|
|||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($SqlError) {
|
if ($SqlError -or $ExitCode) {
|
||||||
$Err = $SqlError -join "`n"
|
$Err = $SqlError -join "`n"
|
||||||
|
if (!$Err) { $Err = "Process exited with error code $ExitCode" }
|
||||||
$Msg = $ErrorMessage
|
$Msg = $ErrorMessage
|
||||||
if (!$Msg) {
|
if (!$Msg) {
|
||||||
$Msg = "Plex SQLite operation failed"
|
$Msg = "Plex SQLite operation failed"
|
||||||
}
|
}
|
||||||
|
|
||||||
$this.ExitDBMaintenance("${msg}: $Err", $false)
|
if ($this.Options.IgnoreErrors -and $this.Options.CanIgnore) {
|
||||||
|
$this.OutputWarn("Ignoring database errors - ${Msg}: $Err")
|
||||||
|
} else {
|
||||||
|
$this.ExitDBMaintenance("${Msg}: $Err", $false)
|
||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($null -ne $Output.Value) {
|
if ($null -ne $Output.Value) {
|
||||||
$Output.Value = $SqlResult
|
$Output.Value = $SqlResult
|
||||||
@ -679,21 +689,58 @@ class PlexDBRepair {
|
|||||||
return $true
|
return $true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Import an exported .sql file into a new database
|
[bool] ExportPlexDB([string] $Source, [string] $Destination) {
|
||||||
[bool] ImportPlexDB($Source, $Destination) {
|
$SqlError = $null
|
||||||
$ImportError = $null
|
$Command = """$Source"" .dump | Set-Content ""$Destination"" -Encoding utf8"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
# Use Start-Process, since PowerShell doesn't have '<', and alternatives ("Get-Content X | SQLite.exe OutDB") are subpar at best when dealing with large files like these database exports.
|
Invoke-Expression "& ""$($this.PlexSQL)"" $Command" -ev SqlError -EA Stop *>$null
|
||||||
Start-Process $this.PlexSQL -ArgumentList @("""$Destination""") -RedirectStandardInput $Source -NoNewWindow -Wait -EA Stop -ErrorVariable importError
|
|
||||||
} catch {
|
} catch {
|
||||||
$Err = $Error -join "`n"
|
$Err = $Error -join "`n"
|
||||||
$this.ExitDBMaintenance("Failed to import Plex database (importing '$Source' into '$Destination): $Err", $false)
|
# 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()
|
$Error.Clear()
|
||||||
return $false
|
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
|
||||||
|
[bool] ImportPlexDB($Source, $Destination) {
|
||||||
|
$ImportError = $null
|
||||||
|
$ExitCode = 0
|
||||||
|
$Err = $null
|
||||||
|
try {
|
||||||
|
# Use Start-Process, since PowerShell doesn't have '<', and alternatives ("Get-Content X | SQLite.exe OutDB") are subpar at best when dealing with large files like these database exports.
|
||||||
|
$process = Start-Process $this.PlexSQL -ArgumentList @("""$Destination""") -RedirectStandardInput $Source -NoNewWindow -Wait -PassThru -EA Stop -ErrorVariable ImportError
|
||||||
|
$ExitCode = $process.ExitCode
|
||||||
|
} catch {
|
||||||
|
$Err = $Error -join "`n"
|
||||||
|
$Error.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
if ($ImportError) {
|
if ($ImportError) {
|
||||||
$Err = $ImportError -join "`n"
|
$Err = $ImportError -join "`n"
|
||||||
|
} elseif ($ExitCode) {
|
||||||
|
if ($this.Options.IgnoreErrors) {
|
||||||
|
$this.OutputWarn("Ignoring errors found during import")
|
||||||
|
} else {
|
||||||
|
$Err = "Process exited with error code $ExitCode (constraint error?)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Err) {
|
||||||
$this.ExitDBMaintenance("Failed to import Plex database (importing '$Source' into '$Destination'): $Err", $false)
|
$this.ExitDBMaintenance("Failed to import Plex database (importing '$Source' into '$Destination'): $Err", $false)
|
||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
@ -701,6 +748,22 @@ class PlexDBRepair {
|
|||||||
return $true
|
return $true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[bool] IntegrityCheck([string] $Database, [string] $DbName) {
|
||||||
|
$this.Options.CanIgnore = $false
|
||||||
|
$VerifyResult = ""
|
||||||
|
$result = $this.GetSQLCommandResult("""$Database"" ""PRAGMA integrity_check(1)""", "Failed to verify $dbName DB", [ref]$VerifyResult)
|
||||||
|
if ($result) {
|
||||||
|
$this.Output("$DbName DB verification check is: $VerifyResult")
|
||||||
|
if ($VerifyResult -ne "ok") {
|
||||||
|
$this.ExitDBMaintenance("$DbName DB verification failed: $VerifyResult", $false)
|
||||||
|
$result = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.Options.CanIgnore = $false
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
# Clear out the temp database directory. If $Confirm is $true, asks the user before doing so.
|
# Clear out the temp database directory. If $Confirm is $true, asks the user before doing so.
|
||||||
[void] CleanDBTemp([bool] $Confirm) {
|
[void] CleanDBTemp([bool] $Confirm) {
|
||||||
if ($Confirm -and !$this.GetYesNo("Ok to remove temporary databases/workfiles for this session")) {
|
if ($Confirm -and !$this.GetYesNo("Ok to remove temporary databases/workfiles for this session")) {
|
||||||
@ -755,12 +818,16 @@ class PlexDBRepair {
|
|||||||
class PlexDBRepairOptions {
|
class PlexDBRepairOptions {
|
||||||
[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] $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() {
|
PlexDBRepairOptions() {
|
||||||
$this.CacheAge = 30
|
$this.CacheAge = 30
|
||||||
$this.ShowMenu = $true
|
$this.ShowMenu = $true
|
||||||
$this.Scripted = $false
|
$this.Scripted = $false
|
||||||
|
$this.IgnoreErrors = $false
|
||||||
|
$this.CanIgnore = $true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user