-
-
@@ -525,7 +521,7 @@
-
Store a hashed password in the config.ini file.
Warning: Your password cannot be recovered if forgotten!
+
Store a hashed password in the config file.
Warning: Your password cannot be recovered if forgotten!
@@ -2138,12 +2134,12 @@ $(document).ready(function() {
}
getSchedulerTable();
- $("#backup_database").click(function () {
- $("#confirm-message").text("Are you sure you want to create a backup of the PlexPy database?");
+ function confirmAjaxCall (url, msg) {
+ $("#confirm-message").text(msg);
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
$.ajax({
- url: 'backup_db',
+ url: url,
type: 'POST',
complete: function (xhr, status) {
result = $.parseJSON(xhr.responseText);
@@ -2156,46 +2152,36 @@ $(document).ready(function() {
}
});
});
+ }
+
+ $("#backup_config").click(function () {
+ var msg = 'Are you sure you want to create a backup of the PlexPy config?';
+ var url = 'backup_config';
+ confirmAjaxCall(url, msg);
+ });
+
+ $("#backup_database").click(function () {
+ var msg = 'Are you sure you want to create a backup of the PlexPy database?';
+ var url = 'backup_db';
+ confirmAjaxCall(url, msg);
});
$("#clear_cache").click(function () {
- $("#confirm-message").text("Are you sure you want to clear the PlexPy cache?");
- $('#confirm-modal').modal();
- $('#confirm-modal').one('click', '#confirm-button', function () {
- $.ajax({
- url: 'delete_cache',
- type: 'POST',
- complete: function (xhr, status) {
- result = $.parseJSON(xhr.responseText);
- msg = result.message;
- if (result.result == 'success') {
- showMsg('
' + msg, false, true, 5000)
- } else {
- showMsg('
' + msg, false, true, 5000, true)
- }
- }
- });
- });
+ var msg = 'Are you sure you want to clear the PlexPy cache?';
+ var url = 'delete_cache';
+ confirmAjaxCall(url, msg);
+ });
+
+ $("#clear_image_cache").click(function () {
+ var msg = 'Are you sure you want to clear the PlexPy image cache?';
+ var url = 'delete_image_cache';
+ confirmAjaxCall(url, msg);
});
$("#clear_logs").click(function () {
- $("#confirm-message").text("Are you sure you want to clear the PlexPy logs?");
- $('#confirm-modal').modal();
- $('#confirm-modal').one('click', '#confirm-button', function () {
- $.ajax({
- url: 'delete_logs',
- type: 'POST',
- complete: function (xhr, status) {
- result = $.parseJSON(xhr.responseText);
- msg = result.message;
- if (result.result == 'success') {
- showMsg('
' + msg, false, true, 5000)
- } else {
- showMsg('
' + msg, false, true, 5000, true)
- }
- }
- });
- });
+ var msg = 'Are you sure you want to clear the PlexPy logs?';
+ var url = 'delete_logs';
+ confirmAjaxCall(url, msg);
});
diff --git a/plexpy/__init__.py b/plexpy/__init__.py
index d07cd117..01877d16 100644
--- a/plexpy/__init__.py
+++ b/plexpy/__init__.py
@@ -345,6 +345,7 @@ def initialize_scheduler():
hours=hours, minutes=0, seconds=0)
schedule_job(database.make_backup, 'Backup PlexPy database', hours=6, minutes=0, seconds=0, args=(True, True))
+ schedule_job(config.make_backup, 'Backup PlexPy config', hours=6, minutes=0, seconds=0, args=(True, True))
# Start scheduler
if start_jobs and len(SCHED.get_jobs()):
diff --git a/plexpy/api2.py b/plexpy/api2.py
index 4b9b1568..8e782810 100644
--- a/plexpy/api2.py
+++ b/plexpy/api2.py
@@ -31,6 +31,7 @@ import cherrypy
import xmltodict
import plexpy
+import config
import database
import logger
import plextv
@@ -295,6 +296,18 @@ class API2:
self.data = rows
return rows
+ def backup_config(self):
+ """ Create a manual backup of the `config.ini` file. """
+
+ data = config.make_backup()
+
+ if data:
+ self.result_type = 'success'
+ else:
+ self.result_type = 'failed'
+
+ return data
+
def backup_db(self):
""" Create a manual backup of the `plexpy.db` file. """
diff --git a/plexpy/common.py b/plexpy/common.py
index 31797826..5c69c8c7 100644
--- a/plexpy/common.py
+++ b/plexpy/common.py
@@ -69,5 +69,6 @@ SCHEDULER_LIST = ['Check GitHub for updates',
'Refresh libraries list',
'Refresh Plex server URLs',
'Refresh Plex server name',
- 'Backup PlexPy database'
+ 'Backup PlexPy database',
+ 'Backup PlexPy config'
]
\ No newline at end of file
diff --git a/plexpy/config.py b/plexpy/config.py
index f2f3b012..bb03fdf3 100644
--- a/plexpy/config.py
+++ b/plexpy/config.py
@@ -13,10 +13,14 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see
.
+import arrow
+import os
import re
+import shutil
from configobj import ConfigObj
+import plexpy
import logger
@@ -29,6 +33,8 @@ def bool_int(value):
value = 0
return int(bool(value))
+FILENAME = "config.ini"
+
_CONFIG_DEFINITIONS = {
'ALLOW_GUEST_ACCESS': (int, 'General', 0),
'DATE_FORMAT': (str, 'General', 'YYYY-MM-DD'),
@@ -480,6 +486,43 @@ _BLACKLIST_KEYS = ['_APITOKEN', '_TOKEN', '_KEY', '_SECRET', '_PASSWORD', '_APIK
_WHITELIST_KEYS = ['HTTPS_KEY', 'UPDATE_SECTION_IDS']
+def make_backup(cleanup=False, scheduler=False):
+ """ Makes a backup of config file, removes all but the last 5 backups """
+
+ if scheduler:
+ backup_file = 'config.backup-%s.sched.ini' % arrow.now().format('YYYYMMDDHHmmss')
+ else:
+ backup_file = 'config.backup-%s.ini' % arrow.now().format('YYYYMMDDHHmmss')
+ backup_folder = plexpy.CONFIG.BACKUP_DIR
+ backup_file_fp = os.path.join(backup_folder, backup_file)
+
+ # In case the user has deleted it manually
+ if not os.path.exists(backup_folder):
+ os.makedirs(backup_folder)
+
+ plexpy.CONFIG.write()
+ shutil.copyfile(plexpy.CONFIG_FILE, backup_file_fp)
+
+ if cleanup:
+ # Delete all scheduled backup files except from the last 5.
+ for root, dirs, files in os.walk(backup_folder):
+ db_files = [os.path.join(root, f) for f in files if f.endswith('.sched.ini')]
+ if len(db_files) > 5:
+ backups_sorted_on_age = sorted(db_files, key=os.path.getctime, reverse=True)
+ for file_ in backups_sorted_on_age[5:]:
+ try:
+ os.remove(file_)
+ except OSError as e:
+ logger.error(u"PlexPy Config :: Failed to delete %s from the backup folder: %s" % (file_, e))
+
+ if backup_file in os.listdir(backup_folder):
+ logger.debug(u"PlexPy Config :: Successfully backed up %s to %s" % (plexpy.CONFIG_FILE, backup_file))
+ return True
+ else:
+ logger.warn(u"PlexPy Config :: Failed to backup %s to %s" % (plexpy.CONFIG_FILE, backup_file))
+ return False
+
+
# pylint:disable=R0902
# it might be nice to refactor for fewer instance variables
class Config(object):
@@ -557,12 +600,12 @@ class Config(object):
new_config[section][ini_key] = self._config[section][ini_key]
# Write it to file
- logger.info("Writing configuration to file")
+ logger.info(u"PlexPy Config :: Writing configuration to file")
try:
new_config.write()
except IOError as e:
- logger.error("Error writing configuration file: %s", e)
+ logger.error(u"PlexPy Config :: Error writing configuration file: %s", e)
self._blacklist()
diff --git a/plexpy/database.py b/plexpy/database.py
index 2331d6ca..6771c1cf 100644
--- a/plexpy/database.py
+++ b/plexpy/database.py
@@ -23,6 +23,7 @@ import time
import plexpy
import logger
+FILENAME = "plexpy.db"
db_lock = threading.Lock()
@@ -52,7 +53,7 @@ def delete_sessions():
logger.warn(u"PlexPy Database :: Unable to clear temporary sessions from database: %s." % e)
return 'Unable to clear temporary sessions.'
-def db_filename(filename="plexpy.db"):
+def db_filename(filename=FILENAME):
""" Returns the filepath to the db """
return os.path.join(plexpy.DATA_DIR, filename)
@@ -115,7 +116,7 @@ def dict_factory(cursor, row):
class MonitorDatabase(object):
- def __init__(self, filename='plexpy.db'):
+ def __init__(self, filename=FILENAME):
self.filename = filename
self.connection = sqlite3.connect(db_filename(filename), timeout=20)
# Don't wait for the disk to finish writing
diff --git a/plexpy/webserve.py b/plexpy/webserve.py
index 64ffd1b9..dbc1aff4 100644
--- a/plexpy/webserve.py
+++ b/plexpy/webserve.py
@@ -30,6 +30,7 @@ from mako import exceptions
import plexpy
import common
+import config
import database
import datafactory
import graphs
@@ -2428,6 +2429,19 @@ class WebInterface(object):
return {'result': 'success', 'message': 'Settings saved.'}
+ @cherrypy.expose
+ @cherrypy.tools.json_out()
+ @requireAuth(member_of("admin"))
+ def backup_config(self):
+ """ Creates a manual backup of the plexpy.db file """
+
+ result = config.make_backup()
+
+ if result:
+ return {'result': 'success', 'message': 'Config backup successful.'}
+ else:
+ return {'result': 'error', 'message': 'Config backup failed.'}
+
@cherrypy.expose
@requireAuth(member_of("admin"))
def get_scheduler_table(self, **kwargs):