Compare commits

..
1 Commits
Author SHA1 Message Date
ChuckPa 7476c2bdad Release v26.10.00 2026-10-16 14:40:15 -04:00
13 changed files with 542 additions and 6395 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
*.zip
/package/
-49
View File
@@ -1,49 +0,0 @@
## How to contribute
As this tool becomes more popular, it also becomes more important to coordinate and document our work.
To contribute to the project, please follow the following instructions:
### Open an Issue describing the problem or enhancement.
- Add a label to the issue
### When submitting your work for review and merge:
1. Create an issue in the DBRepair repo against the current release
- Describe the deficiency to be addressed in sufficient detail
2. Complete your work in your branch
- Be certain to REBASE prior to starting work.
3. Prior to opening a pull request,
- Squash multiple commits into a single commit.
- Clean up the commit message after squashing.
- Use force-push if needed to unify all changes so there is one hash to reference.
4. Open the pull request against the master branch
5. In the pull request, provide a description of what change(s) where made
- As last text added, on a blank line,
- Add the text: `Fixes:` followed by the URL of the open Issue
eg: Fixes: https://github.com/ChuckPa/DBRepair/issues/12 (if we were fixing issue 12)
- Adding the above text & URL has the following impact:
-- The Issue which prompted the change is forever linked to the PR making documentation easy.
-- In the event of unforseen issues, reverting the changes will be trivial and allow easier rework.
6. Be certain to request review with your pull request.
7. Upon completion of review and testing, contributions will be merged into master.
When the PR is approved and merged, Github will automatically mark the issue as closed and fixed.
8. The fix will be included in the next release or immediately in a new release if so warranted.
### Policy
While questions, suggestions, enhancement requests, and bug fixes are welcome and almost always implemented,
it's not possible to accept PRs without an accompanying issue documention which justifies the change.
Thanks,
Chuck
-3034
View File
File diff suppressed because it is too large. Load diff
+453
View File
@@ -0,0 +1,453 @@
Copyright (c) 2022-2026, ChuckPa. All Rights Reserved.
DBRepair is proprietary software developed by ChuckPa. It is provided free
of charge for use with Plex Media Server (Copyright & Trademark of Plex, Inc.).
By installing, copying, or otherwise using this software, you agree to
the following terms:
* No Reverse Engineering: You may not decompile, disassemble,
reverse-engineer, or attempt to derive the source code of this software
in any way.
* Permitted Use: You may download, install, and use DBRepair free of
charge, on any number of machines you own or administer, for use with
Plex Media Server.
* No Redistribution: This software, in whole or in part, may not be
copied, modified, hosted, or redistributed in any format without the
express written permission of ChuckPa.
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.
"DBRepair" and associated marks are trademarks of ChuckPa.
THIRD-PARTY SOFTWARE NOTICES
This software includes third-party components used under their own
licenses. Nothing in this license restricts the rights those licenses grant.
* ICU - license reproduced below.
COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later)
Copyright © 1991-2020 Unicode, Inc. All rights reserved.
Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Unicode data files and any associated documentation
(the "Data Files") or Unicode software and any associated documentation
(the "Software") to deal in the Data Files or Software
without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, and/or sell copies of
the Data Files or Software, and to permit persons to whom the Data Files
or Software are furnished to do so, provided that either
(a) this copyright and permission notice appear with all copies
of the Data Files or Software, or
(b) this copyright and permission notice appear in associated
Documentation.
THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in these Data Files or Software without prior
written authorization of the copyright holder.
---------------------
Third-Party Software Licenses
This section contains third-party software notices and/or additional
terms for licensed third-party software components included within ICU
libraries.
1. ICU License - ICU 1.8.1 to ICU 57.1
COPYRIGHT AND PERMISSION NOTICE
Copyright (c) 1995-2016 International Business Machines Corporation and others
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, provided that the above
copyright notice(s) and this permission notice appear in all copies of
the Software and that both the above copyright notice(s) and this
permission notice appear in supporting documentation.
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
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale, use
or other dealings in this Software without prior written authorization
of the copyright holder.
All trademarks and registered trademarks mentioned herein are the
property of their respective owners.
2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt)
# The Google Chrome software developed by Google is licensed under
# the BSD license. Other software included in this distribution is
# provided under other licenses, as set forth below.
#
# The BSD License
# http://opensource.org/licenses/bsd-license.php
# Copyright (C) 2006-2008, Google Inc.
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided with
# the distribution.
# Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
# The word list in cjdict.txt are generated by combining three word lists
# listed below with further processing for compound word breaking. The
# frequency is generated with an iterative training against Google web
# corpora.
#
# * Libtabe (Chinese)
# - https://sourceforge.net/project/?group_id=1519
# - Its license terms and conditions are shown below.
#
# * IPADIC (Japanese)
# - http://chasen.aist-nara.ac.jp/chasen/distribution.html
# - Its license terms and conditions are shown below.
#
# ---------COPYING.libtabe ---- BEGIN--------------------
#
# /*
# * Copyright (c) 1999 TaBE Project.
# * Copyright (c) 1999 Pai-Hsiang Hsiao.
# * All rights reserved.
# *
# * Redistribution and use in source and binary forms, with or without
# * modification, are permitted provided that the following conditions
# * are met:
# *
# * . Redistributions of source code must retain the above copyright
# * notice, this list of conditions and the following disclaimer.
# * . Redistributions in binary form must reproduce the above copyright
# * notice, this list of conditions and the following disclaimer in
# * the documentation and/or other materials provided with the
# * distribution.
# * . Neither the name of the TaBE Project nor the names of its
# * contributors may be used to endorse or promote products derived
# * from this software without specific prior written permission.
# *
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# * OF THE POSSIBILITY OF SUCH DAMAGE.
# */
#
# /*
# * Copyright (c) 1999 Computer Systems and Communication Lab,
# * Institute of Information Science, Academia
# * Sinica. All rights reserved.
# *
# * Redistribution and use in source and binary forms, with or without
# * modification, are permitted provided that the following conditions
# * are met:
# *
# * . Redistributions of source code must retain the above copyright
# * notice, this list of conditions and the following disclaimer.
# * . Redistributions in binary form must reproduce the above copyright
# * notice, this list of conditions and the following disclaimer in
# * the documentation and/or other materials provided with the
# * distribution.
# * . Neither the name of the Computer Systems and Communication Lab
# * nor the names of its contributors may be used to endorse or
# * promote products derived from this software without specific
# * prior written permission.
# *
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# * OF THE POSSIBILITY OF SUCH DAMAGE.
# */
#
# Copyright 1996 Chih-Hao Tsai @ Beckman Institute,
# University of Illinois
# c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4
#
# ---------------COPYING.libtabe-----END--------------------------------
#
#
# ---------------COPYING.ipadic-----BEGIN-------------------------------
#
# Copyright 2000, 2001, 2002, 2003 Nara Institute of Science
# and Technology. All Rights Reserved.
#
# Use, reproduction, and distribution of this software is permitted.
# Any copy of this software, whether in its original form or modified,
# must include both the above copyright notice and the following
# paragraphs.
#
# Nara Institute of Science and Technology (NAIST),
# the copyright holders, disclaims all warranties with regard to this
# software, including all implied warranties of merchantability and
# fitness, in no event shall NAIST be liable for
# any special, indirect or consequential damages or any damages
# whatsoever resulting from loss of use, data or profits, whether in an
# action of contract, negligence or other tortuous action, arising out
# of or in connection with the use or performance of this software.
#
# A large portion of the dictionary entries
# originate from ICOT Free Software. The following conditions for ICOT
# Free Software applies to the current dictionary as well.
#
# Each User may also freely distribute the Program, whether in its
# original form or modified, to any third party or parties, PROVIDED
# that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear
# on, or be attached to, the Program, which is distributed substantially
# in the same form as set out herein and that such intended
# distribution, if actually made, will neither violate or otherwise
# contravene any of the laws and regulations of the countries having
# jurisdiction over the User or the intended distribution itself.
#
# NO WARRANTY
#
# The program was produced on an experimental basis in the course of the
# research and development conducted during the project and is provided
# to users as so produced on an experimental basis. Accordingly, the
# program is provided without any warranty whatsoever, whether express,
# implied, statutory or otherwise. The term "warranty" used herein
# includes, but is not limited to, any warranty of the quality,
# performance, merchantability and fitness for a particular purpose of
# the program and the nonexistence of any infringement or violation of
# any right of any third party.
#
# Each user of the program will agree and understand, and be deemed to
# have agreed and understood, that there is no warranty whatsoever for
# the program and, accordingly, the entire risk arising from or
# otherwise connected with the program is assumed by the user.
#
# Therefore, neither ICOT, the copyright holder, or any other
# organization that participated in or was otherwise related to the
# development of the program and their respective officials, directors,
# officers and other employees shall be held liable for any and all
# damages, including, without limitation, general, special, incidental
# and consequential damages, arising out of or otherwise in connection
# with the use or inability to use the program or any product, material
# or result produced or otherwise obtained by using the program,
# regardless of whether they have been advised of, or otherwise had
# knowledge of, the possibility of such damages at any time during the
# project or thereafter. Each user will be deemed to have agreed to the
# foregoing by his or her commencement of use of the program. The term
# "use" as used herein includes, but is not limited to, the use,
# modification, copying and distribution of the program and the
# production of secondary products from the program.
#
# In the case where the program, whether in its original form or
# modified, was distributed or delivered to or received by a user from
# any person, organization or entity other than ICOT, unless it makes or
# grants independently of ICOT any specific warranty to the user in
# writing, such person, organization or entity, will also be exempted
# from and not be held liable to the user for any such damages as noted
# above as far as the program is concerned.
#
# ---------------COPYING.ipadic-----END----------------------------------
3. Lao Word Break Dictionary Data (laodict.txt)
# Copyright (c) 2013 International Business Machines Corporation
# and others. All Rights Reserved.
#
# Project: https://github.com/veer66/lao-dictionary
# Dictionary: https://github.com/veer66/lao-dictionary/blob/master/Lao-Dictionary.txt
# License: https://github.com/veer66/lao-dictionary/blob/master/Lao-Dictionary-LICENSE.txt
# (copied below)
#
# This file is derived from the above dictionary, with slight
# modifications.
# ----------------------------------------------------------------------
# Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification,
# are permitted provided that the following conditions are met:
#
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer. Redistributions in
# binary form must reproduce the above copyright notice, this list of
# conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
# --------------------------------------------------------------------------
4. Burmese Word Break Dictionary Data (burmesedict.txt)
# Copyright (c) 2014 International Business Machines Corporation
# and others. All Rights Reserved.
#
# This list is part of a project hosted at:
# github.com/kanyawtech/myanmar-karen-word-lists
#
# --------------------------------------------------------------------------
# Copyright (c) 2013, LeRoy Benjamin Sharon
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met: Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer. Redistributions in binary form must reproduce the
# above copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# Neither the name Myanmar Karen Word Lists, nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# --------------------------------------------------------------------------
5. Time Zone Database
ICU uses the public domain data and code derived from Time Zone
Database for its time zone support. The ownership of the TZ database
is explained in BCP 175: Procedure for Maintaining the Time Zone
Database section 7.
# 7. Database Ownership
#
# The TZ database itself is not an IETF Contribution or an IETF
# document. Rather it is a pre-existing and regularly updated work
# that is in the public domain, and is intended to remain in the
# public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do
# not apply to the TZ Database or contributions that individuals make
# to it. Should any claims be made and substantiated against the TZ
# Database, the organization that is providing the IANA
# Considerations defined in this RFC, under the memorandum of
# understanding with the IETF, currently ICANN, may act in accordance
# with all competent court orders. No ownership claims will be made
# by ICANN or the IETF Trust on the database or the code. Any person
# making a contribution to the database or code waives all rights to
# future claims in that contribution or in the TZ Database.
6. Google double-conversion
Copyright 2006-2011, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-6
View File
@@ -1,6 +0,0 @@
Copyright (c) 2022-2026, ChuckPa. All Rights Reserved.
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 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.
+49 -1127
View File
File diff suppressed because it is too large. Load diff
-957
View File
@@ -1,957 +0,0 @@
# DBRepair
[![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/DBRepair.svg?style=flat)](https://github.com/ChuckPa/DBRepair/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/DBRepair/total.svg)](https://github.com/ChuckPa/DBRepair/releases)
[![master](https://img.shields.io/badge/master-stable-green.svg?maxAge=2592000)]('')
![Maintenance](https://img.shields.io/badge/Maintained-Yes-green.svg)
# Release Info:
v1.17.01
1. CheckFTS/RebuildFTS - FTSRebuild did not perform a proper CheckFTS after repairing the FTS
tables. While this doesn't guarantee they won't corrupt again. It does
confirm DBRepair has repaired them.
Thanks to @dreondre for catching and fixing this.
v1.17.00
1. BusyBox - Address edge case errors with NAS vendors' BusyBox shell implementation.
This addresses weird command behavior on those systems
2. Long Term Support - DBRepair (BASH) version is entering Long Term Support (LTS) phase.
Active development focuses on the compiled C version for all platforms.
This existing BASH version continues to be primary tool until such time
it becomes production ready (perhaps 2027 timeframe).
- DBRepair.sh will be fully maintained and enhanced as needed by the community
until such time as it's retired to Legacy Archive status.
v1.16.00
1. MacOS App Dir - Older MacOS systems use /Applications. Newer MacOS systems use $HOME/Applications.
DBRepair now detects this and supports both locations.
v1.15.00
1. DSM 6 Start/Stop - Change how DSM 6 start/stop feature implemented
This accounts for changes in DSM 6.
2. Permissions/Owner - Some DSM users experience permission errors after running DBRepair
on Synology. Begin implementation of more robust handling for
restricted environments like DSM.
v1.14.00
1. Full-Text Search - Check and repair Full-Text Search (FTS) database indexes.
Damaged indexes often manifests as "500" internal errors. (Collections)
This release adds support for checking those indexes and rebuilding as needed.
( Full credit & thanks to @maxfield-allison for this great work )
Do not be surprised if your Blobs DB has damaged indexes and needs repair.
Even "Known Good" databases have shown FTS index problems.
v1.13.02
1. Autoincrement - Adjust statistics_bandwidth table per Plex engineering suggestion.
v1.13.01
1. Tag sort order - Github tags are not guaranteed to be numeric or in most-recent order.
This update sorts version tags numerically and in reverse order to accommodate github shortcoming.
v1.13.00
1. Binhex containers - Add support for updated 'supervisord' start/stop control.
Maintain support for legacy 'supervisor' start/stop control.
This will be removed in the next release
Update your container before updating DBRepair.
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
1. LC_ALL - When LC_ALL="", set LC_ALL=C (MacOS now needs this)
v1.10.02
1. Refactor UPDATE - QNAP BusyBox no longer support POSIX grep. Refactored.
v1.10.01
1. Minor cleanup - Cleanup purge/prune handling after merging commands into one.
v1.10.00
1. Refactor REPLACE - Processing of DB Replace was awkward.
List of available databases will now be printed in a menu
After selecting the desired DB, the candidate will be checked.
(Selection may be by list item # or date printed)
If valid (DB and Blobs) replacement will proceed normally.
v1.09.00
1. Purge command - Add 'purge' command to clean up all temporary transcoder and image files.
(usually found in /tmp)
v1.08.00
1. Linuxserver.io - Add support for new start/stop path.
Silently support both previous and new path start/stop mechanisms.
v1.07.00
1. Mac start/stop - DBRepair now supports start/stop from the menu.
Default configuration is for MacOS to tell you what it's doing (Haptic). Set to 0 for silence.
2. Code cleanup - Minor code cleanup / dead code removal.
v1.06.02
1. Bug fix - Fixed incorrect error handling when command line arguments not valid in manual configuration mode.
Fixed incorrect reporting of what was wrong in manual configuration mode.
v1.06.01
1. Manual SQLite path - You many now also specify the full path to "Plex SQLite". ( example: "/tmp/downloads/Plex SQLite")
DBRepair.sh will automatically figure out which form to use (path or directory)
--sqlite "/real/host/path/to/plexmediaserver/Directory"
--sqlite "/real/host/path/to/plexmediaserver/directory/Plex SQLite"
v1.06.00
1. Manual configuration - You may now run DBRepair from outside container environments.
This provides a method for running DBRepair when container healthcheck prevents it.
The directories to both:
a. Where Plex SQLite can be found: ( --sqlite "/real/host/path/to/plexmediaserver/Directory" )
b. Where the databases can be found: ( --databases "/real/host/path/to/Plugin Support/Databases" )
If used, these options MUST precede all other command line options
WARNING: The host MUST provide all standard commands AND support "stat -c" option. Bash commands will NOT autoconfigure.
2. "Exit" when scripted: The previously annoyance which required "exit" to be specified on the command line (scripted) has been fixed.
"exit" is no longer required in this use.
"exit" or "quit" is still required in interactive use.
3. Windows: DBRepair-Windows now supports 32 bit PMS on 64 bit Windows base systems. (Mixed mode operation)
v1.05.02
1. HOTIO image paths HOTIO images have again changed PMS executable location. This update
adds support for the lastest location.
v1.05.01
1. MacOS - Transcoder cache directory uses different location than default Plex.
Make "CacheDir" variable.
2. PPM files - Prune old PPM files just as other image files are pruned.
v1.05.00
1. Kubernetes support - Add support for Kubernetes (and also TrueNAS) containers.
v1.04.00
1. SNAP support - Add support for Plex Media Server SNAP package.
v1.03.00
1. New command: Purge - Removes old image files from the Trancoder cache.
These are normally removed during scheduled maintenance.
If scheduled maintenance doesn't complete all tasks, they won't get removed
and will build up.
This command allows you to remove them.
The default age is 30 days. Files older than 30 days will be purged.
2. Introduces Environment variable support (customizing) DBRepair operation.
- DBREPAIR_PAGESIZE: DBREPAIR_PAGESIZE=N (where N is a multiple of 1024, less equal 65536)
This sets the Plex SQLite database page_size during optimization operations.
It's most beneficial on ZFS filesystems to allow tuning to the Dataset size.
- DBREPAIR_CACHEAGE: DBREPAIR_CACHEAGE=N (where N is the max age, in Days) to retain when purging
older image files in the Cache/PhotoTranscoder directory.
This variable allows you to set the purge age (greater than "N" days).
v1.02.01
- Minor fix to logging. One line of output at the console was not present in the logfile
(this is important when diagnosing after connection-loss scenarios and DBRepair.sh was interrupted)
- Added documentation in README.md for using DBRepair with Synology DSM 7 Task Scheduler.
(Maintains app-armor compliance)
v1.02.00
- Provide menu option to ignore/honor "Duplicate" and "UNIQUE Constraint" errors during DB Repair,
and when importing data from other databases.
This is equivalent to the '-i' command line option but now can be used interactively.
- Fixed. ConfirmYesNo would print error message when it shouldn't.
- Fixed. Erroneous echo of your reply when responding to yes/no questions.
v1.01.04
- Missing IgnoreErrors (-i / -f) test when reimporting damaged DB with certain errors prevented repair
in all cases.
v1.01.02
- Correct updating when scripted versus interactive.
v1.01.00
- Adds ability to self download and install latest version of DBRepair.sh
- Slightly changes numbering style to accommodate future updates with new update capability.
- Thanks to @causefx for his contributions to this release
v1.0.13
- Improve HOTIO support. Allow both older and newer directory structure
v1.0.12
- Update HOTIO start/stop commands (re: #404461a)
v1.0.11
- Correct PMS stop problem. Stop operation would not wait until PMS actually stopped.
Now DBRepair waits up to 30 seconds for PMS to stop before issuing error
v1.0.10
- Correct bug when importing watch lists. Negative watch counts could occur.
This release corrects the issue.
v1.0.9
- When recovering a damaged database, it is sometimes necessary to ignore constraint errors resulting from damaged indexes.
This update provides command line options to support this:
1. -i or -f - Ignore DB check errors / Force acceptance.
2. -p - When importing viewstate from another DB, purge duplicate counts.
(Use with extreme caution).
Usage: DBRepair.sh [Options] commands
Example: DBRepair.sh -i -p start auto stop exit
v1.0.8
- Require root UID (super user).
Requiring root UID gives the script the privilege necessary to set the database ownership
and permissions to what they were when the tool started. Without this, the resultant database
might not be accessible by the Plex Media Server user.
Synology: This is achieved by typing 'sudo -su root' at the command line prompt
and entering your password.
QNAP: This is achieved by typing 'sudo -su admin' at the command line prompt
and entering your password.
Containers: Containers run as 'root' at the command line by default.
Other platforms will be similar to the above. Please try combinations of 'sudo'
and 'sudo --help' for more details.
- When successful, you'll see a '#' in the prompt (signifies 'root' level privilege)
v1.0.7
- Correct conditional test on Binhex container which prevented proper detection.
Redact v1.0.6
v1.0.6
- Correct detection conflict between Arch Linux native package and Binhex container.
v1.0.5
- Add Arch Linux Support
- Put system override processing in function
- Separate Quit (99) and Exit functionality to reduce confusion about temp file removal.
v1.0.4
- Correct Start/Stop problem on some hosts
v1.0.3
- Use POSIX free space calculation on all systems
# Introduction
DBRepair provides database repair and maintenance for the most common Plex Media Server database problems.
It is a simple menu-driven utility with a command line backend.
While it does correct the following errors, it can't correct 'data' errors with the individual records.
These type changes can only be performed by PMS.
## Situations and errors commonly seen include:
1. Searching is sluggish
2. Database is malformed / damaged / corrupted
3. Database has bloated from media addition or changes
4. Damaged indexes damaged
## Functions provided
The utility accepts command names.
Command names may be upper/lower case and may also be abbreviated (4 character minimum).
The following commands (or their number), listed in alphabetical order, are accepted as input.
AUTO(matic) - Automatically check, repair/optimize, and reindex the databases in one step.
CHEC(k) - Check the main and blob databases integrity
EXIT - Exit the utility
IMPO(rt) - Import viewstate / watch history from another database
REIN(dex) - Rebuild the database indexes
REPL(ace) - Replace the existing databases with a PMS-generated backup
SHOW - Show the log file
STAR(t) - Start PMS (not available on all platforms)
STOP - Stop PMS (not available on all platforms)
UNDO - UNDO the last operation
VACU(um) - Vacuum the databases
### The menu
The menu gives you the option to enter either a 'command number' or the 'command name/abbreviation'.
For clarity, each command's name is 'quoted'.
Database Repair Utility for Plex Media Server (_host_configuration_name_)
Version v1.0.0
Select
1 - 'stop' PMS (if available)
2 - 'automatic' database check, repair/optimize, and reindex in one step.
3 - 'check' database
4 - 'vacuum' database
5 - 'repair' / 'optimize' database
6 - 'reindex' database
7 - 'start' PMS (if available)
8 - 'import' viewstate (Watch history) from another PMS database
9 - 'replace' current database with newest usable backup copy (interactive)
10 - 'show' logfile
11 - 'status' of PMS (Stop/Run and databases)
12 - 'undo' - Undo last successful command
99 - exit
Enter command # -or- command name (4 char min) :
## Hosts currently supported
1. Apple (MacOS)
2. Arch Linux
3. ASUSTOR
4. Docker containers via 'docker exec' command (inside the running container environment)
- Plex,inc.
- Linuxserver.io
- BINHEX
- HOTIO
- Podman (libgpod)
5. Linux workstation & server
6. Netgear (OS5 Linux-based systems)
7. QNAP (QTS & QuTS)
8. Synology (DSM 6 & DSM 7)
9. Western Digital (OS5)
# Installation
Where to place the utility varies from host to host.
Please use this table as a reference.
```
Vendor | Shared folder name | Recommended directory
-------------------+---------------------+------------------------------------------
Apple | Downloads | ~/Downloads
Arch Linux | N/A | Anywhere
ASUSTOR | Public | /volume1/Public
binhex | N/A | Container root (adjacent /config)
Docker | N/A | Container root (adjacent /config)
Hotio | N/A | Container root (adjacent /config)
Linux (wkstn/svr) | N/A | Anywhere
Netgear (ReadyNAS) | "your_choice" | "/data/your_choice"
QNAP (QTS/QuTS) | Public | /share/Public
Synology (DSM 6) | Plex | /volume1/Plex (change volume as required)
Synology (DSM 7) | PlexMediaServer | /volume1/PlexMediaServer (change volume as required)
Western Digital | Public | /mnt/HD/HD_a2/Public (Does not support 'MyCloudHome' series)
```
### General installation and usage instructions
1. Open your browser to https://github.com/ChuckPa/DBRepair/releases/latest
2. Download the source code (tar.gz or ZIP) file
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.
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)
6. Elevate privilege level to root (sudo) if needed.
7. Extract the utility from the tar or zip file
8. 'cd' into the extraction directory
9. Give DBRepair.sh 'execute' permission (chmod +x)
10. Invoke ./DBRepair.sh
### EXAMPLE: To install & launch on Synology DSM 6
cd /volume1/Plex
sudo bash
tar xf DBRepair-x.y.z.tar.gz
cd DBRepair-x.y.z
chmod +x DBRepair.sh
./DBRepair.sh
### EXAMPLE: Using DBRepair inside containers (manual start/stop included)
#### (Select containers allow stopping/starting PMS from the menu. See menu for details)
sudo docker exec -it plex /bin/bash
# extract from downloaded version file name then cd into directory
tar xf DBRepair-1.0.0.tar.gz
cd DBRepair-1.0.0
chmod +x DBRepair.sh
./DBRepair.sh
```
### EXAMPLE: Using DBRepair on regular Linux native host (Workstation/Server)
```
sudo bash
cd /path/to/DBRepair.tar
tar xf DBRepair-1.0.0.tar.gz
cd DBRepair-1.0.0
chmod +x DBRepair.sh
./DBRepair.sh stop auto start exit
```
### EXAMPLE: Using DBRepair from the command line on MacOS (on the administrator account)
```
osascript -e 'quit app "Plex Media Server"'
cd ~/Downloads
tar xvf PlexDBRepai DBRepair-1.0.0.tar.gz
cd PlexDBRepai DBRepair-1.0.0
chmod +x DBRepair.sh
./DBRepair.sh
## Typical usage
This utility can only operate on PMS when PMS is in the stopped state.
If PMS is running when you startup the utility, it will tell you.
These examples
A. The most common usage will be the "Automatic" function.
Automatic mode is where DBRepair determines which steps are needed to make your database run optimally.
For most users, Automatic is equivalent to 'Check, Repair, Reindex'.
This repairs minor damage, vacuums out all the unused records, and rebuilds search indexes in one step.
B. Database is malformed (Backups of com.plexapp.plugins.library.db and com.plexap.plugins.library.blobs.db available)
Note: You may attempt "Repair" sequence
1. (3) Check - Confirm either main or blobs database is damaged
2. (9) Replace - Use the most recent valid backup -- OR -- (5) Repair. Check date/time stamps for best action.
-- If Replace fails, use Repair (5)
-- (Replace can fail if the database has been damaged for a long time.)
3. (6) Reindex - Generate new indexes so PMS doesn't need to at startup
4. (99) Exit
C. Database is malformed - No Backups
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.
3. (6) Reindex - Generate new indexes so PMS doesn't need to at startup
4. (99) Exit
C. Database sizes excessively large when compared to amount of media indexed (item count)
1. (3) Check - Make certain both databases are fully intact (repair if needed)
2. (4) Vacuum - Instruct SQLite to rebuild its tables and recover unused space.
3. (6) Reindex - Rebuild Indexes.
4. (99) Exit
D. User interface has become 'sluggish' as more media was added
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.
3. (6) Reindex - Rebuild Indexes.
4. Exit - (Option 9)
E. Undo
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
than you were before. In this case, UNDO then Repair. Undo can only undo the single most-recent action.
(Note: In a future release, you will be able to 'undo' every action taken until the DBs are in their original state)
Special considerations:
1. As stated above, this utilty requires PMS to be stopped in order to do what it does.
2. - This utility CAN sit at the menu prompt with PMS running.
- You did a few things and want to check BEFORE exiting the utility
- If you don't like how it worked out,
-- STOP PMS
-- UNDO the last action and do something else
-- OR do more things to the databases
3. When satisfied, Exit the utility.
- There is no harm in keeping the database temp files (except for space used)
- ALL database temps are named with date-time stamps in the name to avoid confusion.
4. The Logfile ('show' command) shows all actions performed WITH timestamp so you can locate intermediate databases
if desired for special / manual recovery cases.
## Scripting support
Certain platforms don't provide for each command line access.
To support those products, this utility can be operated by adding command line arguments.
Another use of this feature is to automate Plex Database maintenance
( Stop Plex, Run this sequence, Start Plex ) at a time when the server isn't busy
The command line arguments are the same as if typing at the menu.
Example: ./DBRepair.sh stop auto start exit
This executes: Stop PMS, Automatic (Check, Repair, Reindex), Start PMS, and Exit commands
## Exiting
When exiting, you will be asked whether to keep the interim temp files created during this session.
If you've encountered any difficulties or aren't sure what to do, don't delete them.
You'll be able to ask in the Plex forums about what to do. Be prepared to present the log file to them.
## Sample interactive session
This is a typical manual session if you aren't sure what to do and want the tool to decide.
```
bash-4.4# #=======================================================================================================
bash-4.4# ./DBRepair.sh
Database Repair Utility for Plex Media Server (Synology (DSM 7))
Version v1.0.0
Select
1 - 'stop' - Stop PMS
2 - 'automatic' - database check, repair/optimize, and reindex in one step.
3 - 'check' - Perform integrity check of database
4 - 'vacuum' - Remove empty space from database
5 - 'repair' - Repair/Optimize databases
6 - 'reindex' - Rebuild database database indexes
7 - 'start' - Start PMS
8 - 'import' - Import watch history from another database independent of Plex. (risky)
9 - 'replace' - Replace current databases with newest usable backup copy (interactive)
10 - 'show' - Show logfile
11 - 'status' - Report status of PMS (run-state and databases)
12 - 'undo' - Undo last successful command
99 - exit
Enter command # -or- command name (4 char min) : 1
Stopping PMS.
Stopped PMS.
Select
1 - 'stop' - Stop PMS
2 - 'automatic' - database check, repair/optimize, and reindex in one step.
3 - 'check' - Perform integrity check of database
4 - 'vacuum' - Remove empty space from database
5 - 'repair' - Repair/Optimize databases
6 - 'reindex' - Rebuild database database indexes
7 - 'start' - Start PMS
8 - 'import' - Import watch history from another database independent of Plex. (risky)
9 - 'replace' - Replace current databases with newest usable backup copy (interactive)
10 - 'show' - Show logfile
11 - 'status' - Report status of PMS (run-state and databases)
12 - 'undo' - Undo last successful command
99 - exit
Enter command # -or- command name (4 char min) : auto
Checking the PMS databases
Check complete. PMS main database is OK.
Check complete. PMS blobs database is OK.
Exporting current databases using timestamp: 2023-02-25_16.15.11
Exporting Main DB
Exporting Blobs DB
Successfully exported the main and blobs databases. Proceeding to import into new databases.
Importing Main DB.
Importing Blobs DB.
Successfully imported data from SQL files.
Verifying databases integrity after importing.
Verification complete. PMS main database is OK.
Verification complete. PMS blobs database is OK.
Saving current databases with '-BKUP-2023-02-25_16.15.11'
Making imported databases active
Import complete. Please check your library settings and contents for completeness.
Recommend: Scan Files and Refresh all metadata for each library section.
Backing up of databases
Backup current databases with '-BKUP-2023-02-25_16.20.41' timestamp.
Reindexing main database
Reindexing main database successful.
Reindexing blobs database
Reindexing blobs database successful.
Reindex complete.
Automatic Check,Repair/optimize,Index successful.
Select
1 - 'stop' PMS
2 - 'automatic' database check, repair/optimize, and reindex in one step.
3 - 'check' database
4 - 'vacuum' database
5 - 'repair' / 'optimize' database
6 - 'reindex' database
7 - 'start' PMS
8 - 'import' viewstate (Watch history) from another PMS database
9 - 'replace' current database with newest usable backup copy (interactive)
10 - 'show' logfile
11 - 'status' of PMS (Stop/Run and databases)
12 - 'undo' - Undo last successful command
99 - exit
Enter command # -or- command name (4 char min) : start
Starting PMS.
Started PMS
Select
1 - 'stop' PMS
2 - 'automatic' database check, repair/optimize, and reindex in one step.
3 - 'check' database
4 - 'vacuum' database
5 - 'repair' / 'optimize' database
6 - 'reindex' database
7 - 'start' PMS
8 - 'import' viewstate (Watch history) from another PMS database
9 - 'replace' current database with newest usable backup copy (interactive)
10 - 'show' logfile
11 - 'status' of PMS (Stop/Run and databases)
12 - 'undo' - Undo last successful command
99 - exit
Enter command # -or- command name (4 char min) : stat
Status report: Sat Feb 25 04:38:50 PM EST 2023
PMS is running.
Databases are OK.
Select
1 - 'stop' PMS
2 - 'automatic' database check, repair/optimize, and reindex in one step.
3 - 'check' database
4 - 'vacuum' database
5 - 'repair' / 'optimize' database
6 - 'reindex' database
7 - 'start' PMS
8 - 'import' viewstate (Watch history) from another PMS database
9 - 'replace' current database with newest usable backup copy (interactive)
10 - 'show' logfile
11 - 'status' of PMS (Stop/Run and databases)
12 - 'undo' - Undo last successful command
99 - exit
Enter command # -or- command name (4 char min) : exit
Ok to remove temporary databases/workfiles for this session? (Y/N) ? y
Are you sure (Y/N) ? y
Deleting all temporary work files.
bash-4.4#
```
## Sample (typical) scripted session (e.g. via 'cron')
```
root@lizum:/sata/plex/Plex Media Server/Plug-in Support/Databases# ./DBRepair.sh stop check auto start exit
Database Repair Utility for Plex Media Server (Ubuntu 20.04.5 LTS)
Version v1.0.0
[2023-03-05 18.53.49] Stopping PMS.
[2023-03-05 18.53.49] Stopped PMS.
[2023-03-05 18.53.49] Checking the PMS databases
[2023-03-05 18.54.22] Check complete. PMS main database is OK.
[2023-03-05 18.54.22] Check complete. PMS blobs database is OK.
[2023-03-05 18.54.22] Automatic Check,Repair,Index started.
[2023-03-05 18.54.22]
[2023-03-05 18.54.22] Checking the PMS databases
[2023-03-05 18.54.56] Check complete. PMS main database is OK.
[2023-03-05 18.54.56] Check complete. PMS blobs database is OK.
[2023-03-05 18.54.56]
[2023-03-05 18.54.56] Exporting current databases using timestamp: 2023-03-05_18.54.22
[2023-03-05 18.54.56] Exporting Main DB
[2023-03-05 18.55.30] Exporting Blobs DB
[2023-03-05 18.55.33] Successfully exported the main and blobs databases. Proceeding to import into new databases.
[2023-03-05 18.55.33] Importing Main DB.
[2023-03-05 18.57.04] Importing Blobs DB.
[2023-03-05 18.57.05] Successfully imported SQL data.
[2023-03-05 18.57.05] Verifying databases integrity after importing.
[2023-03-05 18.57.40] Verification complete. PMS main database is OK.
[2023-03-05 18.57.40] Verification complete. PMS blobs database is OK.
[2023-03-05 18.57.40] Saving current databases with '-BACKUP-2023-03-05_18.54.22'
[2023-03-05 18.57.40] Making repaired databases active
[2023-03-05 18.57.40] Repair complete. Please check your library settings and contents for completeness.
[2023-03-05 18.57.40] Recommend: Scan Files and Refresh all metadata for each library section.
[2023-03-05 18.57.40]
[2023-03-05 18.57.40] Backing up of databases
[2023-03-05 18.57.40] Backup current databases with '-BACKUP-2023-03-05_18.57.40' timestamp.
[2023-03-05 18.57.41] Reindexing main database
[2023-03-05 18.58.17] Reindexing main database successful.
[2023-03-05 18.58.17] Reindexing blobs database
[2023-03-05 18.58.17] Reindexing blobs database successful.
[2023-03-05 18.58.17] Reindex complete.
[2023-03-05 18.58.17] Automatic Check, Repair/optimize, & Index successful.
[2023-03-05 18.58.17] Starting PMS.
[2023-03-05 18.58.17] Started PMS
root@lizum:/sata/plex/Plex Media Server/Plug-in Support/Databases#
```
======================
```
```
## Logfile
The logfile (DBRepair.log) keeps track of all commands issues and their status (PASS/FAIL) with timestamp.
This can be useful when recovering from an interrupted session because temporary files are timestamped.
```
2023-02-25 16.14.39 - ============================================================
2023-02-25 16.14.39 - Session start: Host is Synology (DSM 7)
2023-02-25 16.14.56 - StopPMS - PASS
2023-02-25 16.16.06 - Check - Check com.plexapp.plugins.library.db - PASS
2023-02-25 16.16.06 - Check - Check com.plexapp.plugins.library.blobs.db - PASS
2023-02-25 16.16.06 - Check - PASS
2023-02-25 16.17.20 - Repair - Export databases - PASS
2023-02-25 16.19.52 - Repair - Import - PASS
2023-02-25 16.20.41 - Repair - Verify main database - PASS (Size: 399MB/399MB).
2023-02-25 16.20.41 - Repair - Verify blobs database - PASS (Size: 1MB/1MB).
2023-02-25 16.20.41 - Repair - Move files - PASS
2023-02-25 16.20.41 - Repair - PASS
2023-02-25 16.20.41 - Repair - PASS
2023-02-25 16.20.46 - Reindex - MakeBackup com.plexapp.plugins.library.db - PASS
2023-02-25 16.20.46 - Reindex - MakeBackup com.plexapp.plugins.library.blobs.db - PASS
2023-02-25 16.20.46 - Reindex - MakeBackup - PASS
2023-02-25 16.21.34 - Reindex - Reindex: com.plexapp.plugins.library.db - PASS
2023-02-25 16.21.35 - Reindex - Reindex: com.plexapp.plugins.library.blobs.db - PASS
2023-02-25 16.21.35 - Reindex - PASS
2023-02-25 16.21.35 - Reindex - PASS
2023-02-25 16.21.35 - Auto - PASS
2023-02-25 16.38.35 - StartPMS - PASS
2023-02-25 16.38.57 - Exit - Delete temp files.
2023-02-25 16.38.58 - Session end.
2023-02-25 16.38.58 - ============================================================
2023-02-25 16.40.10 - ============================================================
2023-02-25 16.40.10 - Session start: Host is Synology (DSM 7)
2023-02-25 16.40.27 - StopPMS - PASS
2023-02-25 16.42.23 - Check - Check com.plexapp.plugins.library.db - PASS
2023-02-25 16.42.24 - Check - Check com.plexapp.plugins.library.blobs.db - PASS
2023-02-25 16.42.24 - Check - PASS
2023-02-25 16.43.39 - Repair - Export databases - PASS
2023-02-25 16.46.10 - Repair - Import - PASS
2023-02-25 16.46.58 - Repair - Verify main database - PASS (Size: 399MB/399MB).
2023-02-25 16.46.58 - Repair - Verify blobs database - PASS (Size: 1MB/1MB).
2023-02-25 16.46.59 - Repair - Move files - PASS
2023-02-25 16.46.59 - Repair - PASS
2023-02-25 16.46.59 - Repair - PASS
2023-02-25 16.47.03 - Reindex - MakeBackup com.plexapp.plugins.library.db - PASS
2023-02-25 16.47.03 - Reindex - MakeBackup com.plexapp.plugins.library.blobs.db - PASS
2023-02-25 16.47.03 - Reindex - MakeBackup - PASS
2023-02-25 16.47.52 - Reindex - Reindex: com.plexapp.plugins.library.db - PASS
2023-02-25 16.47.52 - Reindex - Reindex: com.plexapp.plugins.library.blobs.db - PASS
2023-02-25 16.47.52 - Reindex - PASS
2023-02-25 16.47.52 - Reindex - PASS
2023-02-25 16.47.52 - Auto - PASS
2023-02-25 16.48.04 - StartPMS - PASS
2023-02-25 16.48.05 - Exit - Delete temp files.
2023-02-25 16.48.05 - Session end.
```
# Command Reference:
### Automatic
Automatic provides automated processing of most checks and repairs. (Check, Repair/Resequence, Index)
In its current state, it will not automatically replace a damaged database from a backup (future)
It will not stop PMS as not all systems support stopping PMS from within this tool.
### Check
Checks the integrity of the Plex main and blobs databases.
### Exit
Exits the utility and removes all temporary database files created during processing.
To save all intermediate databases, use the 'Quit' command.
### Import
Imports (raw) watch history from another PMS database without ability to check validity
( This can have side effects of "negative watch count" being displayed. Caution is advised. )
### Reindex
Rebuilds the database indexes after an import, repair, or replace operation.
These indexes are used by PMS for searching (both internally and your typed searches)
### Repair
Extracts/recovers all the usable data fron the existing databases into text (SQL ascii) form.
Repair then creates new SQLite-valid databases from the extracted/recovered data.
The side effect of this process is a fully defragmented database (optimal for Plex use).
100% validity/usability by Plex is not guaranteed as the tool cannot validate each individual
record contained in the database. It can only validate at the SQLite level.
In most cases, Repair is the preferred option as the records extracted are only those SQLite deemed valid.
### Replace
Looks through the list of available PMS backups.
Starting with the most recent PMS backup,
1. Check the both db files
2. If valid, offer as a replacement choice
3. If accepted (Y/N question) then use as the replacement
else advance to the next available backup
4. Upon completion, validate one final time.
### Quit
Exits the utility but leaves the temporary databases intact (useful for making exhaustive backups)
### Show
Shows the activity log. The activity log is date/time stamped of all activity.
### Start
On platform environments which support it, and when invoked by the 'root' user, the tool can start PMS.
If not the 'root' user or on a platform which doesn't support it, "Not available" will be indicated.
### Stop
On platform environments which support it, and when invoked by the 'root' user, the tool can stop PMS.
If not the 'root' user or on a platform which doesn't support it, "Not available" will be indicated.
PMS must be in the stopped state in order to operate on the database files.
### Undo
Undo allows you to "Undo" the last Import, Repair, Replace, or Vacuum command.
At present, it only allows the ONE most recent operation.
(Future will support undoing more actions)
### Vacuum
Instructs SQLite to remove the empty/deleted records and gaps from the databases.
This is most beneficial after deleting whole library sections.
###
+38
View File
@@ -0,0 +1,38 @@
DBRepair Release Notes
v26.10.00
* Initial Public Release
- Version 26.10.00 is the DBRepair initial public release.
- Completely rewritten from scratch using "C" programming language.
- No external dependencies (Plex SQLite not required).
- While having been thoroughly tested throughout its development, I
do expect the typical "small stuff".
- If you do find something amiss, please file an issue and I'll
resolve it ASAP.
* Databases
- DBRepair now contains database knowledge for versions 1.18.2 and above.
(255 PMS builds)
* Database Repairs & Cleanup
- DBRepair is now intelligent, and a lot faster, than the old DBRepair script
ever could be.
- It can do things the old DBRepair never could.
- New commands, better analysis and repairs,
DBRepair is "all grown up" (ha ha)
* Full Wiki
- DBRepair now has a full Wiki (https://github.com/ChuckPa/DBRepair/wiki)
Everything is documented in it.
Please pointout any typos or errors.
* Thanks
- Special thanks go to @ukdtom for keeping me
on the right path throughout these past six months.
### Questions ??
Please don't hesitate to ask.
-209
View File
@@ -1,209 +0,0 @@
@echo off
REM DBRepair.bat - Database maintenance / rebuild tool for Windows.
REM
REM This tool currently works as a "full shot" service.
REM - everything is done without need to interact.
REM
REM -- WARNNING -- WARNING -- WARNING
REM
REM This is stable working software but not "Released" software. Development will continue.
setlocal enabledelayedexpansion
echo.
echo NOTE: This script is being replaced with the PowerShell script DBRepair-Windows.ps1,
echo which aims to better emulate DBRepair.sh (more options, interactive mode, etc).
echo Consider moving over to the new script.
echo.
REM ### Create Timestamp
set Hour=%time:~0,2%
set Min=%time:~3,2%
set Sec=%time:~6,2%
REM ## Remove spaces from Hour ##
set Hour=%Hour: =%
REM ## Set TimeStamp ##
set TimeStamp=%Hour%-%Min%-%Sec%
REM Find PMS database location
for /F "tokens=2* skip=2" %%a in ('REG.EXE QUERY "HKCU\Software\Plex, Inc.\Plex Media Server" /v "LocalAppDataPath" 2^> nul') do set "PlexData=%%b\Plex Media Server\Plug-in Support\Databases"
if not exist "%PlexData%" (
if exist "%LOCALAPPDATA%\Plex Media Server\Plug-in Support\Databases" (
set "PlexData=%LOCALAPPDATA%\Plex Media Server\Plug-in Support\Databases"
) else (
echo Could not determine Plex database path.
echo Normally %LOCALAPPDATA%\Plex Media Server\Plug-in Support\Databases
echo.
goto :EOF
)
)
REM Find PMS installation location.
for /F "tokens=2* skip=2" %%a in ('REG.EXE QUERY "HKCU\Software\Plex, Inc.\Plex Media Server" /v "InstallFolder" 2^> nul') do set "PlexSQL=%%b\Plex SQLite.exe"
if not exist "%PlexSQL%" (
REM InstallFolder might be set under HKLM, not HKCU
for /F "tokens=2* skip=2" %%a in ('REG.EXE QUERY "HKLM\Software\Plex, Inc.\Plex Media Server" /v "InstallFolder" 2^> nul') do set "PlexSQL=%%b\Plex SQLite.exe"
)
REM If InstallFolder wasn't set, or the resulting file doesn't exist, iterate through the
REM PROGRAMFILES variables looking for it. If we still can't find it, ask the user to provide it.
if not exist "%PlexSQL%" (
if exist "%PROGRAMFILES%\Plex\Plex Media Server\Plex SQLite.exe" (
set "PlexSQL=%PROGRAMFILES%\Plex\Plex Media Server\Plex SQLite.exe"
) else (
if exist "%PROGRAMFILES(X86)%\Plex\Plex Media Server\Plex SQLite.exe" (
echo NOTE: 32-bit version of PMS detected on a 64-bit version of Windows. Updating to the 64-bit release of PMS is recommended.
set "PlexSQL=%PROGRAMFILES(X86)%\Plex\Plex Media Server\Plex SQLite.exe"
) else (
echo Could not determine SQLite path. Please provide it below
echo Normally %PROGRAMFILES%\Plex\Plex Media Server\Plex SQLite.exe
echo.
REM Last ditch effort, ask the user for the full path to Plex SQLite.exe
set /p "PlexSQL=Path to Plex SQLite.exe: "
if not exist "!PlexSQL!" (
echo "!PlexSQL!" could not be found. Cannot continue.
goto :EOF
)
)
)
)
REM Set temporary file locations
set "DBtmp=%PlexData%\dbtmp"
set "TmpFile=%DBtmp%\results.tmp"
REM Time now.
echo %time% -- ====== Session begins. (%date%) ======
echo %time% -- ====== Session begins. (%date%) ====== >> "%PlexData%\DBRepair.log"
REM Make certain Plex is NOT running.
tasklist | find /I "Plex Media Server.exe" >NUL
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. >> "%PlexData%\DBRepair.log"
exit /B 1
)
cd "%PlexData%"
md "%PlexData%\dbtmp" 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 >> "%PlexData%\DBRepair.log"
echo .dump | "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db" > "%DBtmp%\library.sql_%TimeStamp%"
if not %ERRORLEVEL%==0 (
echo %time% -- ERROR: Cannot export Main DB. Aborting.
exit /b 2
)
echo %time% -- Exporting Blobs DB
echo %time% -- Exporting Blobs DB >> "%PlexData%\DBRepair.log"
echo .dump | "%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db" > "%DBtmp%\blobs.sql_%TimeStamp%"
if not %ERRORLEVEL%==0 (
echo %time% -- ERROR: Cannot export Blobs DB. Aborting.
)
REM Now create new databases from SQL statements
echo %time% -- Exporting Complete.
echo %time% -- Exporting Complete. >> "%PlexData%\DBRepair.log"
echo %time% -- Creating Main DB
echo %time% -- Creating Main DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" < "%DBtmp%\library.sql_%TimeStamp%"
if not %ERRORLEVEL%==0 (
echo %time% -- ERROR: Cannot create Main DB. Aborting.
echo %time% -- ERROR: Cannot create Main DB. Aborting. >> "%PlexData%\DBRepair.log"
exit /b 3
)
echo %time% -- Verifying Main DB
echo %time% -- Verifying Main DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" "PRAGMA integrity_check(1)" >"%TmpFile%"
set /p Result= < "%TmpFile%"
del "%TmpFile%"
echo %time% -- Main DB verification check is: %Result%
echo %time% -- Main DB verification check is: %Result% >> "%PlexData%\DBRepair.log"
if not "%Result%" == "ok" (
echo %time% -- ERROR: Main DB verification failed. Exiting.
echo %time% -- ERROR: Main DB verification failed. Exiting. >> "%PlexData%\DBRepair.log"
exit /B 4
)
echo %time% -- Main DB verification successful.
echo %time% -- Main DB verification successful. >> "%PlexData%\DBRepair.log"
echo %time% -- Creating Blobs DB
echo %time% -- Creating Blobs DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" < "%DBtmp%\blobs.sql_%TimeStamp%"
if not %ERRORLEVEL%==0 (
echo %time% -- ERROR: Cannot create Blobs DB. Aborting.
echo %time% -- ERROR: Cannot create Blobs DB. Aborting. >> "%PlexData%\DBRepair.log"
exit /b 5
)
echo %time% -- Verifying Blobs DB
echo %time% -- Verifying Blobs DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" "PRAGMA integrity_check(1)" > "%TmpFile%"
set /p Result= < "%TmpFile%"
del "%TmpFile%"
echo %time% -- Blobs DB verification check is: %Result%
echo %time% -- Blobs DB verification check is: %Result% >> "%PlexData%\DBRepair.log"
if not "%Result%" == "ok" (
echo %time% -- ERROR: Blobs DB verification failed. Exiting.
echo %time% -- ERROR: Blobs DB verification failed. Exiting. >> "%PlexData%\DBRepair.log"
exit /B 6
)
echo %time% -- Blobs DB verification successful.
echo %time% -- Blobs DB verification successful. >> "%PlexData%\DBRepair.log"
echo %time% -- Import and verification complete.
echo %time% -- Import and verification complete. >> "%PlexData%\DBRepair.log"
REM Import complete, now reindex
echo %time% -- Reindexing Main DB
echo %time% -- Reindexing Main DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.db_%TimeStamp%" "REINDEX;"
echo %time% -- Reindexing Blobs DB
echo %time% -- Reindexing Blobs DB >> "%PlexData%\DBRepair.log"
"%PlexSQL%" "%PlexData%\com.plexapp.plugins.library.blobs.db_%TimeStamp%" "REINDEX;"
REM Index complete, make active
echo %time% -- Reindexing complete.
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 >> "%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_%TimeStamp%" "%PlexData%\com.plexapp.plugins.library.db"
move "%PlexData%\com.plexapp.plugins.library.blobs.db" "%PlexData%\dbtmp\com.plexapp.plugins.library.blobs.db_%TimeStamp%"
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. >> "%PlexData%\DBRepair.log"
echo %time% -- ====== Session completed. ======
echo %time% -- ====== Session completed. ====== >> "%PlexData%\DBRepair.log"
exit /b
REM #### Functions
REM Output - Write text to the console and the log file
:Output
echo %time% %~1
echo %time% %~1 >> "%PlexData%\DBRepair.log"
exit /B
-904
View File
@@ -1,904 +0,0 @@
#########################################################################
# Database check and repair utility script for Plex Media Server #
# #
#########################################################################
$DBRepairVersion = 'v1.01.02'
class DBRepair {
[DBRepairOptions] $Options
[string] $PlexDBDir # Path to Plex's Databases directory
[string] $PlexCache # Path to the PhotoTranscoder directory
[string] $PlexSQL # Path to 'Plex SQLite.exe'
[string] $Timestamp # Timestamp used for temporary database files
[string] $LogFile # Path of our log file
[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"
DBRepair($Arguments, $Version) {
$this.Options = [DBRepairOptions]::new()
$this.Version = $Version
$this.IsError = $false
$Commands = $this.PreprocessArgs($Arguments)
if ($null -eq $Commands) {
return
}
if (!$this.Init()) {
Write-Host "Unable to initialize script, cannot continue."
return
}
$this.PrintHeader($true)
$this.MainLoop($Commands)
}
[void] PrintHeader([boolean] $WriteToLog) {
$OS = [System.Environment]::OSVersion.Version
if ($WriteToLog) {
$this.WriteLog("============================================================")
$this.WriteLog("Session start: Host is Windows $($OS.Major) (Build $($OS.Build))")
}
Write-Host "`n"
Write-Host " Database Repair Utility for Plex Media Server (Windows $($OS.Major), Build $($OS.Build))"
Write-Host " Version $($this.Version) "
Write-Host
}
[void] PrintHelp() {
# -Help doesn't write to the log, since our log file path isn't set.
$this.PrintHeader($false)
Write-Host "When run without arguments, starts an interactive session that displays available options"
Write-Host "and lets you select the operations you want to perform. Or, to run tasks automatically,"
Write-Host "provide them directly to the script, e.g. '.\DBRepair-Windows.ps1 Stop Prune Start Exit'"
Write-Host
$this.PrintOptions("Main Options")
Write-Host
Write-Host "Extra Options - These can only be specified once (last one wins)"
Write-Host
Write-Host " -CacheAge [int] - The date cutoff for pruned images. Defaults to pruning images over 30"
Write-Host " days old."
Write-Host
}
[void] PrintMenu() {
$this.PrintOptions("Select")
}
[void] PrintOptions([string]$Header) {
# NOTE: While Windows only supports a subset of DBRepair.sh's features, keep the command
# numbers the same as we attempt to reach feature parity
Write-Host
Write-Host $Header
Write-Host
Write-Host " 1 - 'stop' - Stop PMS."
Write-Host " 2 - 'automatic' - Check, Repair/Optimize, and Reindex Database in one step."
Write-Host
Write-Host " 7 - 'start' - Start PMS"
Write-Host
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 " 98 - 'quit' - Quit immediately. Keep all temporary files."
Write-Host " 99 'exit' - Exit with cleanup options."
Write-Host
Write-Host " 'menu x' - Show this menu in interactive mode, where x is on/off/yes/no"
}
# Do initial parsing of arguments that aren't part of the loop, returning
# the list of arguments that _should_ be processed in the loop.
#
# E.g. given "Stop Prune CacheAge 20 Start", this function will set the CacheAge
# to 20, and return "Stop Prune Start"
[System.Collections.ArrayList] PreprocessArgs([string[]] $Arguments) {
$FinalArgs = [System.Collections.ArrayList]::new()
for ($i = 0; $i -lt $Arguments.Count; ++$i) {
switch -Regex ($Arguments[$i]) {
'^-?(H(elp)?|\?)$' {
if ($Arguments.Count -gt 1) {
Write-Warning "Found -Help, ignoring extra arguments"
}
$this.PrintHelp()
return $null
}
'^-?CacheAge$' {
if ($i -eq $Arguments.Count - 1) {
Write-Warning "Found -CacheAge argument, but no value. Using default of 30 days"
Break
}
++$i
$Age = $Arguments[$i]
if (!($Age -match "^\d+$")) {
Write-Warning "Invalid -CacheAge value '$Age'. Using default of 30 days"
Break
}
$this.Options.CacheAge = [int]$Age
}
Default { $FinalArgs.Add($_) }
}
}
return $FinalArgs
}
# Setup variables required for this utility to work.
[bool] Init() {
$this.Timestamp = Get-Date -Format HH-mm-ss
$AppData = $this.GetAppDataDir()
$Success = $this.GetPlexDBDir($AppData) -and $this.GetPlexSQL() -and $this.GetPhotoTranscoderDir($AppData)
if ($Success) {
$this.LogFile = Join-Path $this.PlexDBDir -ChildPath "DBRepair.log"
}
return $Success
}
# Core routine that loops over all provided commands and executes them in order.
[void] MainLoop([System.Collections.ArrayList] $Arguments) {
$this.Options.Scripted = $Arguments.Count -ne 0
$i = 0
$Argc = $Arguments.Count
$NullInput = 0
$EOFExit = $false
while ($true) {
$Choice = $null
if ($this.Options.Scripted) {
if ($i -eq $Argc) {
$Choice = "exit"
} else {
$Choice = $Arguments[$i++]
}
} else {
if ($this.Options.ShowMenu) {
$this.PrintMenu()
}
Write-Host
$Choice = Read-Host "Enter command # -or- command name (4 char min)"
if ($Choice -eq "") {
++$NullInput
if ($NullInput -eq 5) {
$this.Output("Unexpected EOF / End of command line options. Exiting. Keeping temp files. ")
$Choice = "exit"
$EOFExit = $true
} else {
if ($NullInput -eq 4) {
Write-Warning "Next empty command exits as EOF. "
}
continue
}
} else {
$NullInput = 0
}
}
# Update timestamp
$this.Timestamp = Get-Date -Format 'yyyy-MM-dd_HH.mm.ss'
switch -Regex ($Choice) {
"^(1|stop)$" { $this.DoStop() }
"^(2|autom?a?t?i?c?)$" {
$this.SetStage("Auto")
$this.IsError = !$this.RunAutomaticDatabaseMaintenance()
}
"^(7|start?)$" { $this.StartPMS() }
"^(21|(prune?|remov?e?))$" {
$this.SetStage("Prune")
$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)
}
"^(98|quit)$" {
$this.Output("Retaining all temporary work files.")
$this.WriteLog("Exit - Retain temp files.")
$this.WriteEnd()
return
}
"^(99|exit)$" {
if ($EOFExit) {
$this.Output("Unexpected exit command. Keeping all temporary work files.")
$this.WriteLog("EOFExit - Retain temp files.")
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.WriteEnd()
return
}
"^menu\b" {
$Match = $Choice -match "^menu\s+(on|off|yes|no)"
if (!$Match) {
$this.OutputWarn("Invalid 'menu' format. Expected 'menu on/off/yes/no', got '$Choice'")
Break
}
$TurnOn = ($Matches.1 -eq 'on') -or ($Matches.1 -eq 'yes');
$this.Options.ShowMenu = $TurnOn
if (!$TurnOn) {
Write-Host "Menu off: Reenable with 'menu on' command"
}
}
Default {
$this.OutputWarn("Unknown Command: '$Choice'")
$this.WriteLog("Unknown command: '$Choice'")
}
}
}
}
# Attempt to stop Plex Media Server if it's running
[void] DoStop() {
$this.WriteLog("Stop - START")
$PMS = $this.GetPMS()
if ($null -eq $PMS) {
$this.Output("PMS already stopped.")
return
}
$this.Output("Stopping PMS.")
# 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
# PMS to close nicely, and bail if that doesn't work.
$ErrorText = $null
Invoke-Expression "taskkill /im ""Plex Media Server.exe""" 2>$null -ErrorVariable ErrorText
if ($ErrorText) {
$this.WriteOutputLogWarn("Failed to send terminate signal to PMS, please stop manually.")
$this.WriteOutputLogWarn($ErrorText -join "`n")
return
}
$PMS.WaitForExit(30000) *>$null # Wait at most 30 seconds for PMS to close. If it still hasn't by then, bail.
if ($PMS.HasExited) {
$this.WriteLog("Stop - PASS")
$this.Output("Stopped PMS.")
return
}
$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
[void] StartPMS() {
$this.WriteLog("Start - START")
if ($this.PMSRunning()) {
$this.Output("Start not needed. PMS is running.")
$this.WriteLog("Start - PASS - PMS is already running")
return
}
$PMS = Join-Path (Split-Path -Parent $this.PlexSQL) -ChildPath "Plex Media Server.exe"
try {
Start-Process $PMS -EA Stop
$this.Output("Started PMS")
$this.WriteLog("Start - PASS")
} catch {
$Err = $Error -join "`n"
$this.OutputWarn("Could not start PMS: $Err")
$Error.Clear()
}
}
# All-in-one database utility - Repair/Check/Reindex
[bool] RunAutomaticDatabaseMaintenance() {
$this.Output("Automatic Check,Repair,Index started.")
$this.WriteLog($this.StageLog("START"))
if ($this.PMSRunning()) {
$this.WriteLog($this.StageLog("FAIL - PMS running"))
$this.OutputWarn("Unable to run automatic sequence. PMS is running. Please stop PlexMediaServer.")
return $false
}
# Create temporary backup directory
$DBTemp = Join-Path $this.PlexDBDir -ChildPath "dbtmp"
if (!$this.DirExists($DBTemp)) {
$TempDirError = $null
New-Item -Path $DBTemp -ItemType "directory" -ErrorVariable tempDirError *>$null
if ($TempDirError) {
$this.ExitDBMaintenance("Unable to create temporary database directory", $false)
return $false
}
}
$this.Output("Exporting Main DB")
$MainDBPath = Join-Path $this.PlexDBDir -ChildPath $this.MainDB
$MainDBSQL = Join-Path $DBTemp -ChildPath "library.sql_$($this.TimeStamp)"
if (!$this.FileExists($MainDBPath)) {
$this.ExitDBMaintenance("Could not find $($this.MainDB) in database directory", $false)
return $false
}
if (!$this.ExportPlexDB($MainDBPath, $MainDBSQL)) { return $false }
$this.Output("Exporting Blobs DB")
$BlobsDBPath = Join-Path $this.PlexDBDir -ChildPath $this.BlobsDB
$BlobsDBSQL = Join-Path $DBTemp -ChildPath "blobs.sql_$($this.Timestamp)"
if (!$this.FileExists($BlobsDBPath)) {
$this.ExitDBMaintenance("Could not find $($this.BlobsDB) in database directory", $false)
return $false
}
if (!$this.ExportPlexDB($BlobsDBPath, $BlobsDBSQL)) { return $false }
$this.Output("Successfully exported the main and blobs databases. Proceeding to import into new database.")
$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.")
$MainDBImport = Join-Path $this.PlexDBDir -ChildPath "$($this.MainDB)_$($this.Timestamp)"
if (!$this.ImportPlexDB($MainDBSQL, $MainDBImport)) { return $false }
$this.Output("Importing Blobs DB.")
$BlobsDBImport = Join-Path $this.PlexDBDir -ChildPath "$($this.BlobsDB)_$($this.Timestamp)"
if (!$this.ImportPlexDB($BlobsDBSQL, $BlobsDBImport)) { return $false }
$this.Output("Successfully imported databases.")
$this.WriteLog("Repair - Import - PASS")
$this.Output("Verifying databases integrity after importing.")
if (!$this.IntegrityCheck($MainDBImport, "Main")) { return $false }
$this.Output("Verification complete. PMS main database is OK.")
$this.WriteLog("Repair - Verify main database - PASS")
if (!$this.IntegrityCheck($BlobsDBImport, "Blobs")) { return $false }
$this.Output("Verification complete. PMS blobs database is OK.")
$this.WriteLog("Repair - Verify blobs database - PASS")
if (!$this.CheckPMS("import")) { return $false }
# Import complete, now reindex
$this.WriteOutputLog("Reindexing Main DB")
if (!$this.RunSQLCommand("""$MainDBImport"" ""REINDEX;""", "Failed to reindex Main DB")) { return $false }
$this.WriteOutputLog("Reindexing Blobs DB")
if (!$this.RunSQLCommand("""$BlobsDBImport"" ""REINDEX;""", "Failed to reindex Blobs DB")) { return $false }
$this.WriteOutputLog("Reindexing complete.")
$this.WriteOutputLog("Moving current DBs to DBTMP and making new databases active")
if (!$this.CheckPMS("new database copy")) { return $false }
try {
$this.MoveDatabase($MainDBPath, (Join-Path $DBTemp -ChildPath "$($this.MainDB)_$($this.Timestamp)"), "move Main DB to DBTMP")
$this.MoveDatabase($MainDBImport, $MainDBPath, "replace Main DB with rebuilt DB")
$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")
} catch {
$Error.Clear()
return $false
}
$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)
[void] PrunePhotoTranscoderCache() {
$this.WriteLog($this.StageLog("START"))
if ($this.PMSRunning()) {
$this.OutputWarn("Unable to prune Phototranscoder cache. PMS is running.")
$this.WriteLog($this.StageLog("FAIL - PMS running"))
return
}
$Cutoff = $this.Options.CacheAge
$ShouldPrune = $this.Options.Scripted
if (!$ShouldPrune) {
$this.Output("Counting how many files are more than $Cutoff days old")
$CacheResult = $this.CheckPhotoTranscoderCache($true)
$Prunable = $CacheResult.PrunableFiles
$SpaceSaved = $CacheResult.SpaceSavings
if ($Prunable -eq 0) {
$this.Output("No files found to prune.")
$this.WriteLog($this.StageLog("PASS (no files found to prune)"))
return
}
$ShouldPrune = $this.GetYesNo("OK to prune $Prunable files ($SpaceSaved)")
}
if ($ShouldPrune) {
$this.Output("Pruning started.")
$PruneResult = $this.CheckPhotoTranscoderCache($false)
$Pruned = $PruneResult.PrunableFiles
$Total = $PruneResult.TotalFiles
$Saved = $PruneResult.SpaceSavings
$this.WriteOutputLog($this.StageLog("Removed $Pruned files over $Cutoff days old ($Saved), out of $Total total files"))
$this.Output("Pruning completed.")
} else {
$this.WriteOutputLog($this.StageLog("Prune cancelled by user"))
}
$this.WriteLog($this.StageLog("PASS"))
}
# Traverses PhotoTranscoder cache to find and delete files older than the specified max age.
# If $DryRun is $true, don't remove items, just gather statistics.
[CleanCacheResult] CheckPhotoTranscoderCache([bool] $DryRun) {
$Cutoff = (Get-Date).AddDays(-$this.Options.CacheAge);
$AllFiles = 0;
$OldFiles = 0;
$FreedBytes = 0;
Get-ChildItem -Path $this.PlexCache -Recurse -File |
Where-Object { $_.extension -in '.jpg','.jpeg','.png','.ppm' } |
ForEach-Object {
$AllFiles++;
if ($_.LastWriteTime -lt $Cutoff) {
$OldFiles++;
$FreedBytes += $_.Length;
if (!$DryRun) {
Remove-Item $_.FullName;
}
}
};
return [CleanCacheResult]::new($AllFiles, $OldFiles, $FreedBytes)
}
### Helpers ###
### Logging Helpers ###
[string] Now() { return Get-Date -Format 'yyyy-MM-dd HH.mm.ss' }
# Write the given text to the console
[void] Output([string] $Text) {
if ($this.Options.Scripted) {
Write-Host "$($this.Now()) $Text"
} else {
Write-Host $Text
}
}
# Write the given text as a warning in the console
[void] OutputWarn([string] $Text) {
if ($this.Options.Scripted) {
Write-Warning "$($this.Now()) $Text"
} else {
Write-Warning $Text
}
}
# Write the given text to the log file
[void] WriteLog([string] $Text) {
Add-Content -Path $this.LogFile -Value "$($this.Now()) -- $($Text)"
}
# Write the given text to the log file and console
[void] WriteOutputLog([string] $Text) {
$this.WriteLog($Text)
$this.Output($Text)
}
# Write the given text to the log file and as warning text in the console
[void] WriteOutputLogWarn([string] $Text) {
$this.WriteLog($Text)
$this.OutputWarn($Text)
}
# Write out the end of the session
[void] WriteEnd() {
$this.WriteLog("Session end. $(Get-Date)")
$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 ###
# Check whether the given directory exists (and is a directory)
[bool] DirExists([string] $Dir) {
if ($Dir) {
return Test-Path $Dir -PathType Container
}
return $false
}
# Check whether the given file exists (and is a file)
[bool] FileExists([string] $File) {
if ($File) {
return Test-Path $File -PathType Leaf
}
return $false
}
### Setup Helpers ###
# Retrieve Plex's data directory, exiting the script on failure
[string] GetAppDataDir() {
$PMSRegistry = $this.GetHKCU()
$PlexAppData = $PMSRegistry.LocalAppDataPath
if ($PlexAppData) {
$PlexAppData = Join-Path -Path $PlexAppData -ChildPath "Plex Media Server"
}
if ($this.DirExists($PlexAppData)) {
return $PlexAppData
}
$PlexAppData = "$env:LOCALAPPDATA\Plex Media Server"
if ($this.DirExists($PlexAppData)) {
return $PlexAppData
}
Write-Host "Could not determine Plex data directory, cannot continue"
Write-Host "Normally $env:LOCALAPPDATA\Plex Media Server"
exit
}
# Retrieve PMS settings under HKEY_CURRENT_USER, exiting the script on failure
[PSCustomObject] GetHKCU() {
try {
return (Get-ItemProperty -path 'HKCU:\Software\Plex, Inc.\Plex Media Server' -EA Stop)
} catch {
Write-Warning "Could not find Plex registry settings (HKCU\Software\Plex, Inc.\Plex Media Server). Are you sure Plex is installed on this machine?"
exit
}
}
# Set the Plex database directory, returning whether we found the directory
[bool] GetPlexDBDir([string] $AppData) {
$DBDir = Join-Path -Path $AppData -ChildPath "Plug-in Support\Databases"
if ($this.DirExists($DBDir)) {
$this.PlexDBDir = $DBDir;
return $true;
}
Write-Host "Could not find Databases folder, cannot continue."
Write-Host "Normally $DBDir"
return $false
}
# Set the path to Plex's PhotoTranscoder cache, returning whether we found the directory.
[bool] GetPhotoTranscoderDir([string] $AppData) {
$CacheDir = Join-Path -Path $AppData -ChildPath "Cache\PhotoTranscoder"
if ($this.DirExists($CacheDir)) {
$this.PlexCache = $CacheDir
return $true
}
Write-Host "Could not find PhotoTranscoder path, cannot prune."
Write-Host "Normally $CacheDir"
return $false
}
# Find the path to Plex SQLite.exe, falling back to user input if necessary.
[bool] GetPlexSQL() {
$PMSRegistry = $this.GetHKCU()
$InstallDir = $PMSRegistry.InstallFolder
if (!$InstallDir) {
# Install location might also be in HKLM
$InstallDir = (Get-ItemProperty -path 'HKLM:\SOFTWARE\Plex, Inc.\Plex Media Server' -EA Ignore).InstallFolder
if (!$InstallDir) {
# Final registry attempt - WOW6432Node
$InstallDir = (Get-ItemProperty -path 'HKLM:\SOFTWARE\WOW6432Node\Plex, Inc.\Plex Media Server' -EA Ignore).InstallFolder
}
}
$SQL = if ($InstallDir) { Join-Path -Path $InstallDir -ChildPath "Plex SQLite.exe" } else { $null }
if ($this.FileExists($SQL)) {
$this.PlexSQL = $SQL
return $true
}
# Still couldn't find install directory. Try standard PROGRAMFILES variables
$SQL = "$env:PROGRAMFILES\Plex\Plex Media Server\Plex SQ Lite.exe"
if ($this.FileExists($SQL)) {
$this.PlexSQL = $SQL
return $true
}
if (${env:PROGRAMFILES(X86)}) {
$SQL = "${env:PROGRAMFILES(X86)}\Plex Plex Media Server\Plex SQLite.exe"
if ($this.FileExists($SQL)) {
Write-Host "Note: 32-bit version of PMS detected on a 64-bit version of Windows. Using the 64-bit release of PMS is recommended."
$this.PlexSQL = $SQL
return $true
}
}
Write-Host "Could not determine Plex SQLite location. Please provide it below"
Write-Host "Normally $env:PORGRAMFILES\Plex\Plex Media Server\Plex SQLite.exe"
$First = $true
while (!$this.FileExists($SQL)) {
if (!$First) {
Write-Host "ERROR: '$SQL' could not be found"
}
$First = $false
$SQL = Read-Host -Prompt "Path to Plex SQLite.exe (Ctrl+C to cancel): "
}
$this.PlexSQL = $SQL
return $true
}
### Database Helpers ###
# Writes to output/log when we're done with database maintenance (on success or failure)
[void] ExitDBMaintenance([string] $Message, [boolean] $Success) {
if ($Success) {
$this.Output("Automatic Check,Repair,Index succeeded.")
$this.WriteLog($this.StageLog("PASS"))
} else {
$this.OutputWarn("Database maintenance failed - $Message")
$this.WriteLog($this.StageLog("$Message, cannot continue."))
$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.
# ErrorMessage is the message to output/write to the log on failure
[bool] RunSQLCommand([string] $Command, [string] $ErrorMessage) {
return $this.RunSQLCommandCore($Command, $ErrorMessage, $null)
}
# Run an SQL command and retrieve the output of said command
# ErrorMessage is the message to output/write to the log on failure
[bool] GetSQLCommandResult([string] $Command, [string] $ErrorMessage, [ref] $Output) {
return $this.RunSQLCommandCore($Command, $ErrorMessage, $Output)
}
# Run a 'Plex SQLite' command
[bool] RunSQLCommandCore([string] $Command, [string] $ErrorMessage, [ref] $Output) {
$SqlError = $null
$SqlResult = $null
$ExitCode = 0
try {
Invoke-Expression "& ""$($this.PlexSQL)"" $Command" -ev sqlError -OutVariable sqlResult -EA Stop *>$null
$ExitCode = $LASTEXITCODE
} catch {
$Err = $Error -join "`n"
$this.ExitDBMaintenance("Failed to run command '$Command': '$Err'", $false)
$Error.Clear()
return $false
}
if ($SqlError -or $ExitCode) {
$Err = $SqlError -join "`n"
if (!$Err) { $Err = "Process exited with error code $ExitCode" }
$Msg = $ErrorMessage
if (!$Msg) {
$Msg = "Plex SQLite operation failed"
}
if ($this.Options.IgnoreErrors -and $this.Options.CanIgnore) {
$this.OutputWarn("Ignoring database errors - ${Msg}: $Err")
} else {
$this.ExitDBMaintenance("${Msg}: $Err", $false)
return $false
}
}
if ($null -ne $Output.Value) {
$Output.Value = $SqlResult
}
return $true
}
# Import an exported .sql file into a new database
[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
$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) {
$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)
return $false
}
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 = $true
return $result
}
# Clear out the temp database directory. If $Confirm is $true, asks the user before doing so.
[void] CleanDBTemp([bool] $Confirm) {
if ($Confirm -and !$this.GetYesNo("Ok to remove temporary databases/workfiles for this session")) {
$this.Output("Retaining all temporary work files.")
$this.WriteLog("Exit - Retain temp files.")
return
}
$DBTemp = Join-Path $this.PlexDBDir -ChildPath "dbtmp"
if ($this.DirExists($DBTemp)) {
try {
Remove-Item $DBTemp -Recurse -Force -EA Stop
$this.Output("Deleted all temporary work files.")
$this.WriteLog("Exit - Deleted temp files.")
} catch {
$Err = $Error -join "`n"
$this.OutputWarn("Failed to remove temporary directory: $Err")
$this.WriteLog("Exit - Failed to remove temporary files: $Err")
$Error.Clear()
}
}
}
### Miscellaneous Helpers ###
# Return whether PMS is running
[bool] PMSRunning() {
return $null -ne $this.GetPMS()
}
# Retrieve the PMS process, if running
[System.Diagnostics.Process] GetPMS() {
return Get-Process -EA Ignore -Name "Plex Media Server"
}
# Ask the user a yes or no question, continuing to prompt them until
# their input starts with either a 'Y' or 'N'
[bool] GetYesNo([string] $Prompt) {
$Response = (Read-Host "$Prompt [Y/N]? ").ToLower()
$Ch = $Response.Substring(0, [Math]::Min($Response.Length, 1))
while (($Ch -ne "y") -and ($Ch -ne "n")) {
Write-Host "Invalid input, please enter [Y]es or [N]o"
$Response = (Read-Host "$Prompt [Y/N]? ").ToLower()
$Ch = $Response.Substring(0, [Math]::Min($Response.Length, 1))
}
return $Ch -eq "y"
}
}
# Contains miscellaneous options/state over the course of a session.
class DBRepairOptions {
[bool] $Scripted # Whether we're running in scripted or interactive mode
[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
DBRepairOptions() {
$this.CacheAge = 30
$this.ShowMenu = $true
$this.Scripted = $false
$this.IgnoreErrors = $false
$this.CanIgnore = $true
}
}
# Contains relevant data about a PhotoTranscoder `prune` attempt
class CleanCacheResult {
[int32] $TotalFiles # Total number of PhotoTranscoder files
[int32] $PrunableFiles # Total number of files that are older than the cutoff
[string] $SpaceSavings # Friendly string of (potential) space savings
CleanCacheResult([int32] $TotalFiles, [int32] $PrunableFiles, [int32] $PrunableBytes) {
$this.TotalFiles = $TotalFiles
$this.PrunableFiles = $PrunableFiles
$this.SpaceSavings = "$($PrunableBytes) bytes"
if ($PrunableBytes -gt 1GB) {
$this.SpaceSavings = "$([math]::round($PrunableBytes / 1GB, 2)) GiB";
} elseif ($PrunableBytes -gt 1MB) {
$this.SpaceSavings = "$([math]::round($PrunableBytes / 1MB, 2)) MiB";
} elseif ($PrunableBytes -gt 1KB) {
$this.SpaceSavings = "$([math]::round($PrunableBytes / 1KB, 2)) KiB";
}
}
}
# Ensure the console can handle utf-8, as the export process pipes utf-8 data from the console to our temporary sql file.
$InputEncodingSave = [console]::InputEncoding
$OutputEncodingSave = [console]::OutputEncoding
[console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
[void]([DBRepair]::new($args, $DBRepairVersion))
[console]::OutputEncoding = $OutputEncodingSave
[console]::InputEncoding = $InputEncodingSave
Binary file not shown.
-76
View File
@@ -1,76 +0,0 @@
# DBRepair-Windows
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
[Plex data directory](https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/).
## DBRepair-Windows.ps1 vs. DBRepair-Windows.bat
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
maintenance (repair/rebuild, check, and reindex). The PowerShell script is intended to align with
DBRepair.sh, offering command-name-based functionality that can either be scripted or
interactive.
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
tested. If any unexpected issues arise with the PowerShell script, please open an
[issue](https://github.com/ChuckPa/DBRepair/issues) so it can be investigated.
## Functions provided
The Windows utility aims to provide a similar interface to DBRepair.sh as outlined in the main
[README file](README.md), but currently only offers a subset of its functionality. For a full
description of the features below, consult that main README file.
The following commands (or their number) are currently supported on Windows.
```
AUTO(matic)
EXIT
PRUN(e)
STAR(t)
STOP
```
Run `.\DBRepair-Windows.ps1 -Help` for more complete documentation.
# Installation and usage instructions
DBRepair-Windows can be downloaded to any location. However, the PowerShell script might require
some prerequisite work in order to run as expected. By default, PowerShell scripts are blocked on
Windows machines, so in order to run DBRepair-Windows.ps1, you may need to do one of the following:
1. From an administrator PowerShell prompt, run `Set-ExecutionPolicy RemoteSigned`, then run the
script from a normal PowerShell prompt. If PowerShell still will not run the script, you can do
one of the following:
* In Windows Explorer, right-click DBRepair-Windows.ps1, select Properties, and check 'Unblock'
at the bottom of the dialog.
* In PowerShell, run `Unblock-File <path\to\DBRepair-Windows.ps1>`
* Run `Set-ExecutionPolicy Unrestricted` - this may result in an "are you sure" prompt before
running the script. `Set-ExecutionPolicy Bypass` will get around this, but is not recommended,
as it allows _any_ downloaded script to run without notification, not just DBRepair.
2. Explicitly set the `ExecutionPolicy` when running the script, e.g.:
```powershell
powershell -ExecutionPolicy Bypass ".\DBRepair-Windows.ps1 stop auto start"
```
Note that this method may not work if your machine is managed with Group Policy, which
can block manual `ExecutionPolicy` overrides.
3. Similar to 2, but make it a batch script (e.g. `DBRepair.bat`) that lives alongside
the powershell script:
```batch
@echo off
powershell -ExecutionPolicy Bypass -Command ".\DBRepair-Windows.ps1 %*"
```
Then run that script directly:
```batch
.\DBRepair.bat stop auto start
```
Also note that the PowerShell script cannot be run directly from a Command Prompt window.
If you are running this from Command Prompt, you must launch it via PowerShell:
```cmd
powershell .\DBRepair-Windows.ps1 [args]
```
-33
View File
@@ -1,33 +0,0 @@
# DBRepair-Windows
Release notes for the Windows counterpart to DBRepair.sh (DBRepair-Windows.ps1)
# Release Info
v1.01.02
- Remove `statistics_bandwidth` pruning, as it's now part of PMS 1.41.8
- Change `quit` to 98 and `exit` to 99
- Minor logging refactoring
v1.01.01
- Add `staticstics_bandwidth` pruning during automatic repair.
v1.01.00
- Rename this tool to be compliant with Plex inc. Trademark Policy.
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