Browse Source

Add display "Database backups" location at config/about if feature available.

Add option "Backup database plan" to config/general/advanced if feature available.
Change save backup DBs with a date_time fmt that is sortable by filename in any file manager.
Change take maximum usage from the helpers.make_dirs function.
Change tweak var names to be consistent.
Fix KeyError 'Backup' at startup.
Fix lastUpdate update error with using wrong db.
tags/release_0.25.1
JackDandy 5 years ago
parent
commit
172ce2218d
  1. 6
      CHANGES.md
  2. 3
      gui/slick/interfaces/default/config.tmpl
  3. 12
      gui/slick/interfaces/default/config_general.tmpl
  4. 26
      sickbeard/__init__.py
  5. 18
      sickbeard/db.py
  6. 6
      sickbeard/show_updater.py
  7. 6
      sickbeard/webserve.py

6
CHANGES.md

@ -1,5 +1,11 @@
### 0.23.0 (2019-xx-xx xx:xx:xx UTC) ### 0.23.0 (2019-xx-xx xx:xx:xx UTC)
* Add db backup to the scheduled daily update
* Add display "Database backups" location at config/about if feature available
* Add option "Backup database plan" to config/general/advanced if feature available
* Add py7zr to recommended.txt for optional 7z compression
* Add `backup_db_path` setting to config.ini to customise backup db location
* Add `backup_db_max_count` to config.ini with range 0-90 where 0 = disable backup, 14 = default
* Change improve list performance for file/directory browser * Change improve list performance for file/directory browser
* Change improve import shows listing performance * Change improve import shows listing performance
* Change improve performance during show rescan process * Change improve performance during show rescan process

3
gui/slick/interfaces/default/config.tmpl

@ -31,6 +31,9 @@
</tr> </tr>
<tr><td class="infoTableHeader">Config file:</td><td class="infoTableCell">$sg_str('CONFIG_FILE')</td></tr> <tr><td class="infoTableHeader">Config file:</td><td class="infoTableCell">$sg_str('CONFIG_FILE')</td></tr>
<tr><td class="infoTableHeader">Database file:</td><td class="infoTableCell">$db.dbFilename()</td></tr> <tr><td class="infoTableHeader">Database file:</td><td class="infoTableCell">$db.dbFilename()</td></tr>
#if $db.db_supports_backup
<tr><td class="infoTableHeader">Database backups:</td><td class="infoTableCell">$backup_db_path</td></tr>
#end if
<tr><td class="infoTableHeader">Cache Dir:</td><td class="infoTableCell">$sg_str('CACHE_DIR')</td></tr> <tr><td class="infoTableHeader">Cache Dir:</td><td class="infoTableCell">$sg_str('CACHE_DIR')</td></tr>
<tr><td class="infoTableHeader">Arguments:</td><td class="infoTableCell">#echo $sg_var('MY_ARGS') or 'None used'#</td></tr> <tr><td class="infoTableHeader">Arguments:</td><td class="infoTableCell">#echo $sg_var('MY_ARGS') or 'None used'#</td></tr>
<tr><td class="infoTableHeader">Web Root:</td><td class="infoTableCell">$sg_str('WEB_ROOT')</td></tr> <tr><td class="infoTableHeader">Web Root:</td><td class="infoTableCell">$sg_str('WEB_ROOT')</td></tr>

12
gui/slick/interfaces/default/config_general.tmpl

@ -5,6 +5,7 @@
#from sickbeard import config, metadata #from sickbeard import config, metadata
#from sickbeard.metadata.generic import GenericMetadata #from sickbeard.metadata.generic import GenericMetadata
#from sickbeard.common import * #from sickbeard.common import *
#from sickbeard.db import db_supports_backup
#from sickbeard.helpers import anon_url, maybe_plural #from sickbeard.helpers import anon_url, maybe_plural
#from sickbeard.logger import reverseNames as file_logging_presets #from sickbeard.logger import reverseNames as file_logging_presets
#from sickbeard.sgdatetime import * #from sickbeard.sgdatetime import *
@ -796,6 +797,17 @@
</span> </span>
</label> </label>
</div> </div>
#if $db_supports_backup
<div class="field-pair">
<label for="backup_db_oneday">
<span class="component-title">Backup database plan</span>
<span class="component-desc">
<input type="checkbox" name="backup_db_oneday" id="backup_db_oneday"#echo ('', $checked)[True == $sg_var('BACKUP_DB_ONEDAY')]#>
<p>backup one day instead of multiple days (helps existing backup strategies)</p>
</span>
</label>
</div>
#end if
<input type="submit" class="btn config_submitter" value="Save Changes"> <input type="submit" class="btn config_submitter" value="Save Changes">
</fieldset> </fieldset>

26
sickbeard/__init__.py

@ -545,9 +545,10 @@ SUBTITLES_FINDER_FREQUENCY = 1
USE_FAILED_DOWNLOADS = False USE_FAILED_DOWNLOADS = False
DELETE_FAILED = False DELETE_FAILED = False
MAX_DB_BACKUP_COUNT = 14 BACKUP_DB_PATH = ''
DEFAULT_DB_BACKUP_COUNT = 14 BACKUP_DB_ONEDAY = False
DB_BACKUP_PATH = '' BACKUP_DB_MAX_COUNT = 14
BACKUP_DB_DEFAULT_COUNT = 14
EXTRA_SCRIPTS = [] EXTRA_SCRIPTS = []
SG_EXTRA_SCRIPTS = [] SG_EXTRA_SCRIPTS = []
@ -748,7 +749,7 @@ def init_stage_1(console_logging):
# Anime Settings # Anime Settings
global ANIME_TREAT_AS_HDTV, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST global ANIME_TREAT_AS_HDTV, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST
# db backup settings # db backup settings
global MAX_DB_BACKUP_COUNT, DEFAULT_DB_BACKUP_COUNT, DB_BACKUP_PATH global BACKUP_DB_PATH, BACKUP_DB_ONEDAY, BACKUP_DB_MAX_COUNT, BACKUP_DB_DEFAULT_COUNT
for stanza in ('General', 'Blackhole', 'SABnzbd', 'NZBGet', 'Emby', 'Kodi', 'XBMC', 'PLEX', for stanza in ('General', 'Blackhole', 'SABnzbd', 'NZBGet', 'Emby', 'Kodi', 'XBMC', 'PLEX',
'Growl', 'Prowl', 'Slack', 'Discord', 'Boxcar2', 'NMJ', 'NMJv2', 'Growl', 'Prowl', 'Slack', 'Discord', 'Boxcar2', 'NMJ', 'NMJv2',
@ -1312,10 +1313,10 @@ def init_stage_1(console_logging):
if not isinstance(BROWSELIST_MRU, dict): if not isinstance(BROWSELIST_MRU, dict):
BROWSELIST_MRU = {} BROWSELIST_MRU = {}
MAX_DB_BACKUP_COUNT = minimax(check_setting_int(CFG, 'Backup', 'max_db_backup_count', DEFAULT_DB_BACKUP_COUNT), BACKUP_DB_PATH = check_setting_str(CFG, 'Backup', 'backup_db_path', '')
DEFAULT_DB_BACKUP_COUNT, 0, 90) BACKUP_DB_ONEDAY = bool(check_setting_int(CFG, 'Backup', 'backup_db_oneday', 0))
use_count = (1, BACKUP_DB_DEFAULT_COUNT)[not BACKUP_DB_ONEDAY]
DB_BACKUP_PATH = check_setting_str(CFG, 'Backup', 'db_backup_path', '') BACKUP_DB_MAX_COUNT = minimax(check_setting_int(CFG, 'Backup', 'backup_db_max_count', use_count), use_count, 0, 90)
sg_helpers.db = db sg_helpers.db = db
sg_helpers.DOMAIN_FAILURES.load_from_db() sg_helpers.DOMAIN_FAILURES.load_from_db()
@ -1885,9 +1886,12 @@ def save_config():
new_config['General']['ignore_words'] = helpers.generate_word_str(IGNORE_WORDS, IGNORE_WORDS_REGEX) new_config['General']['ignore_words'] = helpers.generate_word_str(IGNORE_WORDS, IGNORE_WORDS_REGEX)
new_config['General']['require_words'] = helpers.generate_word_str(REQUIRE_WORDS, REQUIRE_WORDS_REGEX) new_config['General']['require_words'] = helpers.generate_word_str(REQUIRE_WORDS, REQUIRE_WORDS_REGEX)
new_config['General']['calendar_unprotected'] = int(CALENDAR_UNPROTECTED) new_config['General']['calendar_unprotected'] = int(CALENDAR_UNPROTECTED)
new_config['Backup']['max_db_backup_count'] = MAX_DB_BACKUP_COUNT
if DB_BACKUP_PATH: new_config['Backup'] = {}
new_config['Backup']['db_backup_path'] = DB_BACKUP_PATH if BACKUP_DB_PATH:
new_config['Backup']['backup_db_path'] = BACKUP_DB_PATH
new_config['Backup']['backup_db_oneday'] = int(BACKUP_DB_ONEDAY)
new_config['Backup']['backup_db_max_count'] = BACKUP_DB_MAX_COUNT
default_not_zero = ('enable_recentsearch', 'enable_backlog', 'enable_scheduled_backlog', 'use_after_get_data') default_not_zero = ('enable_recentsearch', 'enable_backlog', 'enable_scheduled_backlog', 'use_after_get_data')
for src in filter_iter(lambda px: GenericProvider.TORRENT == px.providerType, providers.sortedProviderList()): for src in filter_iter(lambda px: GenericProvider.TORRENT == px.providerType, providers.sortedProviderList()):

18
sickbeard/db.py

@ -776,7 +776,7 @@ def get_rollback_module():
def delete_old_db_backups(target): def delete_old_db_backups(target):
# type: (AnyStr) -> None # type: (AnyStr) -> None
""" """
remove old db backups (> MAX_DB_BACKUP_COUNT) remove old db backups (> BACKUP_DB_MAX_COUNT)
:param target: backup folder to check :param target: backup folder to check
""" """
@ -786,9 +786,9 @@ def delete_old_db_backups(target):
file_list = [f for f in ek.ek(scandir, target) if f.is_file()] file_list = [f for f in ek.ek(scandir, target) if f.is_file()]
for filename in ['sickbeard', 'cache', 'failed']: for filename in ['sickbeard', 'cache', 'failed']:
tb = filter_list(lambda fn: fn.is_file() and filename in fn.name, file_list) tb = filter_list(lambda fn: fn.is_file() and filename in fn.name, file_list)
if sickbeard.MAX_DB_BACKUP_COUNT < len(tb): if sickbeard.BACKUP_DB_MAX_COUNT < len(tb):
tb.sort(key=lambda f: f.stat(follow_symlinks=False).st_mtime, reverse=True) tb.sort(key=lambda f: f.stat(follow_symlinks=False).st_mtime, reverse=True)
for t in tb[sickbeard.MAX_DB_BACKUP_COUNT:]: for t in tb[sickbeard.BACKUP_DB_MAX_COUNT:]:
try: try:
ek.ek(os.unlink, t.path) ek.ek(os.unlink, t.path)
except (BaseException, Exception): except (BaseException, Exception):
@ -810,12 +810,10 @@ def backup_all_dbs(target, compress=True, prefer_7z=True):
:param prefer_7z: prefer 7z compression if available :param prefer_7z: prefer 7z compression if available
:return: success, message :return: success, message
""" """
if not ek.ek(os.path.isdir, target): if not make_dirs(target):
make_dirs(target)
if not ek.ek(os.path.isdir, target):
logger.log('Failed to create db backup dir', logger.ERROR) logger.log('Failed to create db backup dir', logger.ERROR)
return False, 'Failed to create db backup dir' return False, 'Failed to create db backup dir'
my_db = DBConnection() my_db = DBConnection('cache.db')
last_backup = my_db.select('SELECT time FROM lastUpdate WHERE provider = ?', ['sickgear_db_backup']) last_backup = my_db.select('SELECT time FROM lastUpdate WHERE provider = ?', ['sickgear_db_backup'])
if last_backup: if last_backup:
now_stamp = int(timestamp_near(datetime.datetime.now())) now_stamp = int(timestamp_near(datetime.datetime.now()))
@ -823,10 +821,10 @@ def backup_all_dbs(target, compress=True, prefer_7z=True):
# only backup every 23 hours # only backup every 23 hours
if now_stamp - the_time < 60 * 60 * 23: if now_stamp - the_time < 60 * 60 * 23:
return False, 'Too early to backup db again' return False, 'Too early to backup db again'
now = datetime.datetime.now() now = sgdatetime.SGDatetime.now()
d = sgdatetime.SGDatetime.sbfdate(now, d_preset='%d-%m-%Y') d = sgdatetime.SGDatetime.sbfdate(now, d_preset='%Y-%m-%d')
t = sgdatetime.SGDatetime.sbftime(now, t_preset='%H-%M') t = sgdatetime.SGDatetime.sbftime(now, t_preset='%H-%M')
ds = '%s_%s' % (t, d) ds = '%s_%s' % (d, t)
for c in ['sickbeard', 'cache', 'failed']: for c in ['sickbeard', 'cache', 'failed']:
cur_db = DBConnection('%s.db' % c) cur_db = DBConnection('%s.db' % c)
b_name = '%s_%s.db' % (c, ds) b_name = '%s_%s.db' % (c, ds)

6
sickbeard/show_updater.py

@ -71,13 +71,13 @@ class ShowUpdater(object):
update_date = update_datetime.date() update_date = update_datetime.date()
# backup db's # backup db's
if sickbeard.db.db_supports_backup and 0 < sickbeard.MAX_DB_BACKUP_COUNT: if sickbeard.db.db_supports_backup and 0 < sickbeard.BACKUP_DB_MAX_COUNT:
logger.log('backing up all db\'s') logger.log('backing up all db\'s')
try: try:
sickbeard.db.backup_all_dbs(sickbeard.DB_BACKUP_PATH or sickbeard.db.backup_all_dbs(sickbeard.BACKUP_DB_PATH or
ek.ek(os.path.join, sickbeard.DATA_DIR, 'backup')) ek.ek(os.path.join, sickbeard.DATA_DIR, 'backup'))
except (BaseException, Exception): except (BaseException, Exception):
logger.log('DB backup error', logger.ERROR) logger.log('backup db error', logger.ERROR)
# refresh network timezones # refresh network timezones
try: try:

6
sickbeard/webserve.py

@ -6730,6 +6730,9 @@ class Config(MainHandler):
except (BaseException, Exception): except (BaseException, Exception):
t.version = '' t.version = ''
t.backup_db_path = sickbeard.BACKUP_DB_MAX_COUNT and \
(sickbeard.BACKUP_DB_PATH or ek.ek(os.path.join, sickbeard.DATA_DIR, 'backup')) or 'Disabled'
return t.respond() return t.respond()
@ -6957,7 +6960,7 @@ class ConfigGeneral(Config):
handle_reverse_proxy=None, send_security_headers=None, allowed_hosts=None, allow_anyip=None, handle_reverse_proxy=None, send_security_headers=None, allowed_hosts=None, allow_anyip=None,
git_remote=None, git_remote=None,
git_path=None, cpu_preset=None, anon_redirect=None, encryption_version=None, git_path=None, cpu_preset=None, anon_redirect=None, encryption_version=None,
proxy_setting=None, proxy_indexers=None, file_logging_preset=None): proxy_setting=None, proxy_indexers=None, file_logging_preset=None, backup_db_oneday=None):
results = [] results = []
@ -7067,6 +7070,7 @@ class ConfigGeneral(Config):
sickbeard.PROXY_INDEXERS = config.checkbox_to_value(proxy_indexers) sickbeard.PROXY_INDEXERS = config.checkbox_to_value(proxy_indexers)
sickbeard.FILE_LOGGING_PRESET = file_logging_preset sickbeard.FILE_LOGGING_PRESET = file_logging_preset
# sickbeard.LOG_DIR is set in config.change_log_dir() # sickbeard.LOG_DIR is set in config.change_log_dir()
sickbeard.BACKUP_DB_ONEDAY = config.checkbox_to_value(backup_db_oneday)
logger.log_set_level() logger.log_set_level()

Loading…
Cancel
Save