diff --git a/HACKS.txt b/HACKS.txt deleted file mode 100644 index 8750d457e7c6fe083480533902e15542dfb1aaad..0000000000000000000000000000000000000000 --- a/HACKS.txt +++ /dev/null @@ -1,3 +0,0 @@ -Libs with customisations... - -/tornado diff --git a/gui/slick/images/network/esquire network.png b/gui/slick/images/network/esquire network.png new file mode 100644 index 0000000000000000000000000000000000000000..43d4adf0c208f70d83407cf70a9f371fede534a6 Binary files /dev/null and b/gui/slick/images/network/esquire network.png differ diff --git a/gui/slick/images/network/smithsonian channel.png b/gui/slick/images/network/smithsonian channel.png new file mode 100644 index 0000000000000000000000000000000000000000..3f811e4202ea9006a95da5c9ed1b2a01f01a83c3 Binary files /dev/null and b/gui/slick/images/network/smithsonian channel.png differ diff --git a/gui/slick/interfaces/default/apiBuilder.tmpl b/gui/slick/interfaces/default/apiBuilder.tmpl index fedb826773b5899c0358fb3a7423a34171c3426f..4ff364f3beb8743b8606acdd545d2f1e548f383c 100644 --- a/gui/slick/interfaces/default/apiBuilder.tmpl +++ b/gui/slick/interfaces/default/apiBuilder.tmpl @@ -51,6 +51,8 @@ addList("Command", "Scene Exceptions", "?cmd=exceptions", "exceptions"); addList("Command", "History", "?cmd=history", "history"); addOption("Command", "History.Clear", "?cmd=history.clear", "", "", "action"); addOption("Command", "History.Trim", "?cmd=history.trim", "", "", "action"); +addList("Command", "Failed", "?cmd=failed", "failed"); +addOption("Command", "Backlog", "?cmd=backlog"); addList("Command", "PostProcess", "?cmd=postprocess", "postprocess", "", "","action"); addList("Command", "Logs", "?cmd=logs", "logs"); @@ -321,6 +323,15 @@ addOption("history-limit", "Optional Param", "", 1); addOption("history-limit", "Show Only Downloaded", "&type=downloaded"); addOption("history-limit", "Show Only Snatched", "&type=snatched"); +addOption("failed", "Optional Param", "", 1); +//addOptGroup("failed", "Limit Results"); +addList("failed", "Limit Results (2)", "&limit=2", "failed-limit"); +addList("failed", "Limit Results (25)", "&limit=25", "failed-limit"); +addList("failed", "Limit Results (50)", "&limit=50", "failed-limit"); +//endOptGroup("failed"); + +addOption("failed-limit", "Optional Param", "", 1); + addOption("exceptions", "Optional Param", "", 1); #for $curShow in $sortedShowList: addOption("exceptions", "$curShow.name", "&indexerid=$curShow.indexerid"); diff --git a/gui/slick/interfaces/default/config_search.tmpl b/gui/slick/interfaces/default/config_search.tmpl index a0230412aa83a9f86379f4f0a206398b197519c3..5956180b5bc5c6d09d4e7178a4c7e5264291d259 100755 --- a/gui/slick/interfaces/default/config_search.tmpl +++ b/gui/slick/interfaces/default/config_search.tmpl @@ -259,6 +259,16 @@ </span> </label> </div> + + <div class="field-pair"> + <label> + <span class="component-title">Use SABnzbd category for anime</span> + <span class="component-desc"> + <input type="text" name="sab_category_anime" id="sab_category_anime" value="$sickbeard.SAB_CATEGORY_ANIME" class="form-control input-sm input200" /> + <p>add anime downloads to this category (e.g. anime)</p> + </span> + </label> + </div> </div> <div id="nzbget_settings"> @@ -314,6 +324,16 @@ </label> </div> + <div class="field-pair"> + <label> + <span class="component-title">Use NZBget category for anime</span> + <span class="component-desc"> + <input type="text" name="nzbget_category_anime" id="nzbget_category_anime" value="$sickbeard.NZBGET_CATEGORY_ANIME" class="form-control input-sm input200" /> + <p>send anime downloads marked this category (e.g. anime)</p> + </span> + </label> + </div> + #set $prio_verylow = '' #set $prio_low = '' #set $prio_normal = '' @@ -468,6 +488,18 @@ </label> </div> + <div class="field-pair" id="torrent_label_anime_option"> + <label> + <span class="component-title">Add label to torrent for anime</span> + <span class="component-desc"> + <input type="text" name="torrent_label_anime" id="torrent_label_anime" value="$sickbeard.TORRENT_LABEL_ANIME" class="form-control input-sm input200" /> + <span id="label_anime_warning_deluge" style="display:none"><p>(blank spaces are not allowed)</p> + <div class="clear-left"><p>note: label plugin must be enabled in Deluge clients</p></div> + </span> + </span> + </label> + </div> + <div class="field-pair" id="torrent_path_option"> <label> <span class="component-title" id="directory_title">Downloaded files location</span> diff --git a/gui/slick/js/configSearch.js b/gui/slick/js/configSearch.js index ecf7cccf639735fa5fb646f29f962f622704952b..1543cd4d94d8b2db2ac7a2bbee5ce3e3634b6ded 100644 --- a/gui/slick/js/configSearch.js +++ b/gui/slick/js/configSearch.js @@ -50,6 +50,7 @@ $(document).ready(function(){ if ('blackhole' != selectedProvider) { var label_warning_deluge = '#label_warning_deluge', + label_anime_warning_deluge = '#label_anime_warning_deluge', host_desc_rtorrent = '#host_desc_rtorrent', host_desc_torrent = '#host_desc_torrent', torrent_verify_cert_option = '#torrent_verify_cert_option', @@ -57,10 +58,13 @@ $(document).ready(function(){ torrent_seed_time_option = '#torrent_seed_time_option', torrent_high_bandwidth_option = '#torrent_high_bandwidth_option', torrent_label_option = '#torrent_label_option', + torrent_label_anime_option = '#torrent_label_anime_option', path_synology = '#path_synology', torrent_paused_option = '#torrent_paused_option'; $(label_warning_deluge).hide(); + $(label_anime_warning_deluge).hide(); + $(label_anime_warning_deluge).hide(); $(host_desc_rtorrent).hide(); $(host_desc_torrent).show(); $(torrent_verify_cert_option).hide(); @@ -69,6 +73,7 @@ $(document).ready(function(){ $(torrent_seed_time_option).hide(); $(torrent_high_bandwidth_option).hide(); $(torrent_label_option).show(); + $(torrent_label_anime_option).show(); $(path_synology).hide(); $(torrent_paused_option).show(); @@ -81,15 +86,18 @@ $(document).ready(function(){ $(torrent_seed_time_option).show(); $(torrent_high_bandwidth_option).show(); $(torrent_label_option).hide(); + $(torrent_label_anime_option).hide(); //$('#directory_title').text(client + directory); } else if ('deluge' == selectedProvider){ client = 'Deluge'; $(torrent_verify_cert_option).show(); $(label_warning_deluge).show(); + $(label_anime_warning_deluge).show(); //$('#directory_title').text(client + directory); } else if ('download_station' == selectedProvider){ client = 'Synology DS'; $(torrent_label_option).hide(); + $(torrent_label_anime_option).hide(); $('#torrent_paused_option').hide(); $(torrent_path_option).find('.fileBrowser').hide(); //$('#directory_title').text(client + directory); diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 4c45f39e4c1b4952711c75091db708fc4e87f739..3571ff8a2ec833bc1a86e06f1e70aeee64d0fcda 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -255,11 +255,13 @@ SAB_USERNAME = None SAB_PASSWORD = None SAB_APIKEY = None SAB_CATEGORY = None +SAB_CATEGORY_ANIME = None SAB_HOST = '' NZBGET_USERNAME = None NZBGET_PASSWORD = None NZBGET_CATEGORY = None +NZBGET_CATEGORY_ANIME = None NZBGET_HOST = None NZBGET_USE_HTTPS = False NZBGET_PRIORITY = 100 @@ -272,6 +274,7 @@ TORRENT_SEED_TIME = None TORRENT_PAUSED = False TORRENT_HIGH_BANDWIDTH = False TORRENT_LABEL = '' +TORRENT_LABEL_ANIME = '' TORRENT_VERIFY_CERT = False USE_XBMC = False @@ -477,9 +480,9 @@ def initialize(consoleLogging=True): 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, \ HANDLE_REVERSE_PROXY, USE_NZBS, USE_TORRENTS, NZB_METHOD, NZB_DIR, DOWNLOAD_PROPERS, CHECK_PROPERS_INTERVAL, ALLOW_HIGH_PRIORITY, TORRENT_METHOD, \ - SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, SAB_HOST, \ - NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_PRIORITY, NZBGET_HOST, NZBGET_USE_HTTPS, backlogSearchScheduler, \ - TORRENT_USERNAME, TORRENT_PASSWORD, TORRENT_HOST, TORRENT_PATH, TORRENT_SEED_TIME, TORRENT_PAUSED, TORRENT_HIGH_BANDWIDTH, TORRENT_LABEL, TORRENT_VERIFY_CERT, \ + 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, \ + TORRENT_USERNAME, TORRENT_PASSWORD, TORRENT_HOST, TORRENT_PATH, TORRENT_SEED_TIME, TORRENT_PAUSED, TORRENT_HIGH_BANDWIDTH, TORRENT_LABEL, TORRENT_LABEL_ANIME, TORRENT_VERIFY_CERT, \ USE_XBMC, XBMC_ALWAYS_ON, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD, XBMC_UPDATE_FULL, XBMC_UPDATE_ONLYFIRST, \ XBMC_UPDATE_LIBRARY, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, BACKLOG_FREQUENCY, \ USE_TRAKT, TRAKT_USERNAME, TRAKT_PASSWORD, TRAKT_API, TRAKT_REMOVE_WATCHLIST, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_USE_RECOMMENDED, TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, \ @@ -619,7 +622,8 @@ def initialize(consoleLogging=True): ANON_REDIRECT = check_setting_str(CFG, 'General', 'anon_redirect', 'http://dereferer.org/?') PROXY_SETTING = check_setting_str(CFG, 'General', 'proxy_setting', '') PROXY_INDEXERS = bool(check_setting_int(CFG, 'General', 'proxy_indexers', 1)) - # attempt to help prevent users from breaking links by using a bad url + + # attempt to help prevent users from breaking links by using a bad url if not ANON_REDIRECT.endswith('?'): ANON_REDIRECT = '' @@ -745,11 +749,13 @@ def initialize(consoleLogging=True): SAB_PASSWORD = check_setting_str(CFG, 'SABnzbd', 'sab_password', '') SAB_APIKEY = check_setting_str(CFG, 'SABnzbd', 'sab_apikey', '') SAB_CATEGORY = check_setting_str(CFG, 'SABnzbd', 'sab_category', 'tv') + SAB_CATEGORY_ANIME = check_setting_str(CFG, 'SABnzbd', 'sab_category_anime', 'anime') SAB_HOST = check_setting_str(CFG, 'SABnzbd', 'sab_host', '') NZBGET_USERNAME = check_setting_str(CFG, 'NZBget', 'nzbget_username', 'nzbget') NZBGET_PASSWORD = check_setting_str(CFG, 'NZBget', 'nzbget_password', 'tegbzn6789') NZBGET_CATEGORY = check_setting_str(CFG, 'NZBget', 'nzbget_category', 'tv') + NZBGET_CATEGORY_ANIME = check_setting_str(CFG, 'NZBget', 'nzbget_category_anime', 'anime') NZBGET_HOST = check_setting_str(CFG, 'NZBget', 'nzbget_host', '') NZBGET_USE_HTTPS = bool(check_setting_int(CFG, 'NZBget', 'nzbget_use_https', 0)) NZBGET_PRIORITY = check_setting_int(CFG, 'NZBget', 'nzbget_priority', 100) @@ -762,6 +768,7 @@ def initialize(consoleLogging=True): TORRENT_PAUSED = bool(check_setting_int(CFG, 'TORRENT', 'torrent_paused', 0)) TORRENT_HIGH_BANDWIDTH = bool(check_setting_int(CFG, 'TORRENT', 'torrent_high_bandwidth', 0)) TORRENT_LABEL = check_setting_str(CFG, 'TORRENT', 'torrent_label', '') + TORRENT_LABEL_ANIME = check_setting_str(CFG, 'TORRENT', 'torrent_label_anime', '') TORRENT_VERIFY_CERT = bool(check_setting_int(CFG, 'TORRENT', 'torrent_verify_cert', 0)) USE_XBMC = bool(check_setting_int(CFG, 'XBMC', 'use_xbmc', 0)) @@ -1588,6 +1595,7 @@ def save_config(): new_config['SABnzbd']['sab_password'] = helpers.encrypt(SAB_PASSWORD, ENCRYPTION_VERSION) new_config['SABnzbd']['sab_apikey'] = SAB_APIKEY new_config['SABnzbd']['sab_category'] = SAB_CATEGORY + new_config['SABnzbd']['sab_category_anime'] = SAB_CATEGORY_ANIME new_config['SABnzbd']['sab_host'] = SAB_HOST new_config['NZBget'] = {} @@ -1595,6 +1603,7 @@ def save_config(): new_config['NZBget']['nzbget_username'] = NZBGET_USERNAME new_config['NZBget']['nzbget_password'] = helpers.encrypt(NZBGET_PASSWORD, ENCRYPTION_VERSION) new_config['NZBget']['nzbget_category'] = NZBGET_CATEGORY + new_config['NZBget']['nzbget_category_anime'] = NZBGET_CATEGORY_ANIME new_config['NZBget']['nzbget_host'] = NZBGET_HOST new_config['NZBget']['nzbget_use_https'] = int(NZBGET_USE_HTTPS) new_config['NZBget']['nzbget_priority'] = NZBGET_PRIORITY @@ -1608,6 +1617,7 @@ def save_config(): new_config['TORRENT']['torrent_paused'] = int(TORRENT_PAUSED) new_config['TORRENT']['torrent_high_bandwidth'] = int(TORRENT_HIGH_BANDWIDTH) new_config['TORRENT']['torrent_label'] = TORRENT_LABEL + new_config['TORRENT']['torrent_label_anime'] = TORRENT_LABEL_ANIME new_config['TORRENT']['torrent_verify_cert'] = int(TORRENT_VERIFY_CERT) new_config['XBMC'] = {} diff --git a/sickbeard/clients/deluge.py b/sickbeard/clients/deluge.py index 3cd840ef70214158fa3e9b7250312bae968adc8a..6946abd9e01629758fe6cc1cc05f210879b8d053 100644 --- a/sickbeard/clients/deluge.py +++ b/sickbeard/clients/deluge.py @@ -124,6 +124,8 @@ class DelugeAPI(GenericClient): def _set_torrent_label(self, result): label = sickbeard.TORRENT_LABEL + if result.show.is_anime: + label = sickbeard.TORRENT_LABEL_ANIME if ' ' in label: logger.log(self.name + u': Invalid label. Label must not contain a space', logger.ERROR) return False diff --git a/sickbeard/clients/rtorrent.py b/sickbeard/clients/rtorrent.py index b1a92286e03c8d8e59a83ea25f4974dc36ce7aff..82f760461c36f511f53f7bf323b2d532effcfc1c 100644 --- a/sickbeard/clients/rtorrent.py +++ b/sickbeard/clients/rtorrent.py @@ -61,8 +61,11 @@ class rTorrentAPI(GenericClient): return False # Set label - if sickbeard.TORRENT_LABEL: - torrent.set_custom(1, sickbeard.TORRENT_LABEL.lower()) + label = sickbeard.TORRENT_LABEL + if result.show.is_anime: + label = sickbeard.TORRENT_LABEL_ANIME + if label: + torrent.set_custom(1, label.lower()) if sickbeard.TORRENT_PATH: torrent.set_directory(sickbeard.TORRENT_PATH) @@ -97,8 +100,11 @@ class rTorrentAPI(GenericClient): return False # Set label - if sickbeard.TORRENT_LABEL: - torrent.set_custom(1, sickbeard.TORRENT_LABEL.lower()) + label = sickbeard.TORRENT_LABEL + if result.show.is_anime: + label = sickbeard.TORRENT_LABEL_ANIME + if label: + torrent.set_custom(1, label.lower()) if sickbeard.TORRENT_PATH: torrent.set_directory(sickbeard.TORRENT_PATH) diff --git a/sickbeard/clients/utorrent.py b/sickbeard/clients/utorrent.py index eda8646a16ea36624f41d7df039feb6a172592c8..fd9adc2e11ab71eebc9457f12aab79e73505fab7 100644 --- a/sickbeard/clients/utorrent.py +++ b/sickbeard/clients/utorrent.py @@ -58,10 +58,14 @@ class uTorrentAPI(GenericClient): def _set_torrent_label(self, result): + label = sickbeard.TORRENT_LABEL + if result.show.is_anime: + label = sickbeard.TORRENT_LABEL_ANIME + params = {'action': 'setprops', 'hash': result.hash, 's': 'label', - 'v': sickbeard.TORRENT_LABEL + 'v': label } return self._request(params=params) diff --git a/sickbeard/nzbget.py b/sickbeard/nzbget.py index 469e4e4d7c0f9c4edbb4aa6b5c2e722dc12640f9..a1cb5746338d4994900d502efe2c89768a898acc 100644 --- a/sickbeard/nzbget.py +++ b/sickbeard/nzbget.py @@ -37,6 +37,9 @@ from common import Quality def sendNZB(nzb, proper=False): addToTop = False nzbgetprio = 0 + category = sickbeard.NZBGET_CATEGORY + if nzb.show.is_anime: + category = sickbeard.NZBGET_CATEGORY_ANIME if sickbeard.NZBGET_USE_HTTPS: nzbgetXMLrpc = "https://%(username)s:%(password)s@%(host)s/xmlrpc" @@ -103,7 +106,7 @@ def sendNZB(nzb, proper=False): nzbget_version = helpers.tryInt(nzbget_version_str[:nzbget_version_str.find(".")]) if nzbget_version == 0: if nzbcontent64 is not None: - nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, addToTop, nzbcontent64) + nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", category, addToTop, nzbcontent64) else: if nzb.resultType == "nzb": genProvider = GenericProvider("") @@ -111,27 +114,27 @@ def sendNZB(nzb, proper=False): if (data == None): return False nzbcontent64 = standard_b64encode(data) - nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, addToTop, nzbcontent64) + nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", category, addToTop, nzbcontent64) elif nzbget_version == 12: if nzbcontent64 is not None: - nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, nzbgetprio, False, + nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", category, nzbgetprio, False, nzbcontent64, False, dupekey, dupescore, "score") else: - nzbget_result = nzbGetRPC.appendurl(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, nzbgetprio, False, + nzbget_result = nzbGetRPC.appendurl(nzb.name + ".nzb", category, nzbgetprio, False, nzb.url, False, dupekey, dupescore, "score") # v13+ has a new combined append method that accepts both (url and content) # also the return value has changed from boolean to integer # (Positive number representing NZBID of the queue item. 0 and negative numbers represent error codes.) elif nzbget_version >= 13: nzbget_result = True if nzbGetRPC.append(nzb.name + ".nzb", nzbcontent64 if nzbcontent64 is not None else nzb.url, - sickbeard.NZBGET_CATEGORY, nzbgetprio, False, False, dupekey, dupescore, + category, nzbgetprio, False, False, dupekey, dupescore, "score") > 0 else False else: if nzbcontent64 is not None: - nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, nzbgetprio, False, + nzbget_result = nzbGetRPC.append(nzb.name + ".nzb", category, nzbgetprio, False, nzbcontent64) else: - nzbget_result = nzbGetRPC.appendurl(nzb.name + ".nzb", sickbeard.NZBGET_CATEGORY, nzbgetprio, False, + nzbget_result = nzbGetRPC.appendurl(nzb.name + ".nzb", category, nzbgetprio, False, nzb.url) if nzbget_result: diff --git a/sickbeard/sab.py b/sickbeard/sab.py index 3df53421e4a726be6cae3329dba4776ddea46be6..078e92f06403878b476656ad48fef1d88ff043c2 100644 --- a/sickbeard/sab.py +++ b/sickbeard/sab.py @@ -51,8 +51,11 @@ def sendNZB(nzb): params['ma_password'] = sickbeard.SAB_PASSWORD if sickbeard.SAB_APIKEY != None: params['apikey'] = sickbeard.SAB_APIKEY - if sickbeard.SAB_CATEGORY != None: - params['cat'] = sickbeard.SAB_CATEGORY + category = sickbeard.SAB_CATEGORY + if nzb.show.is_anime: + category = sickbeard.SAB_CATEGORY_ANIME + if category != None: + params['cat'] = category # use high priority if specified (recently aired episode) if nzb.priority == 1: diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py index 9e962f8ab46b378de9e650e8820f44586471a648..f5f41d6ed422f63bae91787113482f014d88af8f 100644 --- a/sickbeard/webapi.py +++ b/sickbeard/webapi.py @@ -37,7 +37,7 @@ from sickbeard import processTV from sickbeard import network_timezones, sbdatetime from sickbeard.exceptions import ex from sickbeard.common import SNATCHED, SNATCHED_PROPER, DOWNLOADED, SKIPPED, UNAIRED, IGNORED, ARCHIVED, WANTED, UNKNOWN -from common import Quality, qualityPresetStrings, statusStrings +from common import Quality, Overview, qualityPresetStrings, statusStrings try: import json @@ -162,19 +162,17 @@ class Api(webserve.MainHandler): return webserve._munge(t) def _out_as_json(self, dict): - self.set_header("Content-Type", "application/json") + self.set_header("Content-Type", "application/json;charset=UTF-8'") try: out = json.dumps(dict, indent=self.intent, ensure_ascii=False, sort_keys=True) - if 'jsonp' in self.request.query_arguments: - out = self.request.arguments['jsonp'] + '(' + out + ');' # wrap with JSONP call if requested - + callback = self.get_query_argument('callback', None) or self.get_query_argument('jsonp', None) + if callback != None: + out = callback + '(' + out + ');' # wrap with JSONP call if requested except Exception, e: # if we fail to generate the output fake an error logger.log(u"API :: " + traceback.format_exc(), logger.DEBUG) out = '{"result":"' + result_type_map[RESULT_ERROR] + '", "message": "error while composing output: "' + ex( e) + '"}' - - tornado_write_hack_dict = {'unwrap_json': out} - return tornado_write_hack_dict + return out def _grand_access(self, realKey, args, kwargs): """ validate api key and log result """ @@ -188,7 +186,7 @@ class Api(webserve.MainHandler): del kwargs["apikey"] if not sickbeard.USE_API: - msg = u"API :: " + remoteIp + " - SB API Disabled. ACCESS DENIED" + 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. ACCESS GRANTED" @@ -715,7 +713,7 @@ class CMD_ComingEpisodes(ApiCall): "optionalParameters": {"sort": {"desc": "change the sort order"}, "type": {"desc": "one or more of allowedValues separated by |"}, "paused": { - "desc": "0 to exclude paused shows, 1 to include them, or omitted to use the SB default"}, + "desc": "0 to exclude paused shows, 1 to include them, or omitted to use the SR default"}, } } @@ -1260,6 +1258,70 @@ class CMD_HistoryTrim(ApiCall): return _responds(RESULT_SUCCESS, msg="Removed history entries greater than 30 days old") +class CMD_Failed(ApiCall): + _help = {"desc": "display failed downloads", + "optionalParameters": {"limit": {"desc": "limit returned results"} + } + } + + def __init__(self, handler, 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) + + def run(self): + """ display failed downloads """ + + myDB = db.DBConnection('failed.db', row_type="dict") + + ulimit = min(int(self.limit), 100) + if ulimit == 0: + sqlResults = myDB.select("SELECT * FROM failed") + else: + sqlResults = myDB.select("SELECT * FROM failed LIMIT ?", [ulimit]) + + return _responds(RESULT_SUCCESS, sqlResults) + +class CMD_Backlog(ApiCall): + _help = {"desc": "display backlogged episodes"} + + def __init__(self, handler, args, kwargs): + # required + # optional + # super, missing, help + ApiCall.__init__(self, handler, args, kwargs) + + def run(self): + """ display backlogged episodes """ + + shows = [] + + myDB = db.DBConnection(row_type="dict") + for curShow in sickbeard.showList: + + showEps = [] + + sqlResults = myDB.select( + "SELECT * FROM tv_episodes WHERE showid = ? ORDER BY season DESC, episode DESC", + [curShow.indexerid]) + + for curResult in sqlResults: + + curEpCat = curShow.getOverview(int(curResult["status"])) + if curEpCat and curEpCat in (Overview.WANTED, Overview.QUAL): + showEps.append(curResult) + + if showEps: + shows.append({ + "indexerid": curShow.indexerid, + "show_name": curShow.name, + "status": curShow.status, + "episodes": showEps + }) + + return _responds(RESULT_SUCCESS, shows) class CMD_Logs(ApiCall): _help = {"desc": "view sickrage's log", @@ -2724,6 +2786,8 @@ class CMD_Shows(ApiCall): if self.paused != None and bool(self.paused) != bool(curShow.paused): continue + indexerShow = helpers.mapIndexersToShow(curShow) + showDict = { "paused": curShow.paused, "quality": _get_quality_string(curShow.quality), @@ -2732,8 +2796,8 @@ class CMD_Shows(ApiCall): "sports": curShow.sports, "anime": curShow.anime, "indexerid": curShow.indexerid, - "tvdbid": helpers.mapIndexersToShow(curShow)[1], - "tvrage_id": helpers.mapIndexersToShow(curShow)[2], + "tvdbid": indexerShow[1], + "tvrage_id": indexerShow[2], "tvrage_name": curShow.name, "network": curShow.network, "show_name": curShow.name, @@ -2805,6 +2869,8 @@ _functionMaper = {"help": CMD_Help, "history": CMD_History, "history.clear": CMD_HistoryClear, "history.trim": CMD_HistoryTrim, + "failed": CMD_Failed, + "backlog": CMD_Backlog, "logs": CMD_Logs, "sb": CMD_SickBeard, "postprocess": CMD_PostProcess, diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 0827781166a199dc80683c0f6d2a216cdb58da6c..dd3593b79e35d4e4be3356d411c1f9cf219de9e6 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -264,7 +264,7 @@ class MainHandler(RequestHandler): else: default_image_name = 'banner.png' - default_image_path = ek.ek(os.path.join, sickbeard.PROG_DIR, 'gui', 'slick', 'images', default_image_name) + image_path = ek.ek(os.path.join, sickbeard.PROG_DIR, 'gui', 'slick', 'images', default_image_name) if show and sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)): cache_obj = image_cache.ImageCache() @@ -279,10 +279,12 @@ class MainHandler(RequestHandler): image_file_name = cache_obj.banner_thumb_path(show) if ek.ek(os.path.isfile, image_file_name): - with file(image_file_name, 'rb') as img: - return img.read() + image_path = image_file_name - with file(default_image_path, 'rb') as img: + from mimetypes import MimeTypes + mime_type, encoding = MimeTypes().guess_type(image_path) + self.set_header('Content-Type', mime_type) + with file(image_path, 'rb') as img: return img.read() def setHomeLayout(self, layout): @@ -1669,14 +1671,14 @@ class ConfigSearch(MainHandler): def saveSearch(self, use_nzbs=None, use_torrents=None, nzb_dir=None, sab_username=None, sab_password=None, - sab_apikey=None, sab_category=None, sab_host=None, nzbget_username=None, nzbget_password=None, - nzbget_category=None, nzbget_priority=None, nzbget_host=None, nzbget_use_https=None, - backlog_days=None, backlog_frequency=None, dailysearch_frequency=None, - nzb_method=None, torrent_method=None, usenet_retention=None, + sab_apikey=None, sab_category=None, sab_category_anime=None, sab_host=None, nzbget_username=None, + nzbget_password=None, nzbget_category=None, nzbget_category_anime=None, nzbget_priority=None, + nzbget_host=None, nzbget_use_https=None, backlog_days=None, backlog_frequency=None, + dailysearch_frequency=None, nzb_method=None, torrent_method=None, usenet_retention=None, download_propers=None, check_propers_interval=None, allow_high_priority=None, backlog_startup=None, dailysearch_startup=None, torrent_dir=None, torrent_username=None, torrent_password=None, torrent_host=None, - torrent_label=None, torrent_path=None, torrent_verify_cert=None, + torrent_label=None, torrent_label_anime=None, torrent_path=None, torrent_verify_cert=None, torrent_seed_time=None, torrent_paused=None, torrent_high_bandwidth=None, ignore_words=None, require_words=None): @@ -1715,11 +1717,13 @@ class ConfigSearch(MainHandler): sickbeard.SAB_PASSWORD = sab_password sickbeard.SAB_APIKEY = sab_apikey.strip() sickbeard.SAB_CATEGORY = sab_category + sickbeard.SAB_CATEGORY_ANIME = sab_category_anime sickbeard.SAB_HOST = config.clean_url(sab_host) sickbeard.NZBGET_USERNAME = nzbget_username sickbeard.NZBGET_PASSWORD = nzbget_password sickbeard.NZBGET_CATEGORY = nzbget_category + sickbeard.NZBGET_CATEGORY_ANIME = nzbget_category_anime sickbeard.NZBGET_HOST = config.clean_host(nzbget_host) sickbeard.NZBGET_USE_HTTPS = config.checkbox_to_value(nzbget_use_https) sickbeard.NZBGET_PRIORITY = config.to_int(nzbget_priority, default=100) @@ -1727,6 +1731,7 @@ class ConfigSearch(MainHandler): sickbeard.TORRENT_USERNAME = torrent_username sickbeard.TORRENT_PASSWORD = torrent_password sickbeard.TORRENT_LABEL = torrent_label + sickbeard.TORRENT_LABEL_ANIME = torrent_label_anime sickbeard.TORRENT_VERIFY_CERT = config.checkbox_to_value(torrent_verify_cert) sickbeard.TORRENT_PATH = torrent_path sickbeard.TORRENT_SEED_TIME = torrent_seed_time diff --git a/sickbeard/webserveInit.py b/sickbeard/webserveInit.py index 567ce865f26b5960715cdc56a135f60c318f375d..f0c440c630f28c36e76125a59875010c94ad5d5b 100644 --- a/sickbeard/webserveInit.py +++ b/sickbeard/webserveInit.py @@ -149,6 +149,4 @@ class SRWebServer(threading.Thread): def shutDown(self): self.alive = False - if self.server: - self.server.stop() - self.io_loop.stop() \ No newline at end of file + self.io_loop.stop() \ No newline at end of file diff --git a/tornado/http1connection.py b/tornado/http1connection.py index 8a5f46c48c8642506ebd0efc4192d811b9ca33cf..90895cc94393d8ef0fd662f759bc4b1d76f0d931 100644 --- a/tornado/http1connection.py +++ b/tornado/http1connection.py @@ -686,9 +686,8 @@ class HTTP1ServerConnection(object): # This exception was already logged. conn.close() return - except Exception as e: - if 1 != e.errno: - gen_log.error("Uncaught exception", exc_info=True) + except Exception: + gen_log.error("Uncaught exception", exc_info=True) conn.close() return if not ret: diff --git a/tornado/iostream.py b/tornado/iostream.py index 69f43957902da4ce8e9753b60dd769178d5558d0..eced6d6482bd017efff1c27c3dd61d5638df3957 100644 --- a/tornado/iostream.py +++ b/tornado/iostream.py @@ -601,9 +601,8 @@ class BaseIOStream(object): pos = self._read_to_buffer_loop() except UnsatisfiableReadError: raise - except Exception as e: - if 1 != e.errno: - gen_log.warning("error on read", exc_info=True) + except Exception: + gen_log.warning("error on read", exc_info=True) self.close(exc_info=True) return if pos is not None: diff --git a/tornado/web.py b/tornado/web.py index 9edd719a1ef1329fe527446f6222715b11bd1a2a..a038265fd3fd4a726d8e1f2f993c79dc9e5ab1e7 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -652,10 +652,7 @@ class RequestHandler(object): if not isinstance(chunk, (bytes, unicode_type, dict)): raise TypeError("write() only accepts bytes, unicode, and dict objects") if isinstance(chunk, dict): - if 'unwrap_json' in chunk: - chunk = chunk['unwrap_json'] - else: - chunk = escape.json_encode(chunk) + chunk = escape.json_encode(chunk) self.set_header("Content-Type", "application/json; charset=UTF-8") chunk = utf8(chunk) self._write_buffer.append(chunk)