mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-01 08:53:37 +00:00
8d9406d5fc
Add episode watched state system that integrates with Kodi, Plex, and/or Emby, instructions at Shows/History/Layout/"Watched". Add installable SickGear Kodi repository containing addon "SickGear Watched State Updater". Change add Emby setting for watched state scheduler at Config/Notifications/Emby/"Update watched interval". Change add Plex setting for watched state scheduler at Config/Notifications/Plex/"Update watched interval". Add API cmd=sg.updatewatchedstate, instructions for use are linked to in layout "Watched" at /history. Change history page table filter input values are saved across page refreshes. Change history page table filter inputs, accept values like "dvd or web" to only display both. Change history page table filter inputs, press 'ESC' key inside a filter input to reset it. Add provider activity stats to Shows/History/Layout/ drop down. Change move provider failures table from Manage/Media Search to Shows/History/Layout/Provider fails. Change sort provider failures by most recent failure, and with paused providers at the top. Change remove table form non-testing version 20007, that was reassigned.
156 lines
7.4 KiB
Python
156 lines
7.4 KiB
Python
import os
|
|
import threading
|
|
import sys
|
|
import sickbeard
|
|
import webserve
|
|
import webapi
|
|
|
|
from sickbeard import logger
|
|
from sickbeard.helpers import create_https_certificates
|
|
from tornado.web import Application
|
|
from tornado.httpserver import HTTPServer
|
|
from tornado.ioloop import IOLoop
|
|
|
|
|
|
class WebServer(threading.Thread):
|
|
def __init__(self, options={}, io_loop=None):
|
|
threading.Thread.__init__(self)
|
|
self.daemon = True
|
|
self.alive = True
|
|
self.name = 'TORNADO'
|
|
self.io_loop = io_loop or IOLoop.current()
|
|
self.server = None
|
|
|
|
self.options = options
|
|
self.options.setdefault('port', 8081)
|
|
self.options.setdefault('host', '0.0.0.0')
|
|
self.options.setdefault('log_dir', None)
|
|
self.options.setdefault('username', '')
|
|
self.options.setdefault('password', '')
|
|
self.options.setdefault('web_root', None)
|
|
assert isinstance(self.options['port'], int)
|
|
assert 'data_root' in self.options
|
|
|
|
# web root
|
|
self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/')) if self.options['web_root'] else ''
|
|
|
|
# tornado setup
|
|
self.enable_https = self.options['enable_https']
|
|
self.https_cert = self.options['https_cert']
|
|
self.https_key = self.options['https_key']
|
|
|
|
if self.enable_https:
|
|
# If either the HTTPS certificate or key do not exist, make some self-signed ones.
|
|
if not (self.https_cert and os.path.exists(self.https_cert))\
|
|
or not (self.https_key and os.path.exists(self.https_key)):
|
|
if not create_https_certificates(self.https_cert, self.https_key):
|
|
logger.log(u'Unable to create CERT/KEY files, disabling HTTPS')
|
|
sickbeard.ENABLE_HTTPS = False
|
|
self.enable_https = False
|
|
|
|
if not (os.path.exists(self.https_cert) and os.path.exists(self.https_key)):
|
|
logger.log(u'Disabled HTTPS because of missing CERT and KEY files', logger.WARNING)
|
|
sickbeard.ENABLE_HTTPS = False
|
|
self.enable_https = False
|
|
|
|
# Load the app
|
|
self.app = Application([],
|
|
debug=True,
|
|
autoreload=False,
|
|
gzip=True,
|
|
cookie_secret=sickbeard.COOKIE_SECRET,
|
|
login_url='%s/login/' % self.options['web_root'])
|
|
|
|
# webui login/logout handlers
|
|
self.app.add_handlers('.*$', [
|
|
(r'%s/login(/?)' % self.options['web_root'], webserve.LoginHandler),
|
|
(r'%s/logout(/?)' % self.options['web_root'], webserve.LogoutHandler),
|
|
])
|
|
|
|
# Web calendar handler (Needed because option Unprotected calendar)
|
|
self.app.add_handlers('.*$', [
|
|
(r'%s/calendar' % self.options['web_root'], webserve.CalendarHandler),
|
|
])
|
|
|
|
# Static File Handlers
|
|
self.app.add_handlers('.*$', [
|
|
# favicon
|
|
(r'%s/(favicon\.ico)' % self.options['web_root'], webserve.BaseStaticFileHandler,
|
|
{'path': os.path.join(self.options['data_root'], 'images/ico/favicon.ico')}),
|
|
|
|
# images
|
|
(r'%s/images/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,
|
|
{'path': os.path.join(self.options['data_root'], 'images')}),
|
|
|
|
# cached images
|
|
(r'%s/cache/images/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,
|
|
{'path': os.path.join(sickbeard.CACHE_DIR, 'images')}),
|
|
|
|
# css
|
|
(r'%s/css/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,
|
|
{'path': os.path.join(self.options['data_root'], 'css')}),
|
|
|
|
# javascript
|
|
(r'%s/js/(.*)' % self.options['web_root'], webserve.BaseStaticFileHandler,
|
|
{'path': os.path.join(self.options['data_root'], 'js')}),
|
|
|
|
(r'%s/kodi/(.*)' % self.options['web_root'], webserve.RepoHandler,
|
|
{'path': os.path.join(sickbeard.CACHE_DIR, 'clients', 'kodi'),
|
|
'default_filename': 'index.html'}),
|
|
])
|
|
|
|
# Main Handler
|
|
self.app.add_handlers('.*$', [
|
|
(r'%s/api/builder(/?)(.*)' % self.options['web_root'], webserve.ApiBuilder),
|
|
(r'%s/api(/?.*)' % self.options['web_root'], webapi.Api),
|
|
(r'%s/imagecache(/?.*)' % self.options['web_root'], webserve.CachedImages),
|
|
(r'%s/cache(/?.*)' % self.options['web_root'], webserve.Cache),
|
|
(r'%s/config/general(/?.*)' % self.options['web_root'], webserve.ConfigGeneral),
|
|
(r'%s/config/search(/?.*)' % self.options['web_root'], webserve.ConfigSearch),
|
|
(r'%s/config/providers(/?.*)' % self.options['web_root'], webserve.ConfigProviders),
|
|
(r'%s/config/subtitles(/?.*)' % self.options['web_root'], webserve.ConfigSubtitles),
|
|
(r'%s/config/postProcessing(/?.*)' % self.options['web_root'], webserve.ConfigPostProcessing),
|
|
(r'%s/config/notifications(/?.*)' % self.options['web_root'], webserve.ConfigNotifications),
|
|
(r'%s/config/anime(/?.*)' % self.options['web_root'], webserve.ConfigAnime),
|
|
(r'%s/config(/?.*)' % self.options['web_root'], webserve.Config),
|
|
(r'%s/errorlogs(/?.*)' % self.options['web_root'], webserve.ErrorLogs),
|
|
(r'%s/history(/?.*)' % self.options['web_root'], webserve.History),
|
|
(r'%s/home/is_alive(/?.*)' % self.options['web_root'], webserve.IsAliveHandler),
|
|
(r'%s/home/addShows(/?.*)' % self.options['web_root'], webserve.NewHomeAddShows),
|
|
(r'%s/home/postprocess(/?.*)' % self.options['web_root'], webserve.HomePostProcess),
|
|
(r'%s/home(/?.*)' % self.options['web_root'], webserve.Home),
|
|
(r'%s/manage/manageSearches(/?.*)' % self.options['web_root'], webserve.ManageSearches),
|
|
(r'%s/manage/showProcesses(/?.*)' % self.options['web_root'], webserve.showProcesses),
|
|
(r'%s/manage/(/?.*)' % self.options['web_root'], webserve.Manage),
|
|
(r'%s/ui(/?.*)' % self.options['web_root'], webserve.UI),
|
|
(r'%s/browser(/?.*)' % self.options['web_root'], webserve.WebFileBrowser),
|
|
(r'%s(/?.*)' % self.options['web_root'], webserve.MainHandler),
|
|
])
|
|
|
|
def run(self):
|
|
protocol, ssl_options = (('http', None),
|
|
('https', {'certfile': self.https_cert, 'keyfile': self.https_key}))[self.enable_https]
|
|
|
|
logger.log(u'Starting SickGear on ' + protocol + '://' + str(self.options['host']) + ':' + str(
|
|
self.options['port']) + '/')
|
|
|
|
try:
|
|
self.server = self.app.listen(self.options['port'], self.options['host'], ssl_options=ssl_options,
|
|
xheaders=sickbeard.HANDLE_REVERSE_PROXY, protocol=protocol)
|
|
except (StandardError, Exception):
|
|
etype, evalue, etb = sys.exc_info()
|
|
logger.log(
|
|
'Could not start webserver on %s. Excpeption: %s, Error: %s' % (self.options['port'], etype, evalue),
|
|
logger.ERROR)
|
|
return
|
|
|
|
try:
|
|
self.io_loop.start()
|
|
self.io_loop.close(True)
|
|
except (IOError, ValueError):
|
|
# Ignore errors like 'ValueError: I/O operation on closed kqueue fd'. These might be thrown during a reload.
|
|
pass
|
|
|
|
def shutDown(self):
|
|
self.alive = False
|
|
self.io_loop.stop()
|