diff --git a/data/interfaces/default/album.html b/data/interfaces/default/album.html index ba8bf33b..5127cf28 100644 --- a/data/interfaces/default/album.html +++ b/data/interfaces/default/album.html @@ -89,9 +89,15 @@
- -

${album['AlbumTitle']}

-

${album['ArtistName']}

+ +

+ ${album['AlbumTitle']} +

+ +

+ ${album['ArtistName']} +

+ <% totalduration = myDB.action("SELECT SUM(TrackDuration) FROM tracks WHERE AlbumID=?", [album['AlbumID']]).fetchone()[0] totaltracks = len(myDB.select("SELECT TrackTitle from tracks WHERE AlbumID=?", [album['AlbumID']])) @@ -275,9 +281,58 @@ feedback.fadeIn(); } + var loadingMessage = false; + var spinner_active = false; + var loadingtext_active = false; + var refreshInterval; + var wasLoading = false; + var x = 0; + + function checkAlbumStatus() { + $.getJSON("getAlbumjson?AlbumID=${album['AlbumID']}", function(data) { + if (data['Status'] == "Loading"){ + wasLoading = true; + $('#albumnamelink').text(data["AlbumTitle"]); + $('#artistnamelink').text(data["ArtistName"]); + if (loadingMessage == false){ + $("#ajaxMsg").after( "
" ); + showArtistMsg("Getting album information"); + loadingMessage = true; + } + if (spinner_active == false){ + $('#albumname').prepend('') + spinner_active = true; + } + if (loadingtext_active == false){ + $('#albumname').append('

(Album information is currently being loaded)

') + loadingtext_active = true; + } + } + else{ + if (++x === 5) { + clearInterval(refreshInterval); + } + var sts = $("#artistname").text(); + if (wasLoading == true || sts == "Loading"){ + location.reload(); + $('#albumnamespinner').remove() + $('#loadingtext').remove() + $('#ajaxMsg2').remove() + spinner_active = false + loadingtext_active = false + loadingMessage = false + } + } + }); + } + $(document).ready(function() { getAlbumInfo(); initThisPage(); + checkAlbumStatus(); + refreshInterval = setInterval(function(){ + checkAlbumStatus(); + }, 3000); }); diff --git a/data/interfaces/default/base.html b/data/interfaces/default/base.html index e606a02b..2920f0a5 100644 --- a/data/interfaces/default/base.html +++ b/data/interfaces/default/base.html @@ -58,7 +58,7 @@
- @@ -115,3 +115,25 @@ <%def name="javascriptIncludes()"> <%def name="headIncludes()"> <%def name="headerIncludes()"> + + + diff --git a/data/interfaces/default/css/style.css b/data/interfaces/default/css/style.css index 6789726f..60baca70 100644 --- a/data/interfaces/default/css/style.css +++ b/data/interfaces/default/css/style.css @@ -758,7 +758,7 @@ div#searchbar input[type=text] { line-height: normal; margin-right: 5px; padding: 4px 5px 4px 25px; - width: 150px; + width: 200px; } div#searchbar .mini-icon { color: #999; @@ -1126,13 +1126,34 @@ div#artistheader h2 a { padding: 2px 10px; } #searchresults_table th#albumname { - min-width: 225px; + min-width: 250px; text-align: left; + font-size: 14px; } #searchresults_table th#artistname { min-width: 325px; text-align: left; } +#searchresults_table th#artistnamesmall { + min-width: 125px; + text-align: left; + font-size: 14px; +} +#searchresults_table th#reldate { + min-width: 80px; + text-align: center; + font-size: 14px; +} +#searchresults_table th#format { + min-width: 50px; + text-align: left; + font-size: 14px; +} +#searchresults_table th#tracks { + min-width: 50px; + text-align: left; + font-size: 14px; +} #searchresults_table #artistImg { background: url("../images/loader_black.gif") no-repeat scroll center center #ffffff; border: 3px solid #FFFFFF; @@ -1144,15 +1165,40 @@ div#artistheader h2 a { width: 50px; } #searchresults_table td#albumname { - min-width: 200px; + min-width: 250px; text-align: left; vertical-align: middle; + font-size: 14px; } #searchresults_table td#artistname { min-width: 300px; text-align: left; vertical-align: middle; } +#searchresults_table td#artistnamesmall { + min-width: 100px; + text-align: left; + vertical-align: middle; + font-size: 14px; +} +#searchresults_table td#reldate { + min-width: 80px; + text-align: center; + vertical-align: middle; + font-size: 14px; +} +#searchresults_table td#format { + min-width: 50px; + text-align: left; + vertical-align: middle; + font-size: 14px; +} +#searchresults_table td#tracks { + min-width: 50px; + text-align: left; + vertical-align: middle; + font-size: 12px; +} #searchresults_table td#add { vertical-align: middle; } @@ -1416,6 +1462,11 @@ div#artistheader h3 span { min-width: 75px; text-align: center; } +#searchresults_table th#scoresmall { + min-width: 50px; + text-align: center; + font-size: 14px; +} #track_table td#bitrate, #track_table td#format { font-size: 12px; diff --git a/data/interfaces/default/images/MusicBrainz_Album_Icon.png b/data/interfaces/default/images/MusicBrainz_Album_Icon.png new file mode 100644 index 00000000..16abf29b Binary files /dev/null and b/data/interfaces/default/images/MusicBrainz_Album_Icon.png differ diff --git a/data/interfaces/default/images/MusicBrainz_Artist_Icon.png b/data/interfaces/default/images/MusicBrainz_Artist_Icon.png new file mode 100644 index 00000000..82e3381d Binary files /dev/null and b/data/interfaces/default/images/MusicBrainz_Artist_Icon.png differ diff --git a/data/interfaces/default/searchresults.html b/data/interfaces/default/searchresults.html index b6083c51..752e0424 100644 --- a/data/interfaces/default/searchresults.html +++ b/data/interfaces/default/searchresults.html @@ -11,36 +11,49 @@ %if type == 'album': Album Name + Artist Name + Format + Tracks + Date + Score + %else: + Artist Name + Score %endif - Artist Name - Score - + %if searchresults: - %for result in searchresults: - <% - if result['score'] == 100: - grade = 'A' - else: - grade = 'Z' - %> + %for result in searchresults: + <% + if result['score'] == 100: + grade = 'A' + else: + grade = 'Z' + + if type == 'album': + albuminfo = 'Type: ' + result['rgtype'] + ', Country: ' + result['country'] + caa_group_url = "http://coverartarchive.org/release-group/%s/front-250.jpg" %result['rgid'] + %> %if type == 'album': -
+
%else:
%endif %if type == 'album': - ${result['title']} - %endif - ${result['uniquename']} -
${result['score']}
- %if type == 'album': - Add this album - %else: - View on MusicBrainz + ${result['title']} + ${result['uniquename']} + ${result['formats']} + ${result['tracks']} + ${result['date']} +
${result['score']}
+ + %else: + ${result['uniquename']} +
${result['score']}
+ %endif %endfor @@ -75,7 +88,7 @@ { "bDestroy": true, "aoColumnDefs": [ - { 'bSortable': false, 'aTargets': [ 0,3 ] } + { 'bSortable': false, 'aTargets': [ 0 ] } ], "oLanguage": { "sLengthMenu":"Show _MENU_ results per page", diff --git a/headphones/cache.py b/headphones/cache.py index a762fd20..4eba6034 100644 --- a/headphones/cache.py +++ b/headphones/cache.py @@ -233,15 +233,15 @@ class Cache(object): return try: - image_url = data['artist']['image'][-1]['#text'] + image_url = data['album']['image'][-1]['#text'] except Exception: - logger.debug('No artist image found') + logger.debug('No album image found on last.fm') image_url = None thumb_url = self._get_thumb_url(data) if not thumb_url: - logger.debug('No artist thumbnail image found') + logger.debug('No album thumbnail image found on last.fm') return {'artwork' : image_url, 'thumbnail' : thumb_url } diff --git a/headphones/importer.py b/headphones/importer.py index c0e96310..36eecaf5 100644 --- a/headphones/importer.py +++ b/headphones/importer.py @@ -528,10 +528,23 @@ def finalize_update(artistid, artistname, errors=False): myDB.upsert("artists", newValueDict, controlValueDict) -def addReleaseById(rid): +def addReleaseById(rid, rgid=None): myDB = db.DBConnection() + # Create minimum info upfront if added from searchresults + status = '' + if rgid: + dbalbum = myDB.select("SELECT * from albums WHERE AlbumID=?", [rgid]) + if not dbalbum: + status = 'Loading' + controlValueDict = {"AlbumID": rgid} + newValueDict = {"AlbumTitle": rgid, + "ArtistName": status, + "Status": status} + myDB.upsert("albums", newValueDict, controlValueDict) + time.sleep(1) + rgid = None artistid = None release_dict = None @@ -547,9 +560,13 @@ def addReleaseById(rid): release_dict = mb.getRelease(rid) except Exception, e: logger.info('Unable to get release information for Release %s: %s', rid, e) + if status == 'Loading': + myDB.action("DELETE FROM albums WHERE AlbumID=?", [rgid]) return if not release_dict: logger.info('Unable to get release information for Release %s: no dict', rid) + if status == 'Loading': + myDB.action("DELETE FROM albums WHERE AlbumID=?", [rgid]) return rgid = release_dict['rgid'] @@ -567,7 +584,6 @@ def addReleaseById(rid): else: sortname = release_dict['artist_name'] - logger.info(u"Now manually adding: " + release_dict['artist_name'] + " - with status Paused") controlValueDict = {"ArtistID": release_dict['artist_id']} newValueDict = {"ArtistName": release_dict['artist_name'], @@ -583,12 +599,16 @@ def addReleaseById(rid): elif not artist_exists and not release_dict: logger.error("Artist does not exist in the database and did not get a valid response from MB. Skipping release.") + if status == 'Loading': + myDB.action("DELETE FROM albums WHERE AlbumID=?", [rgid]) return - if not rg_exists and release_dict: #it should never be the case that we have an rg and not the artist - #but if it is this will fail + if not rg_exists and release_dict or status == 'Loading' and release_dict: #it should never be the case that we have an rg and not the artist + #but if it is this will fail logger.info(u"Now adding-by-id album (" + release_dict['title'] + ") from id: " + rgid) controlValueDict = {"AlbumID": rgid} + if status != 'Loading': + status = 'Wanted' newValueDict = {"ArtistID": release_dict['artist_id'], "ReleaseID": rgid, @@ -597,8 +617,9 @@ def addReleaseById(rid): "AlbumASIN": release_dict['asin'], "ReleaseDate": release_dict['date'], "DateAdded": helpers.today(), - "Status": 'Wanted', - "Type": release_dict['rg_type'] + "Status": status, + "Type": release_dict['rg_type'], + "ReleaseID": rid } myDB.upsert("albums", newValueDict, controlValueDict) @@ -638,11 +659,19 @@ def addReleaseById(rid): myDB.upsert("tracks", newValueDict, controlValueDict) + # Reset status + if status == 'Loading': + controlValueDict = {"AlbumID": rgid} + newValueDict = {"Status": "Wanted"} + myDB.upsert("albums", newValueDict, controlValueDict) + #start a search for the album import searcher searcher.searchforalbum(rgid, False) elif not rg_exists and not release_dict: logger.error("ReleaseGroup does not exist in the database and did not get a valid response from MB. Skipping release.") + if status == 'Loading': + myDB.action("DELETE FROM albums WHERE AlbumID=?", [rgid]) return else: logger.info('Release ' + str(rid) + " already exists in the database!") diff --git a/headphones/mb.py b/headphones/mb.py index d9cc96e6..80467e5f 100644 --- a/headphones/mb.py +++ b/headphones/mb.py @@ -23,6 +23,8 @@ from headphones.helpers import multikeysort, replace_all import lib.musicbrainzngs as musicbrainzngs from lib.musicbrainzngs import WebServiceError +from lib.simplejson import OrderedDict + mb_lock = threading.Lock() @@ -117,7 +119,7 @@ def findArtist(name, limit=1): }) return artistlist -def findRelease(name, limit=1): +def findRelease(name, limit=1, artist=None): with mb_lock: releaselist = [] @@ -126,25 +128,62 @@ def findRelease(name, limit=1): chars = set('!?') if any((c in chars) for c in name): name = '"'+name+'"' - + + # additional artist search + if not artist and ':' in name: + name, artist = name.rsplit(":",1) + try: - releaseResults = musicbrainzngs.search_releases(query=name,limit=limit)['release-list'] + releaseResults = musicbrainzngs.search_releases(query=name,limit=limit,artist=artist)['release-list'] except WebServiceError, e: #need to update exceptions logger.warn('Attempt to query MusicBrainz for "%s" failed: %s' % (name, str(e))) time.sleep(5) if not releaseResults: return False + for result in releaseResults: - releaselist.append({ + + title = result['title'] + if 'disambiguation' in result: + title += ' (' + result['disambiguation'] + ')' + + # Get formats and track counts + format_dict = OrderedDict() + formats = '' + tracks = '' + for medium in result['medium-list']: + if 'format' in medium: + format = medium['format'] + if format not in format_dict: + format_dict[format] = 0 + format_dict[format] += 1 + if 'track-count' in medium: + if tracks: + tracks += ' + ' + tracks += str(medium['track-count']) + for format, count in format_dict.items(): + if formats: + formats += ' + ' + if count > 1: + formats += str(count) + 'x' + formats += format + + releaselist.append({ 'uniquename': unicode(result['artist-credit'][0]['artist']['name']), - 'title': unicode(result['title']), + 'title': unicode(title), 'id': unicode(result['artist-credit'][0]['artist']['id']), 'albumid': unicode(result['id']), 'url': unicode("http://musicbrainz.org/artist/" + result['artist-credit'][0]['artist']['id']),#probably needs to be changed 'albumurl': unicode("http://musicbrainz.org/release/" + result['id']),#probably needs to be changed - 'score': int(result['ext:score']) - }) + 'score': int(result['ext:score']), + 'date': unicode(result['date']) if 'date' in result else '', + 'country': unicode(result['country']) if 'country' in result else '', + 'formats': unicode(formats), + 'tracks': unicode(tracks), + 'rgid': unicode(result['release-group']['id']), + 'rgtype': unicode(result['release-group']['type']) if 'type' in result['release-group'] else '' + }) return releaselist def getArtist(artistid, extrasonly=False): diff --git a/headphones/searcher.py b/headphones/searcher.py index 875d984a..7cf0f9bc 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -94,22 +94,24 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False): TORRENT_PROVIDERS = (headphones.KAT or headphones.PIRATEBAY or headphones.ISOHUNT or headphones.MININOVA or headphones.WAFFLES or headphones.RUTRACKER or headphones.WHATCD) results = [] + myDB = db.DBConnection() + albumlength = myDB.select('SELECT sum(TrackDuration) from tracks WHERE AlbumID=?', [album['AlbumID']])[0][0] if headphones.PREFER_TORRENTS == 0: if NZB_PROVIDERS and NZB_DOWNLOADERS: - results = searchNZB(album, new, losslessOnly) + results = searchNZB(album, new, losslessOnly, albumlength) if not results and TORRENT_PROVIDERS: - results = searchTorrent(album, new, losslessOnly) + results = searchTorrent(album, new, losslessOnly, albumlength) elif headphones.PREFER_TORRENTS == 1: if TORRENT_PROVIDERS: - results = searchTorrent(album, new, losslessOnly) + results = searchTorrent(album, new, losslessOnly, albumlength) if not results and NZB_PROVIDERS and NZB_DOWNLOADERS: - results = searchNZB(album, new, losslessOnly) + results = searchNZB(album, new, losslessOnly, albumlength) else: @@ -117,10 +119,10 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False): torrent_results = None if NZB_PROVIDERS and NZB_DOWNLOADERS: - nzb_results = searchNZB(album, new, losslessOnly) + nzb_results = searchNZB(album, new, losslessOnly, albumlength) if TORRENT_PROVIDERS: - torrent_results = searchTorrent(album, new, losslessOnly) + torrent_results = searchTorrent(album, new, losslessOnly, albumlength) if not nzb_results: nzb_results = [] @@ -134,7 +136,7 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False): if choose_specific_download: return results - sorted_search_results = sort_search_results(results, album, new) + sorted_search_results = sort_search_results(results, album, new, albumlength) if not sorted_search_results: return @@ -145,10 +147,69 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False): if data and bestqual: send_to_downloader(data, bestqual, album) -def sort_search_results(resultlist, album, new): +def more_filtering(results, album, albumlength, new): + low_size_limit = None + high_size_limit = None + allow_lossless = False myDB = db.DBConnection() + # Lossless - ignore results if target size outside bitrate range + if headphones.PREFERRED_QUALITY == 3 and albumlength and (headphones.LOSSLESS_BITRATE_FROM or headphones.LOSSLESS_BITRATE_TO): + if headphones.LOSSLESS_BITRATE_FROM: + low_size_limit = albumlength/1000 * int(headphones.LOSSLESS_BITRATE_FROM) * 128 + if headphones.LOSSLESS_BITRATE_TO: + high_size_limit = albumlength/1000 * int(headphones.LOSSLESS_BITRATE_TO) * 128 + + # Preferred Bitrate - ignore results if target size outside % buffer + elif headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE: + logger.debug('Target bitrate: %s kbps' % headphones.PREFERRED_BITRATE) + if albumlength: + targetsize = albumlength/1000 * int(headphones.PREFERRED_BITRATE) * 128 + logger.info('Target size: %s' % helpers.bytes_to_mb(targetsize)) + if headphones.PREFERRED_BITRATE_LOW_BUFFER: + low_size_limit = targetsize - (targetsize * int(headphones.PREFERRED_BITRATE_LOW_BUFFER)/100) + if headphones.PREFERRED_BITRATE_HIGH_BUFFER: + high_size_limit = targetsize + (targetsize * int(headphones.PREFERRED_BITRATE_HIGH_BUFFER)/100) + if headphones.PREFERRED_BITRATE_ALLOW_LOSSLESS: + allow_lossless = True + + if low_size_limit or high_size_limit or new: + + newlist = [] + + for result in results: + + if low_size_limit and (int(result[1]) < low_size_limit): + logger.info("%s from %s is too small for this album - not considering it. (Size: %s, Minsize: %s)", result[0], result[3], helpers.bytes_to_mb(result[1]), helpers.bytes_to_mb(low_size_limit)) + continue + + if high_size_limit and (int(result[1]) > high_size_limit): + logger.info("%s from %s is too large for this album - not considering it. (Size: %s, Maxsize: %s)", result[0], result[3], helpers.bytes_to_mb(result[1]), helpers.bytes_to_mb(high_size_limit)) + + # Keep lossless results if there are no good lossy matches + if not (allow_lossless and 'flac' in result[0].lower()): + continue + + if new: + alreadydownloaded = myDB.select('SELECT * from snatched WHERE URL=?', [result[2]]) + + if len(alreadydownloaded): + logger.info('%s has already been downloaded from %s. Skipping.' % (result[0], result[3])) + continue + + newlist.append(result) + + results = newlist + + return results + +def sort_search_results(resultlist, album, new, albumlength): + + if new and not len(resultlist): + logger.info('No more results found for: %s - %s' % (album['ArtistName'], album['AlbumTitle'])) + return None + # Add a priority if it has any of the preferred words temp_list = [] preferred_words = None @@ -170,13 +231,7 @@ def sort_search_results(resultlist, album, new): if headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE: - logger.debug('Target bitrate: %s kbps' % headphones.PREFERRED_BITRATE) - - tracks = myDB.select('SELECT TrackDuration from tracks WHERE AlbumID=?', [album['AlbumID']]) - try: - albumlength = sum([pair[0] for pair in tracks]) - targetsize = albumlength/1000 * int(headphones.PREFERRED_BITRATE) * 128 if not targetsize: @@ -184,33 +239,14 @@ def sort_search_results(resultlist, album, new): finallist = sorted(resultlist, key=lambda title: (title[5], int(title[1])), reverse=True) 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 - else: - high_size_limit = None - if headphones.PREFERRED_BITRATE_LOW_BUFFER: - low_size_limit = targetsize * int(headphones.PREFERRED_BITRATE_LOW_BUFFER)/100 - else: - low_size_limit = None - for result in resultlist: - if high_size_limit and (int(result[1]) > high_size_limit): - - logger.info("%s is too large for this album - not considering it. (Size: %s, Maxsize: %s)", result[0], helpers.bytes_to_mb(result[1]), 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], result[5])) - - continue - - if low_size_limit and (int(result[1]) < low_size_limit): - logger.info("%s is too small for this album - not considering it. (Size: %s, Minsize: %s)", result[0], helpers.bytes_to_mb(result[1]), helpers.bytes_to_mb(low_size_limit)) + # Add lossless results 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], result[5])) continue delta = abs(targetsize - int(result[1])) @@ -227,56 +263,10 @@ def sort_search_results(resultlist, album, new): finallist = sorted(resultlist, key=lambda title: (title[5], int(title[1])), reverse=True) - # lossless - ignore results if target size outside bitrate range - elif headphones.PREFERRED_QUALITY == 3 and (headphones.LOSSLESS_BITRATE_FROM or headphones.LOSSLESS_BITRATE_TO): - - finallist = [] - tracks = myDB.select('SELECT TrackDuration from tracks WHERE AlbumID=?', [album['AlbumID']]) - - if len(tracks): - - albumlength = sum([pair[0] for pair in tracks]) - mintargetsize = 0 - maxtargetsize = 0 - if headphones.LOSSLESS_BITRATE_FROM: - mintargetsize = albumlength/1000 * int(headphones.LOSSLESS_BITRATE_FROM) * 128 - if headphones.LOSSLESS_BITRATE_TO: - maxtargetsize = albumlength/1000 * int(headphones.LOSSLESS_BITRATE_TO) * 128 - - if mintargetsize > 0 or maxtargetsize > 0: - for i, result in reversed(list(enumerate(resultlist))): - if int(result[1]) < mintargetsize and mintargetsize > 0 or int(result[1]) > maxtargetsize and maxtargetsize > 0: - if int(result[1]) < mintargetsize: - logger.info("%s is too small for this album - not considering it. (Size: %s, Minsize: %s)", result[0], helpers.bytes_to_mb(result[1]), helpers.bytes_to_mb(mintargetsize)) - else: - logger.info("%s is too large for this album - not considering it. (Size: %s, Maxsize: %s)", result[0], helpers.bytes_to_mb(result[1]), helpers.bytes_to_mb(maxtargetsize)) - del resultlist[i] - - if len (resultlist): - finallist = sorted(resultlist, key=lambda title: (title[5], int(title[1])), reverse=True) - else: finallist = sorted(resultlist, key=lambda title: (title[5], int(title[1])), reverse=True) - if new: - - while True: - - if len(finallist): - - alreadydownloaded = myDB.select('SELECT * from snatched WHERE URL=?', [finallist[0][2]]) - - if len(alreadydownloaded): - logger.info('%s has already been downloaded. Skipping.' % finallist[0][0]) - finallist.pop(0) - - else: - break - else: - logger.info('No more results found for: %s - %s' % (album['ArtistName'], album['AlbumTitle'])) - return None - if not len(finallist): logger.info('No appropriate matches found for %s - %s', album['ArtistName'], album['AlbumTitle']) return None @@ -292,7 +282,7 @@ def get_year_from_release_date(release_date): return year -def searchNZB(album, new=False, losslessOnly=False): +def searchNZB(album, new=False, losslessOnly=False, albumlength=None): albumid = album['AlbumID'] reldate = album['ReleaseDate'] @@ -322,6 +312,12 @@ def searchNZB(album, new=False, losslessOnly=False): term = re.sub('[\.\-\/]', ' ', term).encode('utf-8') artistterm = re.sub('[\.\-\/]', ' ', cleanartist).encode('utf-8') + # If Preferred Bitrate and High Limit and Allow Lossless then get both lossy and lossless + if headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE and headphones.PREFERRED_BITRATE_HIGH_BUFFER and headphones.PREFERRED_BITRATE_ALLOW_LOSSLESS: + allow_lossless = True + else: + allow_lossless = False + logger.debug("Using search term: %s" % term) resultlist = [] @@ -331,7 +327,7 @@ def searchNZB(album, new=False, losslessOnly=False): if headphones.PREFERRED_QUALITY == 3 or losslessOnly: categories = "3040" - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: categories = "3040,3010" else: categories = "3010" @@ -389,7 +385,7 @@ def searchNZB(album, new=False, losslessOnly=False): if headphones.PREFERRED_QUALITY == 3 or losslessOnly: categories = "3040" - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: categories = "3040,3010" else: categories = "3010" @@ -451,7 +447,7 @@ def searchNZB(album, new=False, losslessOnly=False): provider = "nzbsorg" if headphones.PREFERRED_QUALITY == 3 or losslessOnly: categories = "3040" - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: categories = "3040,3010" else: categories = "3010" @@ -500,7 +496,7 @@ def searchNZB(album, new=False, losslessOnly=False): if headphones.PREFERRED_QUALITY == 3 or losslessOnly: sub = "16" - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY ==1 or allow_lossless: sub = "" else: sub = "15" @@ -551,7 +547,7 @@ def searchNZB(album, new=False, losslessOnly=False): if headphones.PREFERRED_QUALITY == 3 or losslessOnly: categories = "22" - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: categories = "22,7" else: categories = "7" @@ -599,7 +595,13 @@ def searchNZB(album, new=False, losslessOnly=False): # # Also will filter flac & remix albums if not specifically looking for it # This code also checks the ignored words and required words - return [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)] + results = [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)] + + # Additional filtering for size etc + if results: + results = more_filtering(results, album, albumlength, new) + + return results def send_to_downloader(data, bestqual, album): @@ -921,7 +923,7 @@ def getresultNZB(result): return nzb -def searchTorrent(album, new=False, losslessOnly=False): +def searchTorrent(album, new=False, losslessOnly=False, albumlength=None): global gazelle # persistent what.cd api object to reduce number of login attempts # rutracker login @@ -973,6 +975,12 @@ def searchTorrent(album, new=False, losslessOnly=False): artistterm = re.sub('[\.\-\/]', ' ', cleanartist).encode('utf-8', 'replace') albumterm = re.sub('[\.\-\/]', ' ', cleanalbum).encode('utf-8', 'replace') + # If Preferred Bitrate and High Limit and Allow Lossless then get both lossy and lossless + if headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE and headphones.PREFERRED_BITRATE_HIGH_BUFFER and headphones.PREFERRED_BITRATE_ALLOW_LOSSLESS: + allow_lossless = True + else: + allow_lossless = False + logger.debug("Using search term: %s" % term) resultlist = [] @@ -986,7 +994,7 @@ def searchTorrent(album, new=False, losslessOnly=False): categories = "7" #music format = "2" #flac maxsize = 10000000000 - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: categories = "7" #music format = "10" #mp3+flac maxsize = 10000000000 @@ -1044,7 +1052,7 @@ def searchTorrent(album, new=False, losslessOnly=False): format = "FLAC" bitrate = "(Lossless)" maxsize = 10000000000 - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: format = "FLAC OR MP3" maxsize = 10000000000 else: @@ -1101,33 +1109,26 @@ def searchTorrent(album, new=False, losslessOnly=False): logger.error(u"An error occurred while trying to parse the response from Waffles.fm: %s" % e) # rutracker.org - if headphones.RUTRACKER and rulogin: provider = "rutracker.org" # Ignore if release date not specified, results too unpredictable - if not year and not usersearchterm: logger.info(u'Release date not specified, ignoring for rutracker.org') else: - bitrate = False - if headphones.PREFERRED_QUALITY == 3 or losslessOnly: format = 'lossless' maxsize = 10000000000 - elif headphones.PREFERRED_QUALITY == 1: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: format = 'lossless+mp3' maxsize = 10000000000 else: format = 'mp3' maxsize = 300000000 - if headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE: - bitrate = True # build search url based on above - if not usersearchterm: searchURL = rutracker.searchurl(artistterm, albumterm, year, format) else: @@ -1136,11 +1137,9 @@ def searchTorrent(album, new=False, losslessOnly=False): logger.info(u'Parsing results from rutracker.org' % searchURL) # parse results and get best match - - rulist = rutracker.search(searchURL, maxsize, minimumseeders, albumid, bitrate) + rulist = rutracker.search(searchURL, maxsize, minimumseeders, albumid) # add best match to overall results list - if rulist: for ru in rulist: title = ru[0].decode('utf-8') @@ -1171,7 +1170,7 @@ def searchTorrent(album, new=False, losslessOnly=False): if bitrate_string not in gazelleencoding.ALL_ENCODINGS: logger.info(u"Your preferred bitrate is not one of the available What.cd filters, so not using it as a search parameter.") maxsize = 10000000000 - elif headphones.PREFERRED_QUALITY == 1: # Highest quality including lossless + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: # Highest quality including lossless search_formats = [gazelleformat.FLAC, gazelleformat.MP3] maxsize = 10000000000 else: # Highest quality excluding lossless @@ -1250,7 +1249,7 @@ def searchTorrent(album, new=False, losslessOnly=False): if headphones.PREFERRED_QUALITY == 3 or losslessOnly: category = '104' #flac maxsize = 10000000000 - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: category = '100' #audio cat maxsize = 10000000000 else: @@ -1317,7 +1316,7 @@ def searchTorrent(album, new=False, losslessOnly=False): categories = "7" #music format = "2" #flac maxsize = 10000000000 - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: categories = "7" #music format = "10" #mp3+flac maxsize = 10000000000 @@ -1383,7 +1382,7 @@ def searchTorrent(album, new=False, losslessOnly=False): categories = "7" #music format = "2" #flac maxsize = 10000000000 - elif headphones.PREFERRED_QUALITY: + elif headphones.PREFERRED_QUALITY == 1 or allow_lossless: categories = "7" #music format = "10" #mp3+flac maxsize = 10000000000 @@ -1433,7 +1432,13 @@ def searchTorrent(album, new=False, losslessOnly=False): #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 - return [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)] + results = [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)] + + # Additional filtering for size etc + if results: + results = more_filtering(results, album, albumlength, new) + + return results # THIS IS KIND OF A MESS AND PROBABLY NEEDS TO BE CLEANED UP def preprocess(resultlist): diff --git a/headphones/searcher_rutracker.py b/headphones/searcher_rutracker.py index 3c799f24..dffb638b 100644 --- a/headphones/searcher_rutracker.py +++ b/headphones/searcher_rutracker.py @@ -88,7 +88,7 @@ class Rutracker(): return searchurl - def search(self, searchurl, maxsize, minseeders, albumid, bitrate): + def search(self, searchurl, maxsize, minseeders, albumid): """ Parse the search results and return valid torrent list """ diff --git a/headphones/webserve.py b/headphones/webserve.py index 3a7c6f16..d8c74942 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -110,6 +110,19 @@ class WebInterface(object): album = myDB.action('SELECT * from albums WHERE AlbumID=?', [AlbumID]).fetchone() tracks = myDB.select('SELECT * from tracks WHERE AlbumID=? ORDER BY CAST(TrackNumber AS INTEGER)', [AlbumID]) description = myDB.action('SELECT * from descriptions WHERE ReleaseGroupID=?', [AlbumID]).fetchone() + + retry = 0 + while retry < 5: + if not album: + time.sleep(1) + album = myDB.action('SELECT * from albums WHERE AlbumID=?', [AlbumID]).fetchone() + retry += 1 + else: + break + + if not album: + raise cherrypy.HTTPRedirect("home") + if not album['ArtistName']: title = ' - ' else: @@ -872,6 +885,17 @@ class WebInterface(object): return artist_json getArtistjson.exposed=True + def getAlbumjson(self, AlbumID, **kwargs): + myDB = db.DBConnection() + album = myDB.action('SELECT * from albums WHERE AlbumID=?', [AlbumID]).fetchone() + album_json = json.dumps({ + 'AlbumTitle': album['AlbumTitle'], + 'ArtistName': album['ArtistName'], + 'Status': album['Status'] + }) + return album_json + getAlbumjson.exposed=True + def clearhistory(self, type=None, date_added=None, title=None): myDB = db.DBConnection() if type: @@ -1403,9 +1427,12 @@ class WebInterface(object): return page extras.exposed = True - def addReleaseById(self, rid): - threading.Thread(target=importer.addReleaseById, args=[rid]).start() - raise cherrypy.HTTPRedirect("home") + def addReleaseById(self, rid, rgid=None): + threading.Thread(target=importer.addReleaseById, args=[rid, rgid]).start() + if rgid: + raise cherrypy.HTTPRedirect("albumPage?AlbumID=%s" % rgid) + else: + raise cherrypy.HTTPRedirect("home") addReleaseById.exposed = True def updateCloud(self): @@ -1458,6 +1485,17 @@ class WebInterface(object): from headphones import cache image_dict = cache.getImageLinks(ArtistID, AlbumID) + # Return the Cover Art Archive urls if not found on last.fm + if AlbumID and not image_dict: + image_url = "http://coverartarchive.org/release/%s/front-500.jpg" % AlbumID + thumb_url = "http://coverartarchive.org/release/%s/front-250.jpg" % AlbumID + image_dict = {'artwork' : image_url, 'thumbnail' : thumb_url} + elif AlbumID and (not image_dict['artwork'] or not image_dict['thumbnail']): + if not image_dict['artwork']: + image_dict['artwork'] = "http://coverartarchive.org/release/%s/front-500.jpg" % AlbumID + if not image_dict['thumbnail']: + image_dict['thumbnail'] = "http://coverartarchive.org/release/%s/front-250.jpg" % AlbumID + return simplejson.dumps(image_dict) getImageLinks.exposed = True