From 1d7142c774a06ba5a6a9636d1fba833c4abf05ce Mon Sep 17 00:00:00 2001 From: clashlab Date: Wed, 23 Jan 2013 15:06:32 +0100 Subject: [PATCH 01/10] Fix NZBsRus results parsing NZBsRus search returns a Python dictionnary. This fix allows to take into account NZBsRus results. Calling eval is not a really good idea and should be replaced --- headphones/searcher.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 9d0e4d01..0027db29 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -348,18 +348,18 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): if data: - d = feedparser.parse(data) + d = eval(data.replace('null','None')) - if not len(d.entries): + if d['matches'] <= 0: logger.info(u"No results found from NZBsRus for %s" % term) pass else: - for item in d.entries: + for item in d['results']: try: - url = item.link - title = item.title - size = int(item.links[1]['length']) + url = "http://www.nzbsrus.com/nzbdownload_rss.php/" + item['id'] + "/" + headphones.NZBSRUS_UID + "/" + item['key'] + title = item['name'] + size = int(item['size']) resultlist.append((title, size, url, provider)) logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) From a3b764d3d524f95238bc37839e28ef9934bb85f3 Mon Sep 17 00:00:00 2001 From: Michel Wilson Date: Mon, 18 Feb 2013 15:18:41 +0100 Subject: [PATCH 02/10] Make albumart-files world readable --- headphones/postprocessor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index c3f8ac18..afb4f35b 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -448,9 +448,11 @@ def addAlbumArt(artwork, albumpath, release): if album_art_name.startswith('.'): album_art_name = album_art_name.replace(0, '_') + prev = os.umask(0002) file = open(os.path.join(albumpath, album_art_name), 'wb') file.write(artwork) file.close() + os.umask(prev) def cleanupFiles(albumpath): logger.info('Cleaning up files') From d0ab10d15604743e41b792d9919642fab45df019 Mon Sep 17 00:00:00 2001 From: Michel Wilson Date: Mon, 18 Feb 2013 17:34:08 +0100 Subject: [PATCH 03/10] Save & use original umask. Saves and uses the original umask at various places where user-accessible files are written. --- headphones/__init__.py | 9 ++++++++- headphones/postprocessor.py | 2 +- headphones/searcher.py | 4 ++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/headphones/__init__.py b/headphones/__init__.py index 7bc31b73..017a3c51 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -221,6 +221,8 @@ HPPASS = None CACHE_SIZEMB = 32 +UMASK = None + def CheckSection(sec): """ Check if INI section exists, if not create it """ try: @@ -286,7 +288,8 @@ def initialize(): PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, PUSHOVER_ENABLED, PUSHOVER_PRIORITY, PUSHOVER_KEYS, PUSHOVER_ONSNATCH, MIRRORLIST, \ MIRROR, CUSTOMHOST, CUSTOMPORT, CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, \ XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, \ - PREFERRED_BITRATE_LOW_BUFFER, PREFERRED_BITRATE_ALLOW_LOSSLESS, CACHE_SIZEMB + PREFERRED_BITRATE_LOW_BUFFER, PREFERRED_BITRATE_ALLOW_LOSSLESS, CACHE_SIZEMB, \ + UMASK if __INITIALIZED__: return False @@ -575,6 +578,10 @@ def initialize(): else: LATEST_VERSION = CURRENT_VERSION + # Store the original umask + UMASK = os.umask(0) + os.umask(UMASK) + __INITIALIZED__ = True return True diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index afb4f35b..34eaa1ab 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -448,7 +448,7 @@ def addAlbumArt(artwork, albumpath, release): if album_art_name.startswith('.'): album_art_name = album_art_name.replace(0, '_') - prev = os.umask(0002) + prev = os.umask(headphones.UMASK) file = open(os.path.join(albumpath, album_art_name), 'wb') file.write(artwork) file.close() diff --git a/headphones/searcher.py b/headphones/searcher.py index df0760d3..bdabca57 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -672,9 +672,11 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): nzb_name = nzb_folder_name + '.nzb' download_path = os.path.join(headphones.BLACKHOLE_DIR, nzb_name) try: + prev = os.umask(headphones.UMASK) f = open(download_path, 'w') f.write(data) f.close() + os.umask(prev) logger.info('File saved to: %s' % nzb_name) except Exception, e: logger.error('Couldn\'t write NZB file: %s' % e) @@ -1341,9 +1343,11 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): break else: #Write the torrent file to a path derived from the TORRENTBLACKHOLE_DIR and file name. + prev = os.umask(headphones.UMASK) torrent_file = open(download_path, 'wb') torrent_file.write(data) torrent_file.close() + os.umask(prev) #Open the fresh torrent file again so we can extract the proper torrent name #Used later in post-processing. From 53a1458bf6826e6d819574dde5b9feb9a7aa1acb Mon Sep 17 00:00:00 2001 From: Ade Date: Fri, 8 Mar 2013 22:06:30 +1300 Subject: [PATCH 04/10] User search term for waffles & rutracker + add year to normal search for waffles --- headphones/searcher.py | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index df0760d3..55f32f96 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -125,7 +125,7 @@ def searchforalbum(albumid=None, new=False, lossless=False): else: foundNZB = "none" - if (headphones.NZBMATRIX or headphones.NEWZNAB or headphones.NZBSORG or headphones.NEWZBIN) and (headphones.SAB_HOST or headphones.BLACKHOLE): + 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): foundNZB = searchNZB(albumid, new, lossless) if (headphones.KAT or headphones.ISOHUNT or headphones.MININOVA or headphones.WAFFLES or headphones.RUTRACKER or headphones.WHATCD) and foundNZB == "none": @@ -845,6 +845,12 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): else: term = cleanartist + ' ' + cleanalbum + # Save user search term + if albums[4]: + usersearchterm = term + else: + usersearchterm = '' + semi_clean_artist_term = re.sub('[\.\-\/]', ' ', semi_cleanartist).encode('utf-8', 'replace') semi_clean_album_term = re.sub('[\.\-\/]', ' ', semi_cleanalbum).encode('utf-8', 'replace') # Replace bad characters in the term and unicode it @@ -946,11 +952,17 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): format = "MP3" maxsize = 300000000 - query_items = ['artist:"%s"' % artistterm, - 'album:"%s"' % albumterm, - 'format:(%s)' % format, - 'size:[0 TO %d]' % maxsize, - '-seeders:0'] # cut out dead torrents + if not usersearchterm: + query_items = ['artist:"%s"' % artistterm, + 'album:"%s"' % albumterm, + 'year:(%s)' % year] + else: + query_items = [usersearchterm] + + query_items.extend(['format:(%s)' % format, + 'size:[0 TO %d]' % maxsize, + '-seeders:0']) # cut out dead torrents + if bitrate: query_items.append('bitrate:"%s"' % bitrate) @@ -1005,7 +1017,7 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): # Ignore if release date not specified, results too unpredictable - if not year: + if not year and not usersearchterm: logger.info(u'Release date not specified, ignoring for rutracker.org') else: @@ -1024,8 +1036,12 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): bitrate = True # build search url based on above - - searchURL = rutracker.searchurl(artistterm, albumterm, year, format) + + if not usersearchterm: + searchURL = rutracker.searchurl(artistterm, albumterm, year, format) + else: + searchURL = rutracker.searchurl(usersearchterm, ' ', ' ', format) + logger.info(u'Parsing results from rutracker.org' % searchURL) # parse results and get best match From 9b44941ec012806ee148c6727f755d9d2857c2d4 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Mon, 13 May 2013 14:55:04 +0700 Subject: [PATCH 05/10] Replace eval() with json.loads() for nzbsrus --- headphones/searcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 0027db29..a70d5e0a 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -348,7 +348,7 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): if data: - d = eval(data.replace('null','None')) + d = json.loads(data.replace('null','None')) if d['matches'] <= 0: logger.info(u"No results found from NZBsRus for %s" % term) From ba826be34b8d492c29c3387aadeec04006a42881 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Mon, 13 May 2013 15:22:47 +0700 Subject: [PATCH 06/10] Fixed whitespace/indentation in searcher.py --- headphones/searcher.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 949cf751..28a8b048 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -1236,19 +1236,19 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): download_path = os.path.join(headphones.TORRENTBLACKHOLE_DIR, torrent_name) try: if bestqual[3] == 'rutracker.org': - download_path = rutracker.get_torrent(bestqual[2], headphones.TORRENTBLACKHOLE_DIR) - if not download_path: - break + download_path = rutracker.get_torrent(bestqual[2], headphones.TORRENTBLACKHOLE_DIR) + if not download_path: + break else: - #Write the torrent file to a path derived from the TORRENTBLACKHOLE_DIR and file name. + #Write the torrent file to a path derived from the TORRENTBLACKHOLE_DIR and file name. prev = os.umask(headphones.UMASK) - torrent_file = open(download_path, 'wb') - torrent_file.write(data) - torrent_file.close() + torrent_file = open(download_path, 'wb') + torrent_file.write(data) + torrent_file.close() os.umask(prev) - - #Open the fresh torrent file again so we can extract the proper torrent name - #Used later in post-processing. + + #Open the fresh torrent file again so we can extract the proper torrent name + #Used later in post-processing. torrent_file = open(download_path, 'rb') torrent_info = bencode.bdecode(torrent_file.read()) torrent_file.close() From 86691f83fd7b065459aa8a6094cd2653befa7c92 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Mon, 13 May 2013 16:01:04 +0700 Subject: [PATCH 07/10] Use metadata artist tag when renaming files with Various Artists as album artist name --- headphones/postprocessor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index e64575e7..29552a51 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -778,16 +778,21 @@ def renameFiles(albumpath, downloaded_track_list, release): else: title = f.title + if release['ArtistName'] == "Various Artists" and f.artist: + artistname = f.artist + else: + artistname = release['ArtistName'] + values = { '$Disc': discnumber, '$Track': tracknumber, '$Title': title, - '$Artist': release['ArtistName'], + '$Artist': artistname, '$Album': release['AlbumTitle'], '$Year': year, '$disc': discnumber, '$track': tracknumber, '$title': title.lower(), - '$artist': release['ArtistName'].lower(), + '$artist': artistname.lower(), '$album': release['AlbumTitle'].lower(), '$year': year } From 1a139e2301defbe16894e433abcd229188a1a03b Mon Sep 17 00:00:00 2001 From: rembo10 Date: Mon, 13 May 2013 16:25:45 +0700 Subject: [PATCH 08/10] Replace any errors when converting unicode album path to bytestring in checkFolder() - should fix issue #1100 when it fails to convert unicode chars to cp1252 --- headphones/postprocessor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index 29552a51..536100b5 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -52,11 +52,11 @@ def checkFolder(): sab_replace_spaces(sab_replace_dots(album['FolderName'])) ] - torrent_album_path = os.path.join(headphones.DOWNLOAD_TORRENT_DIR, album['FolderName']).encode(headphones.SYS_ENCODING) + torrent_album_path = os.path.join(headphones.DOWNLOAD_TORRENT_DIR, album['FolderName']).encode(headphones.SYS_ENCODING,'replace') for nzb_folder_name in nzb_album_possibilities: - nzb_album_path = os.path.join(headphones.DOWNLOAD_DIR, nzb_folder_name).encode(headphones.SYS_ENCODING) + nzb_album_path = os.path.join(headphones.DOWNLOAD_DIR, nzb_folder_name).encode(headphones.SYS_ENCODING, 'replace') if os.path.exists(nzb_album_path): logger.debug('Found %s in NZB download folder. Verifying....' % album['FolderName']) @@ -481,7 +481,7 @@ def moveFiles(albumpath, release, tracks): else: sortname = release['ArtistName'] - if sortname.isdigit(): + if sortname[0].isdigit(): firstchar = '0-9' else: firstchar = sortname[0] From be654361b59d908abd6cc11b6d6c6e098f434771 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Mon, 13 May 2013 16:36:19 +0700 Subject: [PATCH 09/10] Fix for unknown release group types --- headphones/mb.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/headphones/mb.py b/headphones/mb.py index e693c322..f61ef991 100644 --- a/headphones/mb.py +++ b/headphones/mb.py @@ -318,7 +318,10 @@ def getRelease(releaseid, include_artist_info=True): if 'release-group' in results: release['rgid'] = unicode(results['release-group']['id']) release['rg_title'] = unicode(results['release-group']['title']) - release['rg_type'] = unicode(results['release-group']['type']) + try: + release['rg_type'] = unicode(results['release-group']['type']) + except KeyError: + release['rg_type'] = u'Unknown' else: logger.warn("Release " + releaseid + "had no ReleaseGroup associated") From 09bfcf4b0e443bf8cd5c648baf73f81368d678b6 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Mon, 13 May 2013 16:47:53 +0700 Subject: [PATCH 10/10] Added SortArtist option for folder & file renaming. If artist starts with 'The', will make a 'Artist, The' folder --- headphones/postprocessor.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index 536100b5..fd54f17f 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -477,7 +477,7 @@ def moveFiles(albumpath, release, tracks): releasetype = release['Type'].replace('/', '_') if release['ArtistName'].startswith('The '): - sortname = release['ArtistName'][4:] + sortname = release['ArtistName'][4:] + ", The" else: sortname = release['ArtistName'] @@ -488,11 +488,13 @@ def moveFiles(albumpath, release, tracks): values = { '$Artist': artist, + '$SortArtist': sortname, '$Album': album, '$Year': year, '$Type': releasetype, '$First': firstchar.upper(), '$artist': artist.lower(), + '$sortartist': sortname.lower(), '$album': album.lower(), '$year': year, '$type': releasetype.lower(), @@ -782,17 +784,24 @@ def renameFiles(albumpath, downloaded_track_list, release): artistname = f.artist else: artistname = release['ArtistName'] + + if artistname.startswith('The '): + sortname = artistname[4:] + ", The" + else: + sortname = artistname values = { '$Disc': discnumber, '$Track': tracknumber, '$Title': title, '$Artist': artistname, + '$SortArtist': sortname, '$Album': release['AlbumTitle'], '$Year': year, '$disc': discnumber, '$track': tracknumber, '$title': title.lower(), '$artist': artistname.lower(), + '$sortartist': sortname.lower(), '$album': release['AlbumTitle'].lower(), '$year': year }