From 2b7df8e67d715032ea1447f07ddf228089b92a85 Mon Sep 17 00:00:00 2001 From: echel0n Date: Thu, 19 Jun 2014 07:31:44 -0700 Subject: [PATCH] Added backup and restore feature, this allows you to backup your config.ini and sickbeard.db files into a zipfile and save it to a destination of your choice and as well you can restore the same zip file later on then perform a restart to have the changes take affect automatically. Backups are saved date/time stamped. --- SickBeard.py | 23 +++++ .../default/config_backuprestore.tmpl | 83 +++++++++++++++++++ gui/slick/interfaces/default/inc_top.tmpl | 2 + gui/slick/js/browser.js | 14 ++-- gui/slick/js/configBackupRestore.js | 24 ++++++ sickbeard/browser.py | 15 ++-- sickbeard/helpers.py | 69 +++++++++++++-- sickbeard/webserve.py | 74 +++++++++++++---- 8 files changed, 268 insertions(+), 36 deletions(-) create mode 100644 gui/slick/interfaces/default/config_backuprestore.tmpl create mode 100644 gui/slick/js/configBackupRestore.js diff --git a/SickBeard.py b/SickBeard.py index cc01be9a..cd0f7fb6 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -21,6 +21,7 @@ from __future__ import with_statement import sys +import shutil if sys.version_info < (2, 6): print "Sorry, requires Python 2.6 or 2.7." @@ -133,6 +134,20 @@ def daemonize(): dev_null = file('/dev/null', 'r') os.dup2(dev_null.fileno(), sys.stdin.fileno()) +def restore(srcDir, dstDir): + try: + for file in os.listdir(srcDir): + srcFile = os.path.join(srcDir, file) + dstFile = os.path.join(dstDir, file) + bakFile = os.path.join(dstDir, file + '.bak') + shutil.move(dstFile, bakFile) + shutil.move(srcFile, dstFile) + + os.rmdir(srcDir) + return True + except: + return False + def main(): """ TV for me @@ -177,6 +192,14 @@ def main(): # Rename the main thread threading.currentThread().name = "MAIN" + # Check if we need to perform a restore first + restoreDir = os.path.join(sickbeard.PROG_DIR, 'restore') + if os.path.exists(restoreDir): + if restore(restoreDir, sickbeard.PROG_DIR): + print "Restore successful..." + else: + print "Restore FAILED!" + try: opts, args = getopt.getopt(sys.argv[1:], "qfdp::", ['quiet', 'forceupdate', 'daemon', 'port=', 'pidfile=', 'nolaunch', 'config=', diff --git a/gui/slick/interfaces/default/config_backuprestore.tmpl b/gui/slick/interfaces/default/config_backuprestore.tmpl new file mode 100644 index 00000000..cf907ac0 --- /dev/null +++ b/gui/slick/interfaces/default/config_backuprestore.tmpl @@ -0,0 +1,83 @@ +#import os.path +#import datetime +#import locale +#import sickbeard +#from sickbeard.common import * +#from sickbeard.sbdatetime import * +#from sickbeard import config +#from sickbeard import metadata +#from sickbeard.metadata.generic import GenericMetadata +#set global $title = "Config - Backup/Restore" +#set global $header = "Backup/Restore" + +#set global $sbPath="../.." + +#set global $topmenu="config"# +#include $os.path.join($sickbeard.PROG_DIR, "gui/slick/interfaces/default/inc_top.tmpl") + + +#if $varExists('header') +

$header

+#else +

$title

+#end if + +#set $indexer = 0 +#if $sickbeard.INDEXER_DEFAULT + #set $indexer = $sickbeard.INDEXER_DEFAULT +#end if + + + +
+
+ +
+
+ + +
+
+

Backup

+

Backup your main database file and config.

+
+ + Select the folder you wish to save your backup file to: +
+
+
+
+ +
+ +
+
+

Restore

+

Restore your main database file and config.

+
+ + Select the backup file you wish to restore: +
+
+
+
+ +
+
+
+
+ +
+ + + +#include $os.path.join($sickbeard.PROG_DIR,"gui/slick/interfaces/default/inc_bottom.tmpl") diff --git a/gui/slick/interfaces/default/inc_top.tmpl b/gui/slick/interfaces/default/inc_top.tmpl index ea43ecc1..d78597d2 100644 --- a/gui/slick/interfaces/default/inc_top.tmpl +++ b/gui/slick/interfaces/default/inc_top.tmpl @@ -161,6 +161,7 @@ a > i.icon-question-sign { background-image: url("$sbRoot/images/glyphicons-half \$("#SubMenu a:contains('Anime')").addClass('btn').html(' Anime'); \$("#SubMenu a:contains('Settings')").addClass('btn').html(' Search Settings'); \$("#SubMenu a:contains('Provider')").addClass('btn').html(' Search Providers'); + \$("#SubMenu a:contains('Backup/Restore')").addClass('btn').html(' Backup/Restore'); \$("#SubMenu a:contains('General')").addClass('btn').html(' General'); \$("#SubMenu a:contains('Episode Status')").addClass('btn').html(' Episode Status Management'); \$("#SubMenu a:contains('Missed Subtitle')").addClass('btn').html(' Missed Subtitles'); @@ -272,6 +273,7 @@ a > i.icon-question-sign { background-image: url("$sbRoot/images/glyphicons-half