diff --git a/Headphones.py b/Headphones.py old mode 100644 new mode 100755 diff --git a/data/interfaces/brink/config.html b/data/interfaces/brink/config.html index 55ffde67..7ce73c8e 100644 --- a/data/interfaces/brink/config.html +++ b/data/interfaces/brink/config.html @@ -292,32 +292,6 @@

L Search Providers

"We provide you with a automated search service to locate binary files/secgments that can be found on the public access network called Usenet." - - -
- - - - - -
-

DNZBMatrix

- -
-
- - - - - - - - - -
-
-
-
@@ -409,32 +383,6 @@
- - -
- - - - - -
-

DNewzbin

- -
-
- - - - - - - - - -
-
-
- @@ -548,7 +496,7 @@ diff --git a/data/interfaces/classic/config.html b/data/interfaces/classic/config.html index 9a5e92a3..88f6554e 100644 --- a/data/interfaces/classic/config.html +++ b/data/interfaces/classic/config.html @@ -319,7 +319,7 @@

File Format:


- Use: $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year + Use: $Disc/$disc (disc #), $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year
- Use: $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year + Use: $Disc/$disc (disc #), $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year

Miscellaneous:

diff --git a/data/interfaces/default/base.html b/data/interfaces/default/base.html index 783f4f36..0b064a84 100644 --- a/data/interfaces/default/base.html +++ b/data/interfaces/default/base.html @@ -83,9 +83,6 @@ Check for new version -
Version: ${headphones.CURRENT_VERSION} %if version.HEADPHONES_VERSION != 'master': diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 95d3e2e7..5fc7b026 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -362,6 +362,25 @@
+
+ Search Words + Separate words with a comma, e.g. "word1,word2,word3" +
+ + + Results with any of these words in the title will be filtered out +
+
+ + + Results with these words in the title will be preferred over results without them +
+
+ + + Results without these words in the title will be filtered out +
+
@@ -414,7 +433,7 @@
- Use: $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year + Use: $Disc/$disc (disc #), $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year
diff --git a/data/interfaces/remix/config.html b/data/interfaces/remix/config.html index 9a5e92a3..88f6554e 100644 --- a/data/interfaces/remix/config.html +++ b/data/interfaces/remix/config.html @@ -319,7 +319,7 @@

File Format:


- Use: $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year + Use: $Disc/$disc (disc #), $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year

Miscellaneous:

diff --git a/headphones/__init__.py b/headphones/__init__.py index 7bc31b73..ad7bd3dc 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -152,6 +152,10 @@ NZBSRUS_APIKEY = None NZBX = False +PREFERRED_WORDS = None +IGNORED_WORDS = None +REQUIRED_WORDS = None + LASTFM_USERNAME = None LOSSY_MEDIA_FORMATS = ["mp3", "aac", "ogg", "ape", "m4a"] @@ -281,6 +285,7 @@ def initialize(): LIBRARYSCAN, 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, EXTRA_NEWZNABS, \ NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, NZBSRUS, NZBSRUS_UID, NZBSRUS_APIKEY, NZBX, \ + PREFERRED_WORDS, REQUIRED_WORDS, IGNORED_WORDS, \ LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, ENCODERFOLDER, ENCODER_PATH, ENCODER, XLDPROFILE, BITRATE, SAMPLINGFREQUENCY, \ MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, ENCODERLOSSLESS, DELETE_LOSSLESS_FILES, \ PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, PUSHOVER_ENABLED, PUSHOVER_PRIORITY, PUSHOVER_KEYS, PUSHOVER_ONSNATCH, MIRRORLIST, \ @@ -425,6 +430,10 @@ def initialize(): NZBSRUS_APIKEY = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_apikey', '') NZBX = bool(check_setting_int(CFG, 'nzbX', 'nzbx', 0)) + + PREFERRED_WORDS = check_setting_str(CFG, 'General', 'preferred_words', '') + IGNORED_WORDS = check_setting_str(CFG, 'General', 'ignored_words', '') + REQUIRED_WORDS = check_setting_str(CFG, 'General', 'required_words', '') LASTFM_USERNAME = check_setting_str(CFG, 'General', 'lastfm_username', '') @@ -762,6 +771,10 @@ def config_write(): new_config['nzbX'] = {} new_config['nzbX']['nzbx'] = int(NZBX) + + new_config['General']['preferred_words'] = PREFERRED_WORDS + new_config['General']['ignored_words'] = IGNORED_WORDS + new_config['General']['required_words'] = REQUIRED_WORDS new_config['Prowl'] = {} new_config['Prowl']['prowl_enabled'] = int(PROWL_ENABLED) diff --git a/headphones/helpers.py b/headphones/helpers.py index 298062ee..c35e6a53 100644 --- a/headphones/helpers.py +++ b/headphones/helpers.py @@ -322,3 +322,9 @@ def sab_sanitize_foldername(name): # name = name[:maxlen] return name + +def split_string(mystring): + mylist = [] + for each_word in mystring.split(','): + mylist.append(each_word.strip()) + return mylist diff --git a/headphones/mb.py b/headphones/mb.py index 5a20e0ad..e693c322 100644 --- a/headphones/mb.py +++ b/headphones/mb.py @@ -44,7 +44,7 @@ def startmb(): mbport = int(headphones.CUSTOMPORT) sleepytime = int(headphones.CUSTOMSLEEP) elif headphones.MIRROR == "headphones": - mbhost = "178.63.142.150" + mbhost = "192.30.34.130" mbport = 8181 mbuser = headphones.HPUSER mbpass = headphones.HPPASS diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index c3f8ac18..c8800c7b 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -754,7 +754,12 @@ def renameFiles(albumpath, downloaded_track_list, release): except: logger.info("MediaFile couldn't parse: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace')) continue - + + if not f.disc: + discnumber = '' + else: + discnumber = '%d' % f.disc + if not f.track: tracknumber = '' else: @@ -771,11 +776,13 @@ def renameFiles(albumpath, downloaded_track_list, release): else: title = f.title - values = { '$Track': tracknumber, + values = { '$Disc': discnumber, + '$Track': tracknumber, '$Title': title, '$Artist': release['ArtistName'], '$Album': release['AlbumTitle'], '$Year': year, + '$disc': discnumber, '$track': tracknumber, '$title': title.lower(), '$artist': release['ArtistName'].lower(), diff --git a/headphones/searcher.py b/headphones/searcher.py index df0760d3..9d0e4d01 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -109,7 +109,7 @@ def searchforalbum(albumid=None, new=False, lossless=False): for result in results: foundNZB = "none" - if (headphones.NZBMATRIX or headphones.NEWZNAB or headphones.NZBSORG or headphones.NEWZBIN or headphones.NZBX or headphones.NZBSRUS) and (headphones.SAB_HOST or headphones.BLACKHOLE): + if (headphones.NEWZNAB or headphones.NZBSORG or headphones.NZBX or headphones.NZBSRUS) and (headphones.SAB_HOST or headphones.BLACKHOLE): if result['Status'] == "Wanted Lossless": foundNZB = searchNZB(result['AlbumID'], new, losslessOnly=True) else: @@ -179,66 +179,6 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): logger.info("Searching for %s since it was marked as wanted" % term) resultlist = [] - -# if headphones.NZBMATRIX: -# provider = "nzbmatrix" -# if headphones.PREFERRED_QUALITY == 3 or losslessOnly: -# categories = "23" -# elif headphones.PREFERRED_QUALITY: -# categories = "23,22" -# else: -# categories = "22" -# -# # Search Audiobooks/Singles/etc -# if albums['Type'] == "Other": -# categories = "49" -# logger.info("Album type is audiobook/spokenword. Using audiobook category") -# if albums['Type'] == "Single": -# categories = "47" -# logger.info("Album type is 'Single'. Using singles category") -# -# # For some reason NZBMatrix is erroring out/timing out when the term starts with a "The" right now -# # so we'll strip it out for the time being. This may get fixed on their end, it may not, but -# # hopefully this will fix it for now. If you notice anything else it gets stuck on, please post it -# # on Github so it can be added -# if term.lower().startswith("the "): -# term = term[4:] -# -# -# params = { "page": "download", -# "username": headphones.NZBMATRIX_USERNAME, -# "apikey": headphones.NZBMATRIX_APIKEY, -# "subcat": categories, -# "maxage": headphones.USENET_RETENTION, -# "english": 1, -# "ssl": 1, -# "scenename": 1, -# "term": term -# } -# -# searchURL = "https://rss.nzbmatrix.com/rss.php?" + urllib.urlencode(params) -# logger.info(u'Parsing results from NZBMatrix' % searchURL) -# try: -# data = urllib2.urlopen(searchURL, timeout=20).read() -# except urllib2.URLError, e: -# logger.warn('Error fetching data from NZBMatrix: %s' % e) -# data = False -# -# if data: -# -# d = feedparser.parse(data) -# -# 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))) -# -# except AttributeError, e: -# logger.info(u"No results found from NZBMatrix for %s" % term) if headphones.NEWZNAB: @@ -476,95 +416,27 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): except Exception, e: logger.error(u"An unknown error occurred trying to parse the feed: %s" % e) -# if headphones.NEWZBIN: -# provider = "newzbin" -# providerurl = "https://www.newzbin2.es/" -# if headphones.PREFERRED_QUALITY == 3 or losslessOnly: -# categories = "7" #music -# format = "2" #flac -# elif headphones.PREFERRED_QUALITY: -# categories = "7" #music -# format = "10" #mp3+flac -# else: -# categories = "7" #music -# format = "8" #mp3 -# -# if albums['Type'] == 'Other': -# categories = "13" -# format = "16" -# logger.info("Album type is audiobook/spokenword. Using audiobook category") -# -# params = { -# "fpn": "p", -# 'u_nfo_posts_only': 0, -# 'u_url_posts_only': 0, -# 'u_comment_posts_only': 0, -# 'u_show_passworded': 0, -# "searchaction": "Search", -# #"dl": 1, -# "category": categories, -# "retention": headphones.USENET_RETENTION, -# "ps_rb_audio_format": format, -# "feed": "rss", -# "u_post_results_amt": 50, #this can default to a high number per user -# "hauth": 1, -# "q": term -# } -# searchURL = providerurl + "search/?%s" % urllib.urlencode(params) -# try: -# data = getNewzbinURL(searchURL) -# except exceptions.NewzbinAPIThrottled: -# #try again if we were throttled -# data = getNewzbinURL(searchURL) -# if data: -# logger.info(u'Parsing results from %s' % (searchURL, providerurl)) -# -# try: -# d = minidom.parseString(data) -# node = d.documentElement -# items = d.getElementsByTagName("item") -# except ExpatError: -# logger.info('Unable to get the NEWZBIN feed. Check that your settings are correct - post a bug if they are') -# items = [] -# -# if len(items): -# -# for item in items: -# -# sizenode = item.getElementsByTagName("report:size")[0].childNodes -# titlenode = item.getElementsByTagName("title")[0].childNodes -# linknode = item.getElementsByTagName("link")[0].childNodes -# -# for node in sizenode: -# size = int(node.data) -# for node in titlenode: -# title = node.data -# for node in linknode: -# url = node.data -# -# #exract the reportid from the link nodes -# id_regex = re.escape(providerurl) + 'browse/post/(\d+)/' -# id_match = re.match(id_regex, url) -# if not id_match: -# logger.info("Didn't find a valid Newzbin reportid in linknode") -# else: -# url = id_match.group(1) #we have to make a post request later, need the id -# if url: -# resultlist.append((title, size, url, provider)) -# logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) -# else: -# logger.info('No url link found in nzb. Skipping.') -# -# else: -# logger.info('No results found from NEWZBIN for %s' % term) -# - #attempt to verify that this isn't a substring result - #when looking for "Foo - Foo" we don't want "Foobar" - #this should be less of an issue when it isn't a self-titled album so we'll only check vs artist + # attempt to verify that this isn't a substring result + # when looking for "Foo - Foo" we don't want "Foobar" + # this should be less of an issue when it isn't a self-titled album so we'll only check vs artist + # + # Also will filter flac & remix albums if not specifically looking for it + # This code also checks the ignored words and required words + if len(resultlist): - resultlist[:] = [result for result in resultlist if verifyresult(result[0], artistterm, term)] + resultlist[:] = [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)] if len(resultlist): + + # Add a priority if it has any of the preferred words + temp_list = [] + for result in resultlist: + if any(word.lower() in result[0].lower() for word in helpers.split_string(headphones.PREFERRED_WORDS)): + temp_list.append((result[0],result[1],result[2],result[3],1)) + else: + temp_list.append((result[0],result[1],result[2],result[3],0)) + + resultlist = temp_list if headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE: @@ -579,11 +451,12 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): if not targetsize: logger.info('No track information for %s - %s. Defaulting to highest quality' % (albums[0], albums[1])) - nzblist = sorted(resultlist, key=lambda title: title[1], reverse=True) + nzblist = sorted(resultlist, key=lambda title: (-title[4] , -title[1])) else: logger.info('Target size: %s' % helpers.bytes_to_mb(targetsize)) newlist = [] + flac_list = [] if headphones.PREFERRED_BITRATE_HIGH_BUFFER: high_size_limit = targetsize * int(headphones.PREFERRED_BITRATE_HIGH_BUFFER)/100 @@ -598,6 +471,11 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): if high_size_limit and (result[1] > high_size_limit): logger.info(result[0] + " is too large for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Maxsize: " + helpers.bytes_to_mb(high_size_limit)) + + # Add lossless nzbs to the "flac list" which we can use if there are no good lossy matches + if 'flac' in result[0].lower(): + flac_list.append((result[0], result[1], result[2], result[3], result[4])) + continue if low_size_limit and (result[1] < low_size_limit): @@ -605,20 +483,24 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): continue delta = abs(targetsize - result[1]) - newlist.append((result[0], result[1], result[2], result[3], delta)) + newlist.append((result[0], result[1], result[2], result[3], result[4], delta)) - nzblist = sorted(newlist, key=lambda title: title[4]) + nzblist = sorted(newlist, key=lambda title: (-title[4], title[5])) + + if not len(nzblist) and len(flac_list) and headphones.PREFERRED_BITRATE_ALLOW_LOSSLESS: + logger.info("Since there were no appropriate lossy matches (and at least one lossless match), going to use lossless instead") + nzblist = sorted(flac_list, key=lambda title: (-title[4], -title[1])) except Exception, e: logger.debug('Error: %s' % str(e)) logger.info('No track information for %s - %s. Defaulting to highest quality' % (albums[0], albums[1])) - nzblist = sorted(resultlist, key=lambda title: title[1], reverse=True) + nzblist = sorted(resultlist, key=lambda title: (-title[4], -title[1])) else: - nzblist = sorted(resultlist, key=lambda title: title[1], reverse=True) + nzblist = sorted(resultlist, key=lambda title: (-title[4], -title[1])) if new: @@ -660,8 +542,7 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): # If we sent the file to sab, we can check how it was renamed and insert that into the snatched table (replace_spaces, replace_dots) = sab.checkConfig() - print replace_spaces - print replace_dots + if replace_dots: nzb_folder_name = helpers.sab_replace_dots(nzb_folder_name) if replace_spaces: @@ -690,7 +571,7 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): -def verifyresult(title, artistterm, term): +def verifyresult(title, artistterm, term, lossless): title = re.sub('[\.\-\/\_]', ' ', title) @@ -709,10 +590,27 @@ def verifyresult(title, artistterm, term): #another attempt to weed out substrings. We don't want "Vol III" when we were looking for "Vol II" # Filter out remix search results (if we're not looking for it) - if 'remix' not in term and 'remix' in title: + if 'remix' not in term.lower() and 'remix' in title.lower(): logger.info("Removed " + title + " from results because it's a remix album and we're not looking for a remix album right now") return False + # Filter out FLAC if we're not specifically looking for it + if headphones.PREFERRED_QUALITY == (0 or '0') and 'flac' in title.lower() and not lossless: + logger.info("Removed " + title + " from results because it's a lossless album and we're not looking for a lossless album right now") + return False + + if headphones.IGNORED_WORDS: + for each_word in helpers.split_string(headphones.IGNORED_WORDS): + if each_word.lower() in title.lower(): + logger.info("Removed " + title + " from results because it contains ignored word: '" + each_word + "'") + return False + + if headphones.REQUIRED_WORDS: + for each_word in helpers.split_string(headphones.REQUIRED_WORDS): + if each_word.lower() not in title.lower(): + logger.info("Removed " + title + " from results because it doesn't contain required word: '" + each_word + "'") + return False + tokens = re.split('\W', term, re.IGNORECASE | re.UNICODE) for token in tokens: @@ -1256,7 +1154,7 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): #when looking for "Foo - Foo" we don't want "Foobar" #this should be less of an issue when it isn't a self-titled album so we'll only check vs artist if len(resultlist): - resultlist[:] = [result for result in resultlist if verifyresult(result[0], artistterm, term)] + resultlist[:] = [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)] if len(resultlist): diff --git a/headphones/webserve.py b/headphones/webserve.py index 8f13bdbe..349e95b1 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -595,6 +595,9 @@ class WebInterface(object): "nzbsrus_uid" : headphones.NZBSRUS_UID, "nzbsrus_apikey" : headphones.NZBSRUS_APIKEY, "use_nzbx" : checked(headphones.NZBX), + "preferred_words" : headphones.PREFERRED_WORDS, + "ignored_words" : headphones.IGNORED_WORDS, + "required_words" : headphones.REQUIRED_WORDS, "torrentblackhole_dir" : headphones.TORRENTBLACKHOLE_DIR, "download_torrent_dir" : headphones.DOWNLOAD_TORRENT_DIR, "numberofseeders" : headphones.NUMBEROFSEEDERS, @@ -700,8 +703,8 @@ 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, newznab=0, newznab_host=None, newznab_apikey=None, - newznab_enabled=0, nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, nzbsrus=0, nzbsrus_uid=None, nzbsrus_apikey=None, nzbx=0, preferred_quality=0, preferred_bitrate=None, - detect_bitrate=0, move_files=0, torrentblackhole_dir=None, download_torrent_dir=None, + newznab_enabled=0, nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, nzbsrus=0, nzbsrus_uid=None, nzbsrus_apikey=None, nzbx=0, preferred_words=None, required_words=None, ignored_words=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, whatcd=0, whatcd_username=None, whatcd_password=None, rutracker=0, rutracker_user=None, rutracker_password=None, rename_files=0, correct_metadata=0, cleanup_files=0, add_album_art=0, album_art_format=None, embed_album_art=0, embed_lyrics=0, destination_dir=None, lossless_destination_dir=None, folder_format=None, file_format=None, include_extras=0, single=0, ep=0, compilation=0, soundtrack=0, live=0, @@ -748,6 +751,9 @@ class WebInterface(object): headphones.NZBSRUS_UID = nzbsrus_uid headphones.NZBSRUS_APIKEY = nzbsrus_apikey headphones.NZBX = nzbx + headphones.PREFERRED_WORDS = preferred_words + headphones.IGNORED_WORDS = ignored_words + headphones.REQUIRED_WORDS = required_words headphones.TORRENTBLACKHOLE_DIR = torrentblackhole_dir headphones.NUMBEROFSEEDERS = numberofseeders headphones.DOWNLOAD_TORRENT_DIR = download_torrent_dir diff --git a/lib/musicbrainzngs/musicbrainz.py b/lib/musicbrainzngs/musicbrainz.py index e16c0816..0dcdaf2a 100644 --- a/lib/musicbrainzngs/musicbrainz.py +++ b/lib/musicbrainzngs/musicbrainz.py @@ -497,7 +497,7 @@ def _mb_request(path, method='GET', auth_required=False, client_required=False, req.add_header('User-Agent', _useragent) # Add headphones credentials - if hostname == '178.63.142.150:8181': + if hostname == '192.30.34.130:8181': base64string = base64.encodestring('%s:%s' % (hpuser, hppassword)).replace('\n', '') req.add_header("Authorization", "Basic %s" % base64string)