Commit e376aab7 authored by echel0n's avatar echel0n

Added more info logging to detail what goes on during startup on app.

Config now encrypted and save to temp file first then tested to confirm working.
Added actions column to allow force running scheduler jobs under server status page.
parent 803b3977
......@@ -231,6 +231,7 @@ class Core(object):
encryption.initialize()
# load config
self.log.info("Loading encrypted config from disk")
self.config.load()
# set language
......@@ -261,6 +262,7 @@ class Core(object):
# Check available space
try:
self.log.info("Performing disk space checks")
total_space, available_space = get_free_space(self.data_dir)
if available_space < 100:
self.log.warning('Shutting down as SiCKRAGE needs some space to work. You\'ll get corrupted data otherwise. Only %sMB left', available_space)
......@@ -271,15 +273,19 @@ class Core(object):
# perform database startup actions
for db in [self.main_db, self.cache_db]:
# perform integrity check
self.log.info("Performing integrity check on {} database".format(db.name))
db.integrity_check()
# migrate database
self.log.info("Performing migrations on {} database".format(db.name))
db.migrate()
# sync database repo
self.log.info("Performing sync on {} database".format(db.name))
db.sync_db_repo()
# cleanup
self.log.info("Performing cleanup on {} database".format(db.name))
db.cleanup()
# load name cache
......@@ -478,7 +484,7 @@ class Core(object):
# add namecache update job
self.scheduler.add_job(
self.name_cache.build_all,
self.name_cache.run,
IntervalTrigger(
days=1,
timezone='utc'
......
......@@ -31,14 +31,22 @@ from sickrage.core.tv.show.helpers import get_show_list
class NameCache(object):
def __init__(self, *args, **kwargs):
self.name = "NAMECACHE"
self.amActive = False
self.min_time = 10
self.last_update = {}
self.cache = {}
def run(self):
def run(self, force=False):
if self.amActive and not force:
return
self.amActive = True
threading.currentThread().setName(self.name)
self.build_all()
self.amActive = False
def should_update(self, show):
# if we've updated recently then skip the update
if datetime.today() - (self.last_update.get(show.name) or datetime.fromtimestamp(
......@@ -122,8 +130,6 @@ class NameCache(object):
:param show: Specify show to build name cache for, if None, just do all shows
"""
retrieve_exceptions()
if self.should_update(show):
self.last_update[show.name] = datetime.fromtimestamp(int(time.mktime(datetime.today().timetuple())))
......@@ -141,5 +147,6 @@ class NameCache(object):
self.put(show_name, show.indexer_id)
def build_all(self):
retrieve_exceptions(force=True)
for show in get_show_list():
self.build(show)
......@@ -38,8 +38,7 @@ from configobj import ConfigObj
import sickrage
from sickrage.core.api import API
from sickrage.core.common import SD, WANTED, SKIPPED, Quality
from sickrage.core.helpers import make_dir, generate_secret, auto_type, get_lan_ip, \
extract_zipfile, try_int, checkbox_to_value, generate_api_key, backup_versioned_file, encryption
from sickrage.core.helpers import make_dir, generate_secret, auto_type, get_lan_ip, extract_zipfile, try_int, checkbox_to_value, generate_api_key, backup_versioned_file, encryption, move_file
from sickrage.core.websession import WebSession
......@@ -1357,27 +1356,29 @@ class Config(object):
return my_val
def load(self, defaults=False):
if not os.path.isabs(sickrage.app.config_file):
sickrage.app.config_file = os.path.abspath(os.path.join(sickrage.app.data_dir, sickrage.app.config_file))
def load(self, config_file=None, defaults=False, save_config=True):
if not config_file:
config_file = sickrage.app.config_file
if not os.access(sickrage.app.config_file, os.W_OK):
if os.path.isfile(sickrage.app.config_file):
raise SystemExit("Config file '{}' must be writeable.".format(sickrage.app.config_file))
elif not os.access(os.path.dirname(sickrage.app.config_file), os.W_OK):
raise SystemExit(
"Config file root dir '{}' must be writeable.".format(os.path.dirname(sickrage.app.config_file)))
if not os.path.isabs(config_file):
config_file = os.path.abspath(os.path.join(sickrage.app.data_dir, config_file))
if not os.access(config_file, os.W_OK):
if os.path.isfile(config_file):
raise SystemExit("Config file '{}' must be writeable.".format(config_file))
elif not os.access(os.path.dirname(config_file), os.W_OK):
raise SystemExit("Config file root dir '{}' must be writeable.".format(os.path.dirname(config_file)))
# decrypt config
if os.path.exists(sickrage.app.config_file):
if os.path.exists(config_file):
try:
with io.BytesIO() as buffer, open(sickrage.app.config_file, 'rb') as fd:
with io.BytesIO() as buffer, open(config_file, 'rb') as fd:
buffer.write(encryption.decrypt_string(fd.read(), sickrage.app.private_key))
buffer.seek(0)
self.config_obj = ConfigObj(buffer, encoding='utf8')
except (AttributeError, ValueError):
# old encryption from python 2
self.config_obj = ConfigObj(sickrage.app.config_file, encoding='utf8')
self.config_obj = ConfigObj(config_file, encoding='utf8')
self.config_obj.walk(self.decrypt)
self.config_obj = self.config_obj or ConfigObj(encoding='utf8')
......@@ -1875,7 +1876,8 @@ class Config(object):
self.loaded = True
# save config settings
self.save()
if save_config:
self.save()
def save(self):
# dont bother saving settings if there not loaded
......@@ -2362,13 +2364,18 @@ class Config(object):
})
# encrypt config
with io.BytesIO() as buffer, open(sickrage.app.config_file + '.tmp', 'wb') as fd:
new_config.write(buffer)
buffer.seek(0)
fd.write(encryption.encrypt_string(buffer.read(), sickrage.app.public_key))
try:
with io.BytesIO() as buffer, open(sickrage.app.config_file, 'wb') as fd:
new_config.write(buffer)
buffer.seek(0)
fd.write(encryption.encrypt_string(buffer.read(), sickrage.app.public_key))
self.load(config_file=sickrage.app.config_file + '.tmp', save_config=False)
sickrage.app.log.debug("Saved encrypted config to disk")
except sickrage.core.api.exceptions.APIError:
move_file(sickrage.app.config_file + '.tmp', sickrage.app.config_file)
except Exception as e:
sickrage.app.log.debug("Failed to save encrypted config to disk")
os.remove(sickrage.app.config_file + '.tmp')
return False
return True
......
......@@ -37,7 +37,6 @@ import string
import tempfile
import time
import traceback
import unicodedata
import uuid
import webbrowser
import zipfile
......@@ -47,6 +46,7 @@ from urllib.parse import uses_netloc, urlsplit, urlunsplit, urljoin
import rarfile
import requests
import unicodedata
from bs4 import BeautifulSoup
import sickrage
......
......@@ -81,7 +81,7 @@ def set_last_refresh(ex_list, session=None):
@CacheDB.with_session
def retrieve_exceptions(get_xem=True, get_anidb=True, session=None):
def retrieve_exceptions(get_xem=True, get_anidb=True, force=False, session=None):
"""
Looks up the exceptions on github, parses them into a dict, and inserts them into the
scene_exceptions table in cache db and also clears the scene name cache.
......@@ -92,7 +92,7 @@ def retrieve_exceptions(get_xem=True, get_anidb=True, session=None):
for indexer in IndexerApi().indexers:
indexer_name = IndexerApi(indexer).name
if should_refresh(indexer_name):
if should_refresh(indexer_name) or force:
sickrage.app.log.info("Checking for SiCKRAGE scene exception updates on {}".format(indexer_name))
loc = IndexerApi(indexer).config['scene_loc']
......@@ -119,11 +119,11 @@ def retrieve_exceptions(get_xem=True, get_anidb=True, session=None):
# XEM scene exceptions
if get_xem:
_xem_exceptions_fetcher()
_xem_exceptions_fetcher(force)
# AniDB scene exceptions
if get_anidb:
_anidb_exceptions_fetcher()
_anidb_exceptions_fetcher(force)
for cur_indexer_id, cur_exception_dict in exception_dict.copy().items():
if not len(cur_exception_dict):
......@@ -238,7 +238,7 @@ def get_scene_exception_by_name_multiple(show_name, session=None):
if exception_result.count():
return [(int(x.indexer_id), int(x.season)) for x in exception_result]
# FIXME: Handle show names that are encoded
# FIXME: Handle show names that are encoded in byte format
for cur_exception in session.query(CacheDB.SceneException).order_by(CacheDB.SceneException.season):
cur_exception_name = cur_exception.show_name
cur_indexer_id = int(cur_exception.indexer_id)
......@@ -282,8 +282,8 @@ def update_scene_exceptions(indexer_id, scene_exceptions, season=-1, session=Non
session.bulk_insert_mappings(CacheDB.SceneException, sql_t)
def _anidb_exceptions_fetcher():
if should_refresh('anidb'):
def _anidb_exceptions_fetcher(force=False):
if should_refresh('anidb') or force:
sickrage.app.log.info("Checking for AniDB scene exception updates")
for show in get_show_list():
if show.is_anime and show.indexer == 1:
......@@ -306,12 +306,11 @@ def _anidb_exceptions_fetcher():
return anidb_exception_dict
def _xem_exceptions_fetcher():
if should_refresh('xem'):
def _xem_exceptions_fetcher(force=False):
if should_refresh('xem') or force:
sickrage.app.log.info("Checking for XEM scene exception updates")
for indexer in IndexerApi().indexers:
url = "http://thexem.de/map/allNames?origin=%s&seasonNumbers=1" % IndexerApi(indexer).config[
'xem_origin']
......
......@@ -81,7 +81,7 @@ from sickrage.core.webserver.handlers.manage.queues import ManageQueuesHandler,
from sickrage.core.webserver.handlers.root import RobotsDotTxtHandler, MessagesDotPoHandler, \
APIBulderHandler, SetHomeLayoutHandler, SetPosterSortByHandler, SetPosterSortDirHandler, \
ToggleDisplayShowSpecialsHandler, SetScheduleLayoutHandler, ToggleScheduleDisplayPausedHandler, \
SetScheduleSortHandler, ScheduleHandler, UnlinkHandler, QuicksearchDotJsonHandler, SetHistoryLayoutHandler
SetScheduleSortHandler, ScheduleHandler, UnlinkHandler, QuicksearchDotJsonHandler, SetHistoryLayoutHandler, ForceSchedulerJobHandler
from sickrage.core.webserver.handlers.web_file_browser import WebFileBrowserHandler, WebFileBrowserCompleteHandler
from sickrage.core.websocket import WebSocketUIHandler
......@@ -225,6 +225,7 @@ class WebServer(object):
(r'%s/toggleDisplayShowSpecials(/?)' % sickrage.app.config.web_root, ToggleDisplayShowSpecialsHandler),
(r'%s/toggleScheduleDisplayPaused(/?)' % sickrage.app.config.web_root, ToggleScheduleDisplayPausedHandler),
(r'%s/setScheduleSort(/?)' % sickrage.app.config.web_root, SetScheduleSortHandler),
(r'%s/forceSchedulerJob(/?)' % sickrage.app.config.web_root, ForceSchedulerJobHandler),
(r'%s/schedule(/?)' % sickrage.app.config.web_root, ScheduleHandler),
(r'%s/unlink(/?)' % sickrage.app.config.web_root, UnlinkHandler),
(r'%s/setScheduleLayout(/?)' % sickrage.app.config.web_root, SetScheduleLayoutHandler),
......
......@@ -58,6 +58,6 @@ class ConfigHandler(BaseHandler, ABC):
class ConfigResetHandler(BaseHandler, ABC):
@authenticated
def get(self, *args, **kwargs):
sickrage.app.config.load(True)
sickrage.app.config.load(defaults=True)
sickrage.app.alerts.message(_('Configuration Reset to Defaults'), os.path.join(sickrage.app.config_file))
return self.redirect("/config/general")
......@@ -655,7 +655,7 @@ class ServerStatusHandler(BaseHandler, ABC):
tvdirFree=tvdir_free,
rootDir=root_dir,
controller='home',
action='status'
action='server_status'
)
......
......@@ -261,3 +261,13 @@ class QuicksearchDotJsonHandler(BaseHandler, ABC):
}]
return self.write(json.dumps(shows + episodes))
class ForceSchedulerJobHandler(BaseHandler, ABC):
@authenticated
def get(self, *args, **kwargs):
name = self.get_argument('name')
service = getattr(sickrage.app, name, None)
if service:
job = sickrage.app.scheduler.get_job(service.name).func(True)
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -12,6 +12,7 @@
_('Daily Search'): 'daily_searcher',
_('Backlog'): 'backlog_searcher',
_('Show Update'): 'show_updater',
_('Scene Exceptions'): 'name_cache',
}
if sickrage.app.config.version_notify:
......@@ -42,6 +43,7 @@
<th>${_('Active')}</th>
<th>${_('Cycle Time')}</th>
<th>${_('Next Run')}</th>
<th>${_('Action')}</th>
</tr>
</thead>
<tbody>
......@@ -91,9 +93,13 @@
<td align="center"></td>
% endif
% endif
<td align="center">
<button class="btn forceSchedulerJob"
data-target="${srWebRoot}/forceSchedulerJob?name=${scheduler}">
<i class="fa fa-exclamation-triangle"></i> ${_('Force')}
</button>
</td>
</tr>
<% del job %>
<% del service %>
% endfor
</tbody>
</table>
......
......@@ -20,12 +20,14 @@
</div>
<div class="card-body">
<a class="btn" href="${srWebRoot}/manage/manageQueues/forceBacklogSearch">
<i class="icon-exclamation-sign"></i>${_('Force')}
</a>
<a class="btn"
href="${srWebRoot}/manage/manageQueues/pauseBacklogSearcher?paused=${('1', '0')[bool(backlogSearchPaused)]}">
<i class="icon-${('paused', 'play')[bool(backlogSearchPaused)]}"></i>${(_('Pause'), _('Unpause'))[bool(backlogSearchPaused)]}
<i class="fa fa-exclamation-triangle"></i> ${_('Force')}
</a>
% if postProcessorRunning:
<a class="btn"
href="${srWebRoot}/manage/manageQueues/pauseBacklogSearcher?paused=${('1', '0')[bool(backlogSearchPaused)]}">
<i class="fa fa-${('pause', 'play')[bool(backlogSearchPaused)]}"></i> ${(_('Pause'), _('Unpause'))[bool(backlogSearchPaused)]}
</a>
% endif
</div>
</div>
......@@ -38,12 +40,14 @@
</div>
<div class="card-body">
<a class="btn" href="${srWebRoot}/manage/manageQueues/forceDailySearch">
<i class="icon-exclamation-sign"></i>${_('Force')}
</a>
<a class="btn"
href="${srWebRoot}/manage/manageQueues/pauseDailySearcher?paused=${('1', '0')[bool(dailySearchPaused)]}">
<i class="icon-${('paused', 'play')[bool(dailySearchPaused)]}"></i>${(_('Pause'), _('Unpause'))[bool(dailySearchPaused)]}
<i class="fa fa-exclamation-triangle"></i> ${_('Force')}
</a>
% if postProcessorRunning:
<a class="btn"
href="${srWebRoot}/manage/manageQueues/pauseDailySearcher?paused=${('1', '0')[bool(dailySearchPaused)]}">
<i class="fa fa-${('pause', 'play')[bool(dailySearchPaused)]}"></i> ${(_('Pause'), _('Unpause'))[bool(dailySearchPaused)]}
</a>
% endif
</div>
</div>
......@@ -63,7 +67,7 @@
<div class="card-body">
<a class="btn ${('disabled', '')[bool(sickrage.app.config.download_propers)]}"
href="${srWebRoot}/manage/manageQueues/forceFindPropers">
<i class="icon-exclamation-sign"></i>Force
<i class="fa fa-exclamation-triangle"></i> Force
</a>
</div>
</div>
......@@ -76,10 +80,12 @@
</h3>
</div>
<div class="card-body">
<a class="btn"
href="${srWebRoot}/manage/manageQueues/pausePostProcessor?paused=${('1', '0')[bool(postProcessorPaused)]}">
<i class="icon-${('paused', 'play')[bool(postProcessorPaused)]}"></i>${(_('Pause'), _('Unpause'))[bool(postProcessorPaused)]}
</a>
% if postProcessorRunning:
<a class="btn"
href="${srWebRoot}/manage/manageQueues/pausePostProcessor?paused=${('1', '0')[bool(postProcessorPaused)]}">
<i class="fa fa-${('pause', 'play')[bool(postProcessorPaused)]}"></i> ${(_('Pause'), _('Unpause'))[bool(postProcessorPaused)]}
</a>
% endif
</div>
</div>
......
......@@ -1597,19 +1597,6 @@ $(document).ready(function ($) {
//}
//});
},
status: function () {
$("#schedulerStatusTable").tablesorter({
theme: 'bootstrap',
widgets: ['saveSort']
});
$("#queueStatusTable").tablesorter({
theme: 'bootstrap',
sortList: [[3, 0], [4, 0], [2, 1]],
widgets: ['saveSort']
});
}
},
home: {
......@@ -1917,6 +1904,7 @@ $(document).ready(function ($) {
}
});
},
display_show: {
init: function () {
SICKRAGE.home.display_show.imdbRating();
......@@ -2890,6 +2878,26 @@ $(document).ready(function ($) {
} else {
$('#blackwhitelist').hide();
}
},
server_status: {
init: function () {
$("#schedulerStatusTable").tablesorter({
theme: 'bootstrap',
widgets: ['saveSort']
});
$("#queueStatusTable").tablesorter({
theme: 'bootstrap',
sortList: [[3, 0], [4, 0], [2, 1]],
widgets: ['saveSort']
});
$('.forceSchedulerJob').click(function (e) {
e.preventDefault();
$.get($(this).data('target'));
});
}
}
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment