1
0
mirror of https://github.com/moparisthebest/SickRage synced 2024-12-12 11:02:21 -05:00

Merge remote-tracking branch 'origin/develop' into develop

Conflicts:
	sickbeard/webapi.py
This commit is contained in:
echel0n 2014-12-07 13:00:18 -08:00
commit e7de90f688
7 changed files with 320 additions and 358 deletions

View File

@ -45,7 +45,7 @@ function goListGroup(apikey, L7, L6, L5, L4, L3, L2, L1){
html += $.ajax({
url: sbRoot + "/api/" + apikey + "/" + L1 + L2 + L3 + L4 + L5 + L6 + L7 + GlobalOptions,
async: false,
dataType: "html",
dataType: "html"
}).responseText;
html += '</pre>';

View File

@ -58,7 +58,7 @@ $(document).ready(function(){
$('#api_key').click(function(){ $('#api_key').select() });
$("#generate_new_apikey").click(function(){
$.get(sbRoot + '/config/general/generateKey',
$.get(sbRoot + '/config/general/generateApiKey',
function(data){
if (data.error != undefined) {
alert(data.error);

View File

@ -145,6 +145,7 @@ ANON_REDIRECT = None
USE_API = False
API_KEY = None
API_ROOT = None
ENABLE_HTTPS = False
HTTPS_CERT = None
@ -480,7 +481,7 @@ def get_backlog_cycle_time():
def initialize(consoleLogging=True):
with INIT_LOCK:
global BRANCH, GIT_REMOTE, GIT_REMOTE_URL, CUR_COMMIT_HASH, CUR_COMMIT_BRANCH, ACTUAL_LOG_DIR, LOG_DIR, WEB_PORT, WEB_LOG, ENCRYPTION_VERSION, WEB_ROOT, WEB_USERNAME, WEB_PASSWORD, WEB_HOST, WEB_IPV6, USE_API, API_KEY, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, \
global BRANCH, GIT_REMOTE, GIT_REMOTE_URL, CUR_COMMIT_HASH, CUR_COMMIT_BRANCH, ACTUAL_LOG_DIR, LOG_DIR, WEB_PORT, WEB_LOG, ENCRYPTION_VERSION, WEB_ROOT, WEB_USERNAME, WEB_PASSWORD, WEB_HOST, WEB_IPV6, USE_API, API_KEY, API_ROOT, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, \
HANDLE_REVERSE_PROXY, USE_NZBS, USE_TORRENTS, NZB_METHOD, NZB_DIR, DOWNLOAD_PROPERS, RANDOMIZE_PROVIDERS, CHECK_PROPERS_INTERVAL, ALLOW_HIGH_PRIORITY, TORRENT_METHOD, \
SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, SAB_CATEGORY_ANIME, SAB_HOST, \
NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_CATEGORY_ANIME, NZBGET_PRIORITY, NZBGET_HOST, NZBGET_USE_HTTPS, backlogSearchScheduler, \

View File

@ -20,6 +20,7 @@ from __future__ import with_statement
import getpass
import os
import random
import re
import shutil
import socket
@ -1433,3 +1434,27 @@ def get_size(start_path='.'):
def md5(text):
return hashlib.md5(ek.ss(text)).hexdigest()
def generateApiKey(*args, **kwargs):
""" Return a new randomized API_KEY
"""
try:
from hashlib import md5
except ImportError:
from md5 import md5
# Create some values to seed md5
t = str(time.time())
r = str(random.random())
# Create the md5 instance and give it the current time
m = md5(t)
# Update the md5 instance with the random variable
m.update(r)
# Return a hex digest of the md5, eg 49f68a5c8493ec2c0bf489821c21fc3b
logger.log(u"New API generated")
return m.hexdigest()

View File

@ -28,7 +28,6 @@ import traceback
import sickbeard
from sickbeard.webserve import PageTemplate
from sickbeard import db, logger, exceptions, history, ui, helpers
from sickbeard import encodingKludge as ek
from sickbeard import search_queue
@ -48,7 +47,6 @@ except ImportError:
from lib import subliminal
from tornado.web import RequestHandler
from tornado.routes import route
indexer_ids = ["indexerid", "tvdbid", "tvrageid"]
@ -71,46 +69,32 @@ result_type_map = {RESULT_SUCCESS: "success",
}
# basically everything except RESULT_SUCCESS / success is bad
@route('/api/(.*)(/?)')
class ApiHandler(RequestHandler):
""" api class that returns json results """
version = 4 # use an int since float-point is unpredictible
intent = 4
def index(self, *args, **kwargs):
self.apiKey = sickbeard.API_KEY
access, accessMsg, args, kwargs = self._grand_access(self.apiKey, args, kwargs)
def get(self, *args, **kwargs):
# set the output callback
# default json
outputCallbackDict = {'default': self._out_as_json,
'image': lambda x: x['image'],
}
# do we have acces ?
if access:
logger.log(accessMsg, logger.DEBUG)
else:
logger.log(accessMsg, logger.WARNING)
return outputCallbackDict['default'](_responds(RESULT_DENIED, msg=accessMsg))
# set the original call_dispatcher as the local _call_dispatcher
_call_dispatcher = call_dispatcher
_call_dispatcher = self.call_dispatcher
# if profile was set wrap "_call_dispatcher" in the profile function
if 'profile' in kwargs:
if self.get_argument('profile', None):
from lib.profilehooks import profile
_call_dispatcher = profile(_call_dispatcher, immediate=True)
del kwargs["profile"]
# if debug was set call the "_call_dispatcher"
if 'debug' in kwargs:
outDict = _call_dispatcher(self, args,
kwargs) # this way we can debug the cherry.py traceback in the browser
del kwargs["debug"]
if self.get_argument('debug', None):
outDict = _call_dispatcher(args, kwargs) # this way we can debug the cherry.py traceback in the browser
else: # if debug was not set we wrap the "call_dispatcher" in a try block to assure a json output
try:
outDict = _call_dispatcher(self, args, kwargs)
outDict = _call_dispatcher(args, kwargs)
except Exception, e: # real internal error oohhh nooo :(
logger.log(u"API :: " + ex(e), logger.ERROR)
errorData = {"error_msg": ex(e),
@ -124,47 +108,7 @@ class ApiHandler(RequestHandler):
else:
outputCallback = outputCallbackDict['default']
return outputCallback(outDict)
def builder(self):
""" expose the api-builder template """
t = PageTemplate(headers=self.request.headers, file="apiBuilder.tmpl")
def titler(x):
if not x or sickbeard.SORT_ARTICLE:
return x
if x.lower().startswith('a '):
x = x[2:]
elif x.lower().startswith('an '):
x = x[3:]
elif x.lower().startswith('the '):
x = x[4:]
return x
t.sortedShowList = sorted(sickbeard.showList, lambda x, y: cmp(titler(x.name), titler(y.name)))
seasonSQLResults = {}
episodeSQLResults = {}
myDB = db.DBConnection(row_type="dict")
for curShow in t.sortedShowList:
seasonSQLResults[curShow.indexerid] = myDB.select(
"SELECT DISTINCT season FROM tv_episodes WHERE showid = ? ORDER BY season DESC", [curShow.indexerid])
for curShow in t.sortedShowList:
episodeSQLResults[curShow.indexerid] = myDB.select(
"SELECT DISTINCT season,episode FROM tv_episodes WHERE showid = ? ORDER BY season DESC, episode DESC",
[curShow.indexerid])
t.seasonSQLResults = seasonSQLResults
t.episodeSQLResults = episodeSQLResults
if len(sickbeard.API_KEY) == 32:
t.apikey = sickbeard.API_KEY
else:
t.apikey = "api key not generated"
return t
return self.write(outputCallback(outDict))
def _out_as_json(self, dict):
self.set_header("Content-Type", "application/json;charset=UTF-8'")
@ -179,39 +123,14 @@ class ApiHandler(RequestHandler):
e) + '"}'
return out
def _grand_access(self, realKey, args, kwargs):
""" validate api key and log result """
remoteIp = self.request.remote_ip
apiKey = kwargs.get("apikey", None)
if not apiKey:
if args: # if we have keyless vars we assume first one is the api key, always !
apiKey = args[0]
args = args[1:] # remove the apikey from the args tuple
else:
del kwargs["apikey"]
if not sickbeard.USE_API:
msg = u"API :: " + remoteIp + " - SR API Disabled. ACCESS DENIED"
return False, msg, args, kwargs
elif apiKey == realKey:
msg = u"API :: " + remoteIp + " - gave correct API KEY - [" + apiKey + "] - ACCESS GRANTED"
return True, msg, args, kwargs
elif not apiKey:
msg = u"API :: " + remoteIp + " - gave NO API KEY. ACCESS DENIED"
return False, msg, args, kwargs
else:
msg = u"API :: " + remoteIp + " - gave WRONG API KEY - [" + apiKey + "] - ACCESS DENIED"
return False, msg, args, kwargs
def call_dispatcher(handler, args, kwargs):
def call_dispatcher(self, args, kwargs):
""" calls the appropriate CMD class
looks for a cmd in args and kwargs
or calls the TVDBShorthandWrapper when the first args element is a number
or returns an error that there is no such cmd
"""
logger.log(u"API :: all args: '" + str(args) + "'", logger.DEBUG)
logger.log(u"API :: all kwargs: '" + str(kwargs) + "'", logger.DEBUG)
logger.log(u"API :: all args: '" + str(self.get_arguments('cmd')) + "'", logger.DEBUG)
# logger.log(u"API :: dateFormat: '" + str(dateFormat) + "'", logger.DEBUG)
cmds = None
@ -228,7 +147,7 @@ def call_dispatcher(handler, args, kwargs):
cmds = cmds.split("|")
multiCmds = bool(len(cmds) > 1)
for cmd in cmds:
curArgs, curKwargs = filter_params(cmd, args, kwargs)
curArgs, curKwargs = self.filter_params(cmd, args, kwargs)
cmdIndex = None
if len(cmd.split("_")) > 1: # was a index used for this cmd ?
cmd, cmdIndex = cmd.split("_") # this gives us the clear cmd and the index
@ -237,10 +156,9 @@ def call_dispatcher(handler, args, kwargs):
if not (multiCmds and cmd in ('show.getposter', 'show.getbanner')): # skip these cmd while chaining
try:
if cmd in _functionMaper:
curOutDict = _functionMaper.get(cmd)(handler, curArgs,
curKwargs).run() # get the cmd class, init it and run()
curOutDict = _functionMaper.get(cmd)(curArgs, curKwargs).run()
elif _is_int(cmd):
curOutDict = TVDBShorthandWrapper(handler, curArgs, curKwargs, cmd).run()
curOutDict = TVDBShorthandWrapper(curArgs, curKwargs, cmd).run()
else:
curOutDict = _responds(RESULT_ERROR, "No such cmd: '" + cmd + "'")
except ApiError, e: # Api errors that we raised, they are harmless
@ -264,12 +182,12 @@ def call_dispatcher(handler, args, kwargs):
if multiCmds: # if we had multiple cmds we have to wrap it in a response dict
outDict = _responds(RESULT_SUCCESS, outDict)
else: # index / no cmd given
outDict = CMD_SickBeard(handler, args, kwargs).run()
outDict = CMD_SickBeard(args, kwargs).run()
return outDict
def filter_params(cmd, args, kwargs):
def filter_params(self, cmd, args, kwargs):
""" return only params kwargs that are for cmd
and rename them to a clean version (remove "<cmd>_")
args are shared across all cmds
@ -306,19 +224,17 @@ def filter_params(cmd, args, kwargs):
class ApiCall(ApiHandler):
_help = {"desc": "No help message available. Please tell the devs that a help msg is missing for this cmd"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# missing
try:
if self._missing:
self.run = self.return_missing
except AttributeError:
pass
# help
if 'help' in kwargs:
self.run = self.return_help
# RequestHandler
self.handler = handler
# help
if self.get_argument('help', None):
self.run = self.return_help
def run(self):
# override with real output function in subclass
@ -492,8 +408,7 @@ class ApiCall(ApiHandler):
class TVDBShorthandWrapper(ApiCall):
_help = {"desc": "this is an internal function wrapper. call the help command directly for more information"}
def __init__(self, handler, args, kwargs, sid):
self.handler = handler
def __init__(self, args, kwargs, sid):
self.origArgs = args
self.kwargs = kwargs
self.sid = sid
@ -502,17 +417,17 @@ class TVDBShorthandWrapper(ApiCall):
self.e, args = self.check_params(args, kwargs, "e", None, False, "ignore", [])
self.args = args
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" internal function wrapper """
args = (self.sid,) + self.origArgs
if self.e:
return CMD_Episode(self.handler, args, self.kwargs).run()
return CMD_Episode(args, self.kwargs).run()
elif self.s:
return CMD_ShowSeasons(self.handler, args, self.kwargs).run()
return CMD_ShowSeasons(args, self.kwargs).run()
else:
return CMD_Show(self.handler, args, self.kwargs).run()
return CMD_Show(args, self.kwargs).run()
# ###############################
@ -697,12 +612,12 @@ class CMD_Help(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.subject, args = self.check_params(args, kwargs, "subject", "help", False, "string",
_functionMaper.keys())
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display help information for a given subject/command """
@ -722,7 +637,7 @@ class CMD_ComingEpisodes(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.sort, args = self.check_params(args, kwargs, "sort", "date", False, "string",
@ -734,7 +649,7 @@ class CMD_ComingEpisodes(ApiCall):
False, "int",
[0, 1])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display the coming episodes """
@ -847,7 +762,7 @@ class CMD_Episode(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
self.s, args = self.check_params(args, kwargs, "season", None, True, "int", [])
@ -855,7 +770,7 @@ class CMD_Episode(ApiCall):
# optional
self.fullPath, args = self.check_params(args, kwargs, "full_path", 0, False, "bool", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display detailed info about an episode """
@ -911,14 +826,14 @@ class CMD_EpisodeSearch(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
self.s, args = self.check_params(args, kwargs, "season", None, True, "int", [])
self.e, args = self.check_params(args, kwargs, "episode", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" search for an episode """
@ -965,7 +880,7 @@ class CMD_EpisodeSetStatus(ApiCall):
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
self.s, args = self.check_params(args, kwargs, "season", None, True, "int", [])
@ -975,7 +890,7 @@ class CMD_EpisodeSetStatus(ApiCall):
self.e, args = self.check_params(args, kwargs, "episode", None, False, "int", [])
self.force, args = self.check_params(args, kwargs, "force", 0, False, "bool", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" set status of an episode or a season (when no ep is provided) """
@ -1077,14 +992,14 @@ class CMD_SubtitleSearch(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
self.s, args = self.check_params(args, kwargs, "season", None, True, "int", [])
self.e, args = self.check_params(args, kwargs, "episode", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" search episode subtitles """
@ -1130,13 +1045,13 @@ class CMD_Exceptions(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, False, "int", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display scene exceptions for all or a given show """
@ -1173,14 +1088,14 @@ class CMD_History(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.limit, args = self.check_params(args, kwargs, "limit", 100, False, "int", [])
self.type, args = self.check_params(args, kwargs, "type", None, False, "string",
["downloaded", "snatched"])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display sickrage downloaded/snatched history """
@ -1231,11 +1146,11 @@ class CMD_HistoryClear(ApiCall):
_help = {"desc": "clear sickrage's history",
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" clear sickrage's history """
@ -1249,11 +1164,11 @@ class CMD_HistoryTrim(ApiCall):
_help = {"desc": "trim sickrage's history by removing entries greater than 30 days old"
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" trim sickrage's history """
@ -1269,12 +1184,12 @@ class CMD_Failed(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.limit, args = self.check_params(args, kwargs, "limit", 100, False, "int", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display failed downloads """
@ -1292,11 +1207,11 @@ class CMD_Failed(ApiCall):
class CMD_Backlog(ApiCall):
_help = {"desc": "display backlogged episodes"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display backlogged episodes """
@ -1334,13 +1249,13 @@ class CMD_Logs(ApiCall):
"desc": "the minimum level classification of log entries to show, with each level inherting its above level"}}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.min_level, args = self.check_params(args, kwargs, "min_level", "error", False, "string",
["error", "warning", "info", "debug"])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" view sickrage's log """
@ -1400,7 +1315,7 @@ class CMD_PostProcess(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.path, args = self.check_params(args, kwargs, "path", None, False, "string", [])
@ -1412,7 +1327,7 @@ class CMD_PostProcess(ApiCall):
self.type, args = self.check_params(args, kwargs, "type", "auto", None, "string",
["auto", "manual"])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" Starts the postprocess """
@ -1437,11 +1352,11 @@ class CMD_PostProcess(ApiCall):
class CMD_SickBeard(ApiCall):
_help = {"desc": "display misc sickrage related information"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display misc sickrage related information """
@ -1458,13 +1373,13 @@ class CMD_SickBeardAddRootDir(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.location, args = self.check_params(args, kwargs, "location", None, True, "string", [])
# optional
self.default, args = self.check_params(args, kwargs, "default", 0, False, "bool", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" add a parent directory to sickrage's config """
@ -1511,11 +1426,11 @@ class CMD_SickBeardAddRootDir(ApiCall):
class CMD_SickBeardCheckScheduler(ApiCall):
_help = {"desc": "query the scheduler"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" query the scheduler """
@ -1537,12 +1452,12 @@ class CMD_SickBeardDeleteRootDir(ApiCall):
"requiredParameters": {"location": {"desc": "the full path to root (parent) directory"}}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.location, args = self.check_params(args, kwargs, "location", None, True, "string", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" delete a parent directory from sickrage's config """
@ -1581,11 +1496,11 @@ class CMD_SickBeardDeleteRootDir(ApiCall):
class CMD_SickBeardGetDefaults(ApiCall):
_help = {"desc": "get sickrage user defaults"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" get sickrage user defaults """
@ -1601,15 +1516,15 @@ class CMD_SickBeardGetDefaults(ApiCall):
class CMD_SickBeardGetMessages(ApiCall):
_help = {"desc": "get all messages"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
messages = []
for cur_notification in ui.notifications.get_notifications(self.handler.request.remote_ip):
for cur_notification in ui.notifications.get_notifications(self.request.remote_ip):
messages.append({"title": cur_notification.title,
"message": cur_notification.message,
"type": cur_notification.type})
@ -1619,11 +1534,11 @@ class CMD_SickBeardGetMessages(ApiCall):
class CMD_SickBeardGetRootDirs(ApiCall):
_help = {"desc": "get sickrage user parent directories"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" get the parent directories defined in sickrage's config """
@ -1636,12 +1551,12 @@ class CMD_SickBeardPauseBacklog(ApiCall):
"optionalParameters": {"pause ": {"desc": "pause or unpause the global backlog"}}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.pause, args = self.check_params(args, kwargs, "pause", 0, False, "bool", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" pause the backlog search """
@ -1656,15 +1571,15 @@ class CMD_SickBeardPauseBacklog(ApiCall):
class CMD_SickBeardPing(ApiCall):
_help = {"desc": "check to see if sickrage is running"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" check to see if sickrage is running """
self.handler.set_header('Cache-Control', "max-age=0,no-cache,no-store")
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
if sickbeard.started:
return _responds(RESULT_SUCCESS, {"pid": sickbeard.PID}, "Pong")
else:
@ -1674,11 +1589,11 @@ class CMD_SickBeardPing(ApiCall):
class CMD_SickBeardRestart(ApiCall):
_help = {"desc": "restart sickrage"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" restart sickrage """
@ -1702,7 +1617,7 @@ class CMD_SickBeardSearchIndexers(ApiCall):
'de': 14, 'da': 10, 'fi': 11, 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32,
'sv': 8, 'sl': 30}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.name, args = self.check_params(args, kwargs, "name", None, False, "string", [])
@ -1711,7 +1626,7 @@ class CMD_SickBeardSearchIndexers(ApiCall):
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, False, "int", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" search for show at tvdb with a given string and language """
@ -1789,9 +1704,9 @@ class CMD_SickBeardSearchTVDB(CMD_SickBeardSearchIndexers):
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
self.indexerid, args = self.check_params(args, kwargs, "tvdbid", None, False, "int", [])
CMD_SickBeardSearchIndexers.__init__(self, handler, args, kwargs)
CMD_SickBeardSearchIndexers.__init__(self, args, kwargs)
class CMD_SickBeardSearchTVRAGE(CMD_SickBeardSearchIndexers):
@ -1802,9 +1717,9 @@ class CMD_SickBeardSearchTVRAGE(CMD_SickBeardSearchIndexers):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
self.indexerid, args = self.check_params(args, kwargs, "tvrageid", None, False, "int", [])
CMD_SickBeardSearchIndexers.__init__(self, handler, args, kwargs)
CMD_SickBeardSearchIndexers.__init__(self, args, kwargs)
class CMD_SickBeardSetDefaults(ApiCall):
@ -1816,7 +1731,7 @@ class CMD_SickBeardSetDefaults(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.initial, args = self.check_params(args, kwargs, "initial", None, False, "list",
@ -1833,7 +1748,7 @@ class CMD_SickBeardSetDefaults(ApiCall):
self.status, args = self.check_params(args, kwargs, "status", None, False, "string",
["wanted", "skipped", "archived", "ignored"])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" set sickrage user defaults """
@ -1888,11 +1803,11 @@ class CMD_SickBeardSetDefaults(ApiCall):
class CMD_SickBeardShutdown(ApiCall):
_help = {"desc": "shutdown sickrage"}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" shutdown sickrage """
@ -1912,12 +1827,12 @@ class CMD_Show(ApiCall):
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display information for a given show """
@ -1926,8 +1841,8 @@ class CMD_Show(ApiCall):
return _responds(RESULT_FAILURE, msg="Show not found")
showDict = {}
showDict["season_list"] = CMD_ShowSeasonList(self.handler, (), {"indexerid": self.indexerid}).run()["data"]
showDict["cache"] = CMD_ShowCache(self.handler, (), {"indexerid": self.indexerid}).run()["data"]
showDict["season_list"] = CMD_ShowSeasonList((), {"indexerid": self.indexerid}).run()["data"]
showDict["cache"] = CMD_ShowCache((), {"indexerid": self.indexerid}).run()["data"]
genreList = []
if showObj.genre:
@ -2008,7 +1923,7 @@ class CMD_ShowAddExisting(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "", [])
@ -2027,7 +1942,7 @@ class CMD_ShowAddExisting(ApiCall):
self.subtitles, args = self.check_params(args, kwargs, "subtitles", int(sickbeard.USE_SUBTITLES),
False, "int", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" add a show in sickrage with an existing folder """
@ -2039,8 +1954,7 @@ class CMD_ShowAddExisting(ApiCall):
return _responds(RESULT_FAILURE, msg='Not a valid location')
indexerName = None
indexerResult = CMD_SickBeardSearchIndexers(self.handler, [],
{indexer_ids[self.indexer]: self.indexerid}).run()
indexerResult = CMD_SickBeardSearchIndexers([], {indexer_ids[self.indexer]: self.indexerid}).run()
if indexerResult['result'] == result_type_map[RESULT_SUCCESS]:
if not indexerResult['data']['results']:
@ -2111,7 +2025,7 @@ class CMD_ShowAddNew(ApiCall):
'de': 14, 'da': 10, 'fi': 11, 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32,
'sv': 8, 'sl': 30}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
@ -2142,7 +2056,7 @@ class CMD_ShowAddNew(ApiCall):
[])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" add a show in sickrage with an existing folder """
@ -2205,8 +2119,7 @@ class CMD_ShowAddNew(ApiCall):
newStatus = self.status
indexerName = None
indexerResult = CMD_SickBeardSearchIndexers(self.handler, [],
{indexer_ids[self.indexer]: self.indexerid}).run()
indexerResult = CMD_SickBeardSearchIndexers([], {indexer_ids[self.indexer]: self.indexerid}).run()
if indexerResult['result'] == result_type_map[RESULT_SUCCESS]:
if not indexerResult['data']['results']:
@ -2254,12 +2167,12 @@ class CMD_ShowCache(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" check sickrage's cache to see if the banner or poster image for a show is valid """
@ -2295,13 +2208,13 @@ class CMD_ShowDelete(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
self.removefiles, args = self.check_params(args, kwargs, "removefiles", 0, False, "int", [0,1])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" delete a show in sickrage """
@ -2333,12 +2246,12 @@ class CMD_ShowGetQuality(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" get quality setting for a show in sickrage """
@ -2362,16 +2275,16 @@ class CMD_ShowGetPoster(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" get the poster for a show in sickrage """
return {'outputType': 'image', 'image': self.handler.showPoster(self.indexerid, 'poster')}
return {'outputType': 'image', 'image': self.showPoster(self.indexerid, 'poster')}
class CMD_ShowGetBanner(ApiCall):
@ -2385,12 +2298,12 @@ class CMD_ShowGetBanner(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" get the banner for a show in sickrage """
@ -2409,13 +2322,13 @@ class CMD_ShowPause(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
self.pause, args = self.check_params(args, kwargs, "pause", 0, False, "bool", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" set a show's paused state in sickrage """
@ -2441,12 +2354,12 @@ class CMD_ShowRefresh(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" refresh a show in sickrage """
@ -2474,7 +2387,7 @@ class CMD_ShowSeasonList(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
@ -2482,7 +2395,7 @@ class CMD_ShowSeasonList(ApiCall):
["asc",
"desc"]) # "asc" and "desc" default and fallback is "desc"
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display the season list for a given show """
@ -2516,13 +2429,13 @@ class CMD_ShowSeasons(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
self.season, args = self.check_params(args, kwargs, "season", None, False, "int", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display a listing of episodes for all or a given show """
@ -2589,7 +2502,7 @@ class CMD_ShowSetQuality(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
@ -2603,7 +2516,7 @@ class CMD_ShowSetQuality(ApiCall):
"fullhdwebdl",
"hdbluray", "fullhdbluray"])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" set the quality for a show in sickrage by taking in a deliminated
@ -2655,12 +2568,12 @@ class CMD_ShowStats(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display episode statistics for a given show """
@ -2764,12 +2677,12 @@ class CMD_ShowUpdate(ApiCall):
}
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
self.indexerid, args = self.check_params(args, kwargs, "indexerid", None, True, "int", [])
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" update a show in sickrage """
@ -2793,13 +2706,13 @@ class CMD_Shows(ApiCall):
},
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
self.sort, args = self.check_params(args, kwargs, "sort", "id", False, "string", ["id", "name"])
self.paused, args = self.check_params(args, kwargs, "paused", None, False, "bool", [])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display_is_int_multi( self.indexerid )shows in sickrage """
@ -2836,7 +2749,7 @@ class CMD_Shows(ApiCall):
showDict['next_ep_airdate'] = ''
showDict["cache"] = \
CMD_ShowCache(self.handler, (), {"indexerid": curShow.indexerid}).run()["data"]
CMD_ShowCache((), {"indexerid": curShow.indexerid}).run()["data"]
if not showDict["network"]:
showDict["network"] = ""
if self.sort == "name":
@ -2851,11 +2764,11 @@ class CMD_ShowsStats(ApiCall):
_help = {"desc": "display the global shows and episode stats"
}
def __init__(self, handler, args, kwargs):
def __init__(self, args, kwargs):
# required
# optional
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
ApiCall.__init__(self, args, kwargs)
def run(self):
""" display the global shows and episode stats """

View File

@ -17,6 +17,7 @@
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
from __future__ import with_statement
import random
import traceback
import os
@ -24,7 +25,6 @@ import time
import urllib
import re
import datetime
import random
import sys
import sickbeard
@ -133,7 +133,7 @@ def haveTORRENT():
return False
class Menus:
def HomeMenu(self):
def HomeMenu(self, *args, **kwargs):
menu = [
{'title': 'Add Shows', 'path': 'home/addShows/', },
{'title': 'Manual Post-Processing', 'path': 'home/postprocess/'},
@ -146,7 +146,7 @@ class Menus:
return menu
def ConfigMenu(self):
def ConfigMenu(self, *args, **kwargs):
menu = [
{'title': 'General', 'path': 'config/general/'},
{'title': 'Backup/Restore', 'path': 'config/backuprestore/'},
@ -160,7 +160,7 @@ class Menus:
return menu
def ManageMenu(self):
def ManageMenu(self, *args, **kwargs):
menu = [
{'title': 'Backlog Overview', 'path': 'manage/backlogOverview/'},
{'title': 'Manage Searches', 'path': 'manage/manageSearches/'},
@ -179,7 +179,7 @@ class Menus:
return menu
def ErrorLogsMenu(self):
def ErrorLogsMenu(self, *args, **kwargs):
menu = [
{'title': 'Clear Errors', 'path': 'errorlogs/clearerrors/'},
# { 'title': 'View Log', 'path': 'errorlogs/viewlog' },
@ -236,7 +236,7 @@ class PageTemplate(Template):
return super(PageTemplate, self).compile(*args, **kwargs)
class BaseHandler(RequestHandler):
def get_current_user(self):
def get_current_user(self, *args, **kwargs):
if sickbeard.WEB_USERNAME and sickbeard.WEB_PASSWORD:
return self.get_secure_cookie('user')
else:
@ -249,7 +249,6 @@ class BaseHandler(RequestHandler):
t.message = message
return t
# Make non basic auth option to get api key
class KeyHandler(RequestHandler):
def get(self, *args, **kwargs):
api_key = None
@ -258,8 +257,8 @@ class KeyHandler(RequestHandler):
username = sickbeard.WEB_USERNAME
password = sickbeard.WEB_PASSWORD
if (self.get_argument('u') == sickbeard.helpers.md5(username) or not username) \
and (self.get_argument('p') == password or not password):
if (self.get_argument('u', None) == username or not username) \
and (self.get_argument('p', None) == password or not password):
api_key = sickbeard.API_KEY
self.write({
@ -270,24 +269,6 @@ class KeyHandler(RequestHandler):
logger.log('Failed doing key request: %s' % (traceback.format_exc()), logger.ERROR)
self.write({'success': False, 'error': 'Failed returning results'})
class UIHandler(RequestHandler):
def add_message(self):
ui.notifications.message('Test 1', 'This is test number 1')
ui.notifications.error('Test 2', 'This is test number 2')
return "ok"
def get_messages(self):
messages = {}
cur_notification_num = 1
for cur_notification in ui.notifications.get_notifications(self.request.remote_ip):
messages['notification-' + str(cur_notification_num)] = {'title': cur_notification.title,
'message': cur_notification.message,
'type': cur_notification.type}
cur_notification_num += 1
return json.dumps(messages)
class WebHandler(BaseHandler):
def write_error(self, status_code, **kwargs):
if status_code == 404:
@ -323,7 +304,7 @@ class WebHandler(BaseHandler):
self.write('Could not load webui module')
return
except:
page_not_found(self)
page_not_found(self, *args, **kwargs)
return
try:
@ -377,14 +358,53 @@ class LogoutHandler(BaseHandler):
@route('(.*)(/?)')
class WebRoot(WebHandler):
def index(self):
def index(self, *args, **kwargs):
self.redirect('/home/')
def robots_txt(self):
def robots_txt(self, *args, **kwargs):
""" Keep web crawlers out """
self.set_header('Content-Type', 'text/plain')
return "User-agent: *\nDisallow: /"
def apibuilder(self, *args, **kwargs):
t = PageTemplate(rh=self, file="apiBuilder.tmpl")
def titler(x):
if not x or sickbeard.SORT_ARTICLE:
return x
if x.lower().startswith('a '):
x = x[2:]
elif x.lower().startswith('an '):
x = x[3:]
elif x.lower().startswith('the '):
x = x[4:]
return x
t.sortedShowList = sorted(sickbeard.showList, lambda x, y: cmp(titler(x.name), titler(y.name)))
seasonSQLResults = {}
episodeSQLResults = {}
myDB = db.DBConnection(row_type="dict")
for curShow in t.sortedShowList:
seasonSQLResults[curShow.indexerid] = myDB.select(
"SELECT DISTINCT season FROM tv_episodes WHERE showid = ? ORDER BY season DESC", [curShow.indexerid])
for curShow in t.sortedShowList:
episodeSQLResults[curShow.indexerid] = myDB.select(
"SELECT DISTINCT season,episode FROM tv_episodes WHERE showid = ? ORDER BY season DESC, episode DESC",
[curShow.indexerid])
t.seasonSQLResults = seasonSQLResults
t.episodeSQLResults = episodeSQLResults
if len(sickbeard.API_KEY) == 32:
t.apikey = sickbeard.API_KEY
else:
t.apikey = "api key not generated"
return t
def showPoster(self, show=None, which=None):
# Redirect initial poster/banner thumb to default images
if which[0:6] == 'poster':
@ -630,9 +650,28 @@ class WebRoot(WebHandler):
return ical
@route('/ui/(.*)(/?)')
class UIHandler(WebRoot):
def add_message(self, *args, **kwargs):
ui.notifications.message('Test 1', 'This is test number 1')
ui.notifications.error('Test 2', 'This is test number 2')
return "ok"
def get_messages(self, *args, **kwargs):
messages = {}
cur_notification_num = 1
for cur_notification in ui.notifications.get_notifications(self.request.remote_ip):
messages['notification-' + str(cur_notification_num)] = {'title': cur_notification.title,
'message': cur_notification.message,
'type': cur_notification.type}
cur_notification_num += 1
return json.dumps(messages)
@route('/home/(.*)(/?)')
class Home(WebRoot):
def index(self):
def index(self, *args, **kwargs):
t = PageTemplate(rh=self, file="home.tmpl")
if sickbeard.ANIME_SPLIT_HOME:
shows = []
@ -3293,6 +3332,10 @@ class ConfigGeneral(Config):
t.submenu = Menus().ConfigMenu()
return t
def generateApiKey(self, *args, **kwargs):
return helpers.generateApiKey()
def saveRootDirs(self, rootDirString=None):
sickbeard.ROOT_DIRS = rootDirString
@ -3322,31 +3365,6 @@ class ConfigGeneral(Config):
sickbeard.save_config()
def generateKey(self, *args, **kwargs):
""" Return a new randomized API_KEY
"""
try:
from hashlib import md5
except ImportError:
from md5 import md5
# Create some values to seed md5
t = str(time.time())
r = str(random.random())
# Create the md5 instance and give it the current time
m = md5(t)
# Update the md5 instance with the random variable
m.update(r)
# Return a hex digest of the md5, eg 49f68a5c8493ec2c0bf489821c21fc3b
logger.log(u"New API generated")
return m.hexdigest()
def saveGeneral(self, log_dir=None, web_port=None, web_log=None, encryption_version=None, web_ipv6=None,
update_shows_on_start=None, trash_remove_show=None, trash_rotate_logs=None, update_frequency=None,
launch_browser=None, web_username=None,
@ -4523,7 +4541,7 @@ class ConfigAnime(Config):
@route('/errorlogs/(.*)(/?)')
class ErrorLogs(WebRoot):
def index(self):
def index(self, *args, **kwargs):
t = PageTemplate(rh=self, file="errorlogs.tmpl")
t.submenu = Menus().ErrorLogsMenu()

View File

@ -1,16 +1,13 @@
import os
import socket
import time
import threading
import sys
import sickbeard
import webserve
import webapi
from sickbeard.webserve import LoginHandler, LogoutHandler
from sickbeard.webserve import LoginHandler, LogoutHandler, KeyHandler
from sickbeard.webapi import ApiHandler
from sickbeard import logger
from sickbeard.helpers import create_https_certificates
from tornado.web import Application, StaticFileHandler, HTTPError
from sickbeard.helpers import create_https_certificates, generateApiKey
from tornado.web import Application, StaticFileHandler, HTTPError, RedirectHandler
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.routes import route
@ -63,8 +60,13 @@ class SRWebServer(threading.Thread):
self.video_root = None
# web root
self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/')) if self.options['web_root'] else '/'
sickbeard.WEB_ROOT = self.options['web_root'].strip('/')
self.options['web_root'] = ('/' + self.options['web_root'].lstrip('/')).strip('/')
sickbeard.WEB_ROOT = self.options['web_root']
# api root
if not sickbeard.API_KEY:
sickbeard.API_KEY = generateApiKey()
self.options['api_root'] = r'%s/api/%s/' % (sickbeard.WEB_ROOT, sickbeard.API_KEY)
# tornado setup
self.enable_https = self.options['enable_https']
@ -97,20 +99,23 @@ class SRWebServer(threading.Thread):
# Main Handlers
self.app.add_handlers(".*$", [
(r'%slogin(/?)' % self.options['web_root'], LoginHandler),
(r'%slogout(/?)' % self.options['web_root'], LogoutHandler)
(r'%s(/?)' % self.options['api_root'], ApiHandler),
(r'%s/getkey(/?)' % self.options['web_root'], KeyHandler),
(r'%s/api/builder' % self.options['web_root'], RedirectHandler, {"url": self.options['web_root'] + '/apibuilder/'}),
(r'%s/login(/?)' % self.options['web_root'], LoginHandler),
(r'%s/logout(/?)' % self.options['web_root'], LogoutHandler)
] + route.get_routes())
# Static Path Handlers
self.app.add_handlers(".*$", [
(r'%s(favicon\.ico)' % self.options['web_root'], MultiStaticFileHandler,
(r'%s/(favicon\.ico)' % self.options['web_root'], MultiStaticFileHandler,
{'paths': [os.path.join(self.options['data_root'], 'images/ico/favicon.ico')]}),
(r'%s%s/(.*)(/?)' % (self.options['web_root'], 'images'), MultiStaticFileHandler,
(r'%s/%s/(.*)(/?)' % (self.options['web_root'], 'images'), MultiStaticFileHandler,
{'paths': [os.path.join(self.options['data_root'], 'images'),
os.path.join(sickbeard.CACHE_DIR, 'images')]}),
(r'%s%s/(.*)(/?)' % (self.options['web_root'], 'css'), MultiStaticFileHandler,
(r'%s/%s/(.*)(/?)' % (self.options['web_root'], 'css'), MultiStaticFileHandler,
{'paths': [os.path.join(self.options['data_root'], 'css')]}),
(r'%s%s/(.*)(/?)' % (self.options['web_root'], 'js'), MultiStaticFileHandler,
(r'%s/%s/(.*)(/?)' % (self.options['web_root'], 'js'), MultiStaticFileHandler,
{'paths': [os.path.join(self.options['data_root'], 'js')]}),
])