Album Search Results Changes

- mb findRelease
get additional info incl Date, Formats, Tracks, Rgid etc, pass to
searchresults
added optional artist to findrelease, if searching by album can now
enter album:artist in the search bar, went for this for now as I didn’t
want to change the design too much but maybe in the future we could
have 2 boxes, artist album and then there’s no need for the dropdown
artist, album

- base
position at search box and persist selected option (uses local storage)
when refreshing, useful if entering multiple albums
increased the search box size a little

- searchresults
album results - new fields from mb, fall back to cover art archive rgid
url if last.fm not found (should get more results), musicbrainz album
icon link, pass mb rgid to addReleaseById to redirect to album page
artist results - musicbrainz artist icon

- importer
addreleaseById - added rgid param to create the album record upfront
with status Loading if from searchresults

- webserve
redirect to album page using rgid from searchresults

- album
spinner while album is loading
This commit is contained in:
Ade
2014-06-28 08:18:54 +12:00
parent 0fdc62c914
commit 66b9da36dd
10 changed files with 297 additions and 47 deletions

View File

@@ -89,9 +89,15 @@
<div id="albumImg">
<img height="200" alt="" class="albumArt" src="artwork/album/${album['AlbumID']}">
</div>
<h1><a href="http://musicbrainz.org/release-group/${album['AlbumID']}">${album['AlbumTitle']}</a></h1>
<h2><a href="http://musicbrainz.org/artist/${album['ArtistID']}">${album['ArtistName']}</a></h2>
<h1 id="albumname">
<a href="http://musicbrainz.org/release-group/${album['AlbumID']}" id="albumnamelink">${album['AlbumTitle']}</a>
</h1>
<h2 id="artistname">
<a href="http://musicbrainz.org/artist/${album['ArtistID']}" id="artistnamelink">${album['ArtistName']}</a>
</h2>
<%
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( "<div id='ajaxMsg2' class='ajaxMsg'></div>" );
showArtistMsg("Getting album information");
loadingMessage = true;
}
if (spinner_active == false){
$('#albumname').prepend('<i class="fa fa-refresh fa-spin" id="albumnamespinner"></i>')
spinner_active = true;
}
if (loadingtext_active == false){
$('#albumname').append('<h3 id="loadingtext"><i>(Album information is currently being loaded)</i></h3>')
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);
});
</script>

View File

@@ -58,7 +58,7 @@
<form action="search" method="get">
<input type="text" value="" placeholder="Search" onfocus="if(this.value==this.defaultValue) this.value='';" name="name" />
<i class='fa fa-search mini-icon'></i>
<select name="type">
<select name="type" id="search_type">
<option value="artist">Artist</option>
<option value="album">Album</option>
</select>
@@ -115,3 +115,25 @@
<%def name="javascriptIncludes()"></%def>
<%def name="headIncludes()"></%def>
<%def name="headerIncludes()"></%def>
<!--persist search type using local storage-->
<script type="text/javascript">
$(document).ready(function() {
$('form:first *:input[type!=hidden]:first').focus();
try{
var type = window.localStorage.getItem('search_type');
$("#search_type").val(type);
} catch(e) {
}
});
$('select[id=search_type]').change(function() {
var type = $(this).val()
try{
window.localStorage.setItem('search_type', type);
} catch(e) {
}
});
</script>

View File

@@ -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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -11,37 +11,51 @@
<th id="albumart"></th>
%if type == 'album':
<th id="albumname">Album Name</th>
<th id="artistnamesmall">Artist Name</th>
<th id="format">Format</th>
<th id="tracks">Tracks</th>
<th id="reldate">Date</th>
<th id="scoresmall">Score</th>
%else:
<th id="artistname">Artist Name</th>
<th id="score">Score</th>
%endif
<th id="artistname">Artist Name</th>
<th id="score">Score</th>
<th id="add"></th>
<th id="mb"></th>
</tr>
</thead>
<tbody>
%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']
%>
<tr class="grade${grade}">
%if type == 'album':
<td id="albumart"><div id="artistImg"><img title="${result['albumid']}" class="albumArt" height="50" width="50"></div></td>
<td id="albumart" style=" text-align: center; vertical-align: middle;"><div id="artistImg"><img title="${result['albumid']}" class="albumArt" height="50" width="50" onerror="this.src='${caa_group_url}'"></div></td>
%else:
<td id="albumart"><div id="artistImg"><img title="${result['id']}" class="albumArt" height="50" width="50"></div></td>
%endif
%if type == 'album':
<td id="albumname"><a href="${result['albumurl']}">${result['title']}</a></td>
%endif
<td id="artistname"><a href="${result['url']}" title="${result['uniquename']}">${result['uniquename']}</a></td>
<td id="score"><div class="bar"><div class="score" style="width: ${result['score']}px">${result['score']}</div></div></td>
%if type == 'album':
<td id="add"><a href="addReleaseById?rid=${result['albumid']}"><i class="fa fa-plus"></i> Add this album</a></td>
%else:
<td id="add"><a href="addArtist?artistid=${result['id']}"><i class="fa fa-plus"></i> Add this artist</a></td>
<td id="albumname"><a href="addReleaseById?rid=${result['albumid']}&rgid=${result['rgid']}" title="${albuminfo}">${result['title']}</a></td>
<td id="artistnamesmall"><a href="addArtist?artistid=${result['id']}" title="${result['uniquename']}">${result['uniquename']}</a></td>
<td id="format">${result['formats']}</td>
<td id="tracks">${result['tracks']}</td>
<td id="reldate">${result['date']}</td>
<td id="score"><a href="${result['albumurl']} "title="View on MusicBrainz"><div class="bar"><div class="score" style="width: ${result['score']}px">${result['score']}</div></div></a></td>
<td id="musicbrainz" style=" text-align: center; line-height: 0; vertical-align: middle;"><a href="${result['albumurl']}"><img src="interfaces/default/images/MusicBrainz_Album_Icon.png" title="View on MusicBrainz" height="20" width="20"></a></td>
%else:
<td id="artistname"><a href="addArtist?artistid=${result['id']}" title="${result['uniquename']}">${result['uniquename']}</a></td>
<td id="score"><a href="${result['url']} "title="View on MusicBrainz"><div class="bar"><div class="score" style="width: ${result['score']}px">${result['score']}</div></div></a></td>
<td id="musicbrainz" style=" text-align: center; line-height: 0; vertical-align: middle;"><a href="${result['url']}"><img src="interfaces/default/images/MusicBrainz_Artist_Icon.png" title="View on MusicBrainz" height="20" width="20"></a></td>
%endif
</tr>
%endfor
%endif
@@ -75,7 +89,7 @@
{
"bDestroy": true,
"aoColumnDefs": [
{ 'bSortable': false, 'aTargets': [ 0,3 ] }
{ 'bSortable': false, 'aTargets': [ 0 ] }
],
"oLanguage": {
"sLengthMenu":"Show _MENU_ results per page",
@@ -91,7 +105,7 @@
resetFilters("album");
}
$(document).ready(function(){
initThisPage();
initThisPage();
});
$(window).load(function(){
initFancybox();

View File

@@ -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 }

View File

@@ -389,6 +389,8 @@ def addArtisttoDB(artistid, extrasonly=False, forcefull=False):
releaseid = rg['id']
else:
releaseid = rg_exists['ReleaseID']
if not releaseid:
releaseid = rg['id']
album = myDB.action('SELECT * from allalbums WHERE ReleaseID=?', [releaseid]).fetchone()
@@ -526,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
@@ -545,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']
@@ -565,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'],
@@ -581,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'],
"ArtistName": release_dict['artist_name'],
@@ -594,8 +616,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)
@@ -635,11 +658,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!")

View File

@@ -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):

View File

@@ -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:
@@ -864,6 +877,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:
@@ -1395,9 +1419,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):
@@ -1450,6 +1477,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