From 2b51447a9e7885c5d3835154566e0d6e919efd14 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Wed, 25 Jul 2012 17:54:41 +0530 Subject: [PATCH 1/6] Initial changes to allow multiple newznab providers --- data/interfaces/default/config.html | 31 ++++++++++++++++------------- headphones/__init__.py | 5 ++++- headphones/webserve.py | 4 +++- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index ef0f534c..b5d62ecc 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -184,7 +184,7 @@ m<%inherit file="base.html"/>
- +
@@ -200,17 +200,20 @@ m<%inherit file="base.html"/>
-
- - - e.g. http://nzb.su -
-
- - -
-
- +
+ + + e.g. http://nzb.su +
+
+ + +
+
+ +
+
+ @@ -233,11 +236,11 @@ m<%inherit file="base.html"/>
- +
- +
diff --git a/headphones/__init__.py b/headphones/__init__.py index a6ab5255..91b396f7 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -121,6 +121,7 @@ NZBMATRIX_APIKEY = None NEWZNAB = False NEWZNAB_HOST = None NEWZNAB_APIKEY = None +NEWZNAB_ENABLED = False NZBSORG = False NZBSORG_UID = None @@ -240,7 +241,7 @@ def initialize(): ADD_ALBUM_ART, EMBED_ALBUM_ART, EMBED_LYRICS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, \ TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, MININOVA, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, DOWNLOAD_TORRENT_DIR, \ LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \ - NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, \ + NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_ENABLED, \ NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, \ ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, \ ENCODERLOSSLESS, PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, MIRRORLIST, MIRROR, CUSTOMHOST, CUSTOMPORT, \ @@ -340,6 +341,7 @@ def initialize(): NEWZNAB = bool(check_setting_int(CFG, 'Newznab', 'newznab', 0)) NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '') NEWZNAB_APIKEY = check_setting_str(CFG, 'Newznab', 'newznab_apikey', '') + NEWZNAB_ENABLED = bool(check_setting_int(CFG, 'Newznab', 'newznab_enabled', 1)) NZBSORG = bool(check_setting_int(CFG, 'NZBsorg', 'nzbsorg', 0)) NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '') @@ -613,6 +615,7 @@ def config_write(): new_config['Newznab']['newznab'] = int(NEWZNAB) new_config['Newznab']['newznab_host'] = NEWZNAB_HOST new_config['Newznab']['newznab_apikey'] = NEWZNAB_APIKEY + new_config['Newznab']['newznab_enabled'] = int(NEWZNAB_ENABLED) new_config['NZBsorg'] = {} new_config['NZBsorg']['nzbsorg'] = int(NZBSORG) diff --git a/headphones/webserve.py b/headphones/webserve.py index fc0332e7..93865a6a 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -384,6 +384,7 @@ class WebInterface(object): "use_newznab" : checked(headphones.NEWZNAB), "newznab_host" : headphones.NEWZNAB_HOST, "newznab_api" : headphones.NEWZNAB_APIKEY, + "newznab_enabled" : checked(headphones.NEWZNAB_ENABLED), "use_nzbsorg" : checked(headphones.NZBSORG), "nzbsorg_uid" : headphones.NZBSORG_UID, "nzbsorg_hash" : headphones.NZBSORG_HASH, @@ -458,7 +459,7 @@ class WebInterface(object): def configUpdate(self, http_host='0.0.0.0', http_username=None, http_port=8181, http_password=None, launch_browser=0, api_enabled=0, api_key=None, download_scan_interval=None, nzb_search_interval=None, libraryscan_interval=None, sab_host=None, sab_username=None, sab_apikey=None, sab_password=None, sab_category=None, download_dir=None, blackhole=0, blackhole_dir=None, - usenet_retention=None, nzbmatrix=0, nzbmatrix_username=None, nzbmatrix_apikey=None, newznab=0, newznab_host=None, newznab_apikey=None, + usenet_retention=None, nzbmatrix=0, nzbmatrix_username=None, nzbmatrix_apikey=None, newznab=0, newznab_host=None, newznab_apikey=None, newznab_enabled=0, nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, newzbin=0, newzbin_uid=None, newzbin_password=None, preferred_quality=0, preferred_bitrate=None, detect_bitrate=0, move_files=0, torrentblackhole_dir=None, download_torrent_dir=None, numberofseeders=10, use_isohunt=0, use_kat=0, use_mininova=0, waffles=0, waffles_uid=None, waffles_passkey=None, rename_files=0, correct_metadata=0, cleanup_files=0, add_album_art=0, embed_album_art=0, embed_lyrics=0, destination_dir=None, folder_format=None, file_format=None, include_extras=0, autowant_upcoming=False, autowant_all=False, interface=None, log_dir=None, @@ -491,6 +492,7 @@ class WebInterface(object): headphones.NEWZNAB = newznab headphones.NEWZNAB_HOST = newznab_host headphones.NEWZNAB_APIKEY = newznab_apikey + headphones.NEWZNAB_ENABLED = newznab_enabled headphones.NZBSORG = nzbsorg headphones.NZBSORG_UID = nzbsorg_uid headphones.NZBSORG_HASH = nzbsorg_hash From 4f8e5877a7e4642984f556338c5cbfd3b11ed5cb Mon Sep 17 00:00:00 2001 From: rembo10 Date: Wed, 25 Jul 2012 20:18:43 +0530 Subject: [PATCH 2/6] Added jquery to allow adding/removing newznab providers --- data/interfaces/default/config.html | 41 ++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index b5d62ecc..3a0ac8a8 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -199,19 +199,22 @@ m<%inherit file="base.html"/>
-
-
- - - e.g. http://nzb.su -
-
- - -
-
- +
+
+
+ + + e.g. http://nzb.su +
+
+ + +
+
+ +
+
@@ -792,7 +795,19 @@ m<%inherit file="base.html"/> initConfigCheckbox("#useapi"); } $(document).ready(function() { - initThisPage(); + initThisPage(); + $("#add_newznab").click(function() { + var intIdPrev = $("#newznab_providers > div").size() + var intId = intIdPrev + 1; + var formfields = $("
"); + var removeButton = $("
"); + removeButton.click(function() { + $(this).parent().remove(); + }); + formfields.append(removeButton); + formfields.append("
"); + $("#newznab" + intIdPrev).append(formfields); + }); }); From 0cf59d94ffea31f277e1cdde45fec671a14e0875 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Wed, 25 Jul 2012 20:33:11 +0530 Subject: [PATCH 3/6] Allow for extra newznabs to be inserted into the form on load --- data/interfaces/default/config.html | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 3a0ac8a8..9bceb8db 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -214,6 +214,28 @@ m<%inherit file="base.html"/>
+ <% + newznab_number = 2 + %> + %for newznab in config['extra_newznabs']: +
+
+ + + e.g. http://nzb.su +
+
+ + +
+
+ +
+
+ <% + newznab_number += 1 + %> + %endfor @@ -799,7 +821,7 @@ m<%inherit file="base.html"/> $("#add_newznab").click(function() { var intIdPrev = $("#newznab_providers > div").size() var intId = intIdPrev + 1; - var formfields = $("
"); + var formfields = $("
"); var removeButton = $("
"); removeButton.click(function() { $(this).parent().remove(); From cc2adb40ebda1381cb0421e720e9a316dc826ac6 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Thu, 26 Jul 2012 01:29:16 +0530 Subject: [PATCH 4/6] Extra newznabs can be saved to and pulled from the config --- data/interfaces/default/config.html | 27 ++++++++++++++++++++------- headphones/__init__.py | 5 ++++- headphones/webserve.py | 19 ++++++++++++++++++- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 9bceb8db..5f29847b 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -1,6 +1,7 @@ m<%inherit file="base.html"/> <%! import headphones + from operator import itemgetter %> <%def name="headerIncludes()"> @@ -217,19 +218,27 @@ m<%inherit file="base.html"/> <% newznab_number = 2 %> - %for newznab in config['extra_newznabs']: + %for newznab in sorted(config['extra_newznabs'], key=itemgetter(0)): + <% + if newznab[2]: + newznab_enabled = "checked" + else: + newznab_enabled = "" + %>
- e.g. http://nzb.su
- +
- + +
+
+
<% @@ -804,6 +813,10 @@ m<%inherit file="base.html"/> $("#mirror").change(handleNewSelection); handleNewSelection.apply($("#mirror")); + + $(".remove").click(function() { + $(this).parent().parent().remove(); + }); $(function() { $( "#tabs" ).tabs(); }); @@ -819,16 +832,16 @@ m<%inherit file="base.html"/> $(document).ready(function() { initThisPage(); $("#add_newznab").click(function() { - var intIdPrev = $("#newznab_providers > div").size() + var intIdPrev = $("#newznab_providers > div").size(); var intId = intIdPrev + 1; - var formfields = $("
"); + var formfields = $("
"); var removeButton = $("
"); removeButton.click(function() { $(this).parent().remove(); }); formfields.append(removeButton); formfields.append("
"); - $("#newznab" + intIdPrev).append(formfields); + $("#newznab" + intIdPrev).after(formfields); }); }); diff --git a/headphones/__init__.py b/headphones/__init__.py index 91b396f7..f8eacc1a 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -122,6 +122,7 @@ NEWZNAB = False NEWZNAB_HOST = None NEWZNAB_APIKEY = None NEWZNAB_ENABLED = False +EXTRA_NEWZNABS = [] NZBSORG = False NZBSORG_UID = None @@ -241,7 +242,7 @@ def initialize(): ADD_ALBUM_ART, EMBED_ALBUM_ART, EMBED_LYRICS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, \ TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, MININOVA, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, DOWNLOAD_TORRENT_DIR, \ LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \ - NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_ENABLED, \ + NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_ENABLED, EXTRA_NEWZNABS,\ NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, \ ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, \ ENCODERLOSSLESS, PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, MIRRORLIST, MIRROR, CUSTOMHOST, CUSTOMPORT, \ @@ -342,6 +343,7 @@ def initialize(): NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '') NEWZNAB_APIKEY = check_setting_str(CFG, 'Newznab', 'newznab_apikey', '') NEWZNAB_ENABLED = bool(check_setting_int(CFG, 'Newznab', 'newznab_enabled', 1)) + EXTRA_NEWZNABS = check_setting_str(CFG, 'Newznab', 'extra_newznabs', [], log=False) NZBSORG = bool(check_setting_int(CFG, 'NZBsorg', 'nzbsorg', 0)) NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '') @@ -616,6 +618,7 @@ def config_write(): new_config['Newznab']['newznab_host'] = NEWZNAB_HOST new_config['Newznab']['newznab_apikey'] = NEWZNAB_APIKEY new_config['Newznab']['newznab_enabled'] = int(NEWZNAB_ENABLED) + new_config['Newznab']['extra_newznabs'] = EXTRA_NEWZNABS new_config['NZBsorg'] = {} new_config['NZBsorg']['nzbsorg'] = int(NZBSORG) diff --git a/headphones/webserve.py b/headphones/webserve.py index 93865a6a..2d190bf8 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -385,6 +385,7 @@ class WebInterface(object): "newznab_host" : headphones.NEWZNAB_HOST, "newznab_api" : headphones.NEWZNAB_APIKEY, "newznab_enabled" : checked(headphones.NEWZNAB_ENABLED), + "extra_newznabs" : headphones.EXTRA_NEWZNABS, "use_nzbsorg" : checked(headphones.NZBSORG), "nzbsorg_uid" : headphones.NZBSORG_UID, "nzbsorg_hash" : headphones.NZBSORG_HASH, @@ -465,7 +466,7 @@ class WebInterface(object): rename_files=0, correct_metadata=0, cleanup_files=0, add_album_art=0, embed_album_art=0, embed_lyrics=0, destination_dir=None, folder_format=None, file_format=None, include_extras=0, autowant_upcoming=False, autowant_all=False, interface=None, log_dir=None, music_encoder=0, encoder=None, bitrate=None, samplingfrequency=None, encoderfolder=None, advancedencoder=None, encoderoutputformat=None, encodervbrcbr=None, encoderquality=None, encoderlossless=0, prowl_enabled=0, prowl_onsnatch=0, prowl_keys=None, prowl_priority=0, xbmc_enabled=0, xbmc_host=None, xbmc_username=None, xbmc_password=None, xbmc_update=0, xbmc_notify=0, - nma_enabled=False, nma_apikey=None, nma_priority=0, synoindex_enabled=False, mirror=None, customhost=None, customport=None, customsleep=None, hpuser=None, hppass=None): + nma_enabled=False, nma_apikey=None, nma_priority=0, synoindex_enabled=False, mirror=None, customhost=None, customport=None, customsleep=None, hpuser=None, hppass=None, **kwargs): headphones.HTTP_HOST = http_host headphones.HTTP_PORT = http_port @@ -556,6 +557,22 @@ class WebInterface(object): headphones.CUSTOMSLEEP = customsleep headphones.HPUSER = hpuser headphones.HPPASS = hppass + + # Handle the variable config options. Note - keys with False values aren't getting passed + + headphones.EXTRA_NEWZNABS = [] + + for kwarg in kwargs: + if kwarg.startswith('newznab_host'): + newznab_number = kwarg[12:] + newznab_host = kwargs['newznab_host' + newznab_number] + newznab_api = kwargs['newznab_api' + newznab_number] + try: + newznab_enabled = int(kwargs['newznab_enabled' + newznab_number]) + except KeyError: + newznab_enabled = 0 + + headphones.EXTRA_NEWZNABS.append([newznab_host, newznab_api, newznab_enabled]) headphones.config_write() From 362338926c9aad9e961a73dfa83b0cc35934a632 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Thu, 26 Jul 2012 01:41:52 +0530 Subject: [PATCH 5/6] Make sure we can still add new newznab providers after a config save without refreshing the page. Moved the add function from the document ready function to the main functions --- data/interfaces/default/config.html | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 5f29847b..120ec49a 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -817,6 +817,20 @@ m<%inherit file="base.html"/> $(".remove").click(function() { $(this).parent().parent().remove(); }); + + $("#add_newznab").click(function() { + var intIdPrev = $("#newznab_providers > div").size(); + var intId = intIdPrev + 1; + var formfields = $("
"); + var removeButton = $("
"); + removeButton.click(function() { + $(this).parent().remove(); + }); + formfields.append(removeButton); + formfields.append("
"); + $("#newznab" + intIdPrev).after(formfields); + }); + $(function() { $( "#tabs" ).tabs(); }); @@ -831,18 +845,6 @@ m<%inherit file="base.html"/> } $(document).ready(function() { initThisPage(); - $("#add_newznab").click(function() { - var intIdPrev = $("#newznab_providers > div").size(); - var intId = intIdPrev + 1; - var formfields = $("
"); - var removeButton = $("
"); - removeButton.click(function() { - $(this).parent().remove(); - }); - formfields.append(removeButton); - formfields.append("
"); - $("#newznab" + intIdPrev).after(formfields); - }); }); From 351c5de23ebc5c9c2ce1c94cce77207f7cffa5c3 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Thu, 26 Jul 2012 02:05:54 +0530 Subject: [PATCH 6/6] Modified searcher.py to use the new multiple newznab format --- headphones/searcher.py | 81 +++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 95e14a5e..a7808220 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -216,6 +216,16 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): logger.info(u"No results found from NZBMatrix for %s" % term) if headphones.NEWZNAB: + + newznab_hosts = [[headphones.NEWZNAB_HOST, headphones.NEWZNAB_APIKEY, headphones.NEWZNAB_ENABLED]] + + # This is just to make sure we don't have any empty string for EXTRA_NEWZNABS + if not headphones.EXTRA_NEWZNABS: + headphones.EXTRA_NEWZNABS = [] + + for newznab_host in headphones.EXTRA_NEWZNABS: + newznab_hosts.append(newznab_host) + provider = "newznab" if headphones.PREFERRED_QUALITY == 3 or losslessOnly: categories = "3040" @@ -227,44 +237,49 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): if albums['Type'] == 'Other': categories = "3030" logger.info("Album type is audiobook/spokenword. Using audiobook category") + + for newznab_host in newznab_hosts: + + if newznab_host[2] == 0 or newznab_host[2] == '0': + continue - params = { "t": "search", - "apikey": headphones.NEWZNAB_APIKEY, - "cat": categories, - "maxage": headphones.USENET_RETENTION, - "q": term - } - - searchURL = headphones.NEWZNAB_HOST + '/api?' + urllib.urlencode(params) - - logger.info(u'Parsing results from %s' % (searchURL, headphones.NEWZNAB_HOST)) + params = { "t": "search", + "apikey": newznab_host[1], + "cat": categories, + "maxage": headphones.USENET_RETENTION, + "q": term + } - try: - data = urllib2.urlopen(searchURL, timeout=20).read() - except urllib2.URLError, e: - logger.warn('Error fetching data from %s: %s' % (headphones.NEWZNAB_HOST, e)) - data = False + searchURL = newznab_host[0] + '/api?' + urllib.urlencode(params) + + logger.info(u'Parsing results from %s' % (searchURL, newznab_host[0])) - if data: - - d = feedparser.parse(data) + try: + data = urllib2.urlopen(searchURL, timeout=20).read() + except urllib2.URLError, e: + logger.warn('Error fetching data from %s: %s' % (newznab_host[0], e)) + data = False + + if data: - if not len(d.entries): - logger.info(u"No results found from %s for %s" % (headphones.NEWZNAB_HOST, term)) - pass - - else: - for item in d.entries: - try: - url = item.link - title = item.title - size = int(item.links[1]['length']) + d = feedparser.parse(data) + + if not len(d.entries): + logger.info(u"No results found from %s for %s" % (newznab_host[0], term)) + pass + + else: + for item in d.entries: + try: + url = item.link + title = item.title + size = int(item.links[1]['length']) + + resultlist.append((title, size, url, provider)) + logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) - resultlist.append((title, size, url, provider)) - logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) - - except Exception, e: - logger.error(u"An unknown error occurred trying to parse the feed: %s" % e) + except Exception, e: + logger.error(u"An unknown error occurred trying to parse the feed: %s" % e) if headphones.NZBSORG: provider = "nzbsorg"