mirror of
https://github.com/rembo10/headphones.git
synced 2026-01-12 07:48:16 -05:00
Changed all Using href="#" to href="javascript:void(0)". Using "#" causes the browser to jump to the top of the page when the hyperlink is clicked (default empty # anchor position). Using "javascript:void(0)" will not change the browser's scroll position.
329 lines
13 KiB
HTML
329 lines
13 KiB
HTML
<%inherit file="base.html"/>
|
|
<%!
|
|
from headphones import db
|
|
import headphones
|
|
import string
|
|
%>
|
|
|
|
<%def name="headerIncludes()">
|
|
<div id="subhead_container">
|
|
<div id="subhead_menu">
|
|
<a id="menu_link_refresh" onclick="doSimpleAjaxCall('refreshArtist?ArtistID=${artist['ArtistID']}')" href="javascript:void(0)"><i class="fa fa-refresh"></i> Refresh Artist</a>
|
|
<a id="menu_link_delete" href="deleteArtist?ArtistID=${artist['ArtistID']}"><i class="fa fa-trash-o"></i> Delete Artist</a>
|
|
<a id="menu_link_scan" onclick="doAjaxCall('scanArtist?ArtistID=${artist['ArtistID']}', $(this)),'table'" href="javascript:void(0)" data-success="'${artist['ArtistName']}' was scanned"><i class="fa fa-refresh"></i> Scan Artist</a>
|
|
%if artist['Status'] == 'Paused':
|
|
<a id="menu_link_resume" href="javascript:void(0)" onclick="doAjaxCall('resumeArtist?ArtistID=${artist['ArtistID']}',$(this),true)" data-success="${artist['ArtistName']} resumed"><i class="fa fa-play"></i> Resume Artist</a>
|
|
%else:
|
|
<a id="menu_link_pauze" href="javascript:void(0)" onclick="doAjaxCall('pauseArtist?ArtistID=${artist['ArtistID']}',$(this),true)" data-success="${artist['ArtistName']} paused"><i class="fa fa-pause"></i> Pause Artist</a>
|
|
%endif
|
|
%if artist['IncludeExtras']:
|
|
<a id="menu_link_removeextra" href="javascript:void(0)" onclick="doAjaxCall('removeExtras?ArtistID=${artist['ArtistID']}&ArtistName=${artist['ArtistName']}',$(this),'submenu&table')" data-success="Extras removed for ${artist['ArtistName']}"><i class="fa fa-minus"></i> Remove Extras</a>
|
|
<a class="menu_link_edit" id="menu_link_modifyextra" href="javascript:void(0)"><i class="fa fa-pencil"></i> Modify Extras</a>
|
|
%else:
|
|
<a id="menu_link_getextra" href="javascript:void(0)"><i class="fa fa-plus"></i> Get Extras</a>
|
|
%endif
|
|
<div id="dialog" title="Choose Which Extras to Fetch" style="display:none" class="configtable">
|
|
<form action="getExtras" method="get" class="form">
|
|
<input type="hidden" name="ArtistID" value="${artist['ArtistID']}">
|
|
<input type="hidden" name="newstyle" value="true">
|
|
%for extra in extras:
|
|
<input type="checkbox" id="${extra}" name="${extra}" value="1" ${extras[extra]} />${string.capwords(extra)}<br>
|
|
%endfor
|
|
<br>
|
|
<input id="submit" type="submit" value="Fetch Extras">
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<a href="home" class="back">« Back to overview</a>
|
|
</%def>
|
|
|
|
<%def name="body()">
|
|
<div id="artistheader" class="clearfix">
|
|
<div id="artistImg">
|
|
<img id="artistImage" class="albumArt" alt="" src="artwork/artist/${artist['ArtistID']}"/>
|
|
</div>
|
|
<h1 id="artistname">
|
|
<a href="http://musicbrainz.org/artist/${artist['ArtistID']}" id="artistnamelink">${artist['ArtistName']}</a>
|
|
</h1>
|
|
<div id="artistBio"></div>
|
|
</div>
|
|
<ul id="artistCalendar" style="display:none;"></ul>
|
|
<form action="markAlbums" method="get" id="markAlbums">
|
|
<input type="hidden" name="ArtistID" value=${artist['ArtistID']}>
|
|
<div id="markalbum">Mark selected albums as
|
|
<select name="action" onChange="doAjaxCall('markAlbums',$(this),'table',true);" data-error="You didn't select any albums">
|
|
<option disabled="disabled" selected="selected">Choose...</option>
|
|
<option value="Wanted">Wanted</option>
|
|
<option value="WantedNew">Wanted (new only)</option>
|
|
<option value="Skipped">Skipped</option>
|
|
<option value="Ignored">Ignored</option>
|
|
<option value="Downloaded">Downloaded</option>
|
|
</select>
|
|
<input type="hidden" value="Go">
|
|
</div>
|
|
<table class="display" id="album_table">
|
|
<thead>
|
|
<tr>
|
|
<th id="select"><input type="checkbox" onClick="toggle(this)" /></th>
|
|
<th id="albumart"></th>
|
|
<th id="albumname">Name</th>
|
|
<th id="reldate">Date</th>
|
|
<th id="type">Type</th>
|
|
<th id="score">Metacritic</th>
|
|
<th id="status">Status</th>
|
|
<th id="have">Have</th>
|
|
<th id="bitrate">Bitrate</th>
|
|
<th id="albumformat">Format</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
%for album in albums:
|
|
<%
|
|
if album['Status'] == 'Skipped':
|
|
grade = 'Z'
|
|
elif album['Status'] == 'Wanted':
|
|
grade = 'X'
|
|
elif album['Status'] == 'Snatched':
|
|
grade = 'C'
|
|
elif album['Status'] == 'Ignored':
|
|
grade = 'I'
|
|
else:
|
|
grade = 'A'
|
|
|
|
myDB = db.DBConnection()
|
|
totaltracks = len(myDB.select('SELECT TrackTitle from tracks WHERE AlbumID=?', [album['AlbumID']]))
|
|
havetracks = len(myDB.select('SELECT TrackTitle from tracks WHERE AlbumID=? AND Location IS NOT NULL', [album['AlbumID']])) + len(myDB.select('SELECT TrackTitle from have WHERE ArtistName like ? AND AlbumTitle LIKE ? AND Matched = "Failed"', [album['ArtistName'], album['AlbumTitle']]))
|
|
|
|
try:
|
|
percent = (havetracks*100.0)/totaltracks
|
|
if percent > 100:
|
|
percent = 100
|
|
except (ZeroDivisionError, TypeError):
|
|
percent = 0
|
|
totaltracks = '?'
|
|
|
|
avgbitrate = myDB.action("SELECT AVG(BitRate) FROM tracks WHERE AlbumID=?", [album['AlbumID']]).fetchone()[0]
|
|
if avgbitrate:
|
|
bitrate = str(int(avgbitrate)/1000) + ' kbps'
|
|
else:
|
|
bitrate = ''
|
|
|
|
albumformatcount = myDB.action("SELECT COUNT(DISTINCT Format) FROM tracks WHERE AlbumID=?", [album['AlbumID']]).fetchone()[0]
|
|
if albumformatcount == 1:
|
|
albumformat = myDB.action("SELECT DISTINCT Format FROM tracks WHERE AlbumID=?", [album['AlbumID']]).fetchone()[0]
|
|
elif albumformatcount > 1:
|
|
albumformat = 'Mixed'
|
|
else:
|
|
albumformat = ''
|
|
|
|
lossy_formats = [str.upper(fmt) for fmt in headphones.LOSSY_MEDIA_FORMATS]
|
|
|
|
%>
|
|
<tr class="grade${grade}">
|
|
<td id="select"><input type="checkbox" name="${album['AlbumID']}" class="checkbox" /></td>
|
|
<td id="albumart"><img class="albumArtnostretch" id="${album['AlbumID']}" src="artwork/thumbs/album/${album['AlbumID']}" height="64" width="64"></td>
|
|
<td id="albumname"><a href="albumPage?AlbumID=${album['AlbumID']}">${album['AlbumTitle']}</a></td>
|
|
<td id="reldate">${album['ReleaseDate']}</td>
|
|
<td id="type">${album['Type']}</td>
|
|
<td id="score">${album['CriticScore']}/${album['UserScore']}</td>
|
|
<td id="status">${album['Status']}
|
|
%if album['Status'] == 'Skipped' or album['Status'] == 'Ignored':
|
|
[<a href="javascript:void(0)" onclick="doAjaxCall('queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}',$(this),'table')" data-success="'${album['AlbumTitle']}' added to Wanted list">want</a>]
|
|
%elif (album['Status'] == 'Wanted' or album['Status'] == 'Wanted Lossless'):
|
|
[<a href="javascript:void(0)" onclick="doAjaxCall('unqueueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}',$(this),'table')" data-success="'${album['AlbumTitle']}' skipped">skip</a>] [<a href="javascript:void(0)" onclick="doAjaxCall('queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}', $(this),'table')" data-success="Trying to download'${album['AlbumTitle']}'" title="Search if available for download">search</a>]
|
|
%else:
|
|
[<a href="javascript:void(0)" onclick="doAjaxCall('queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}', $(this),'table')" data-success="Retrying the same version of '${album['AlbumTitle']}'" title="Retry the same download again">retry</a>][<a href="javascript:void(0)" onclick="doAjaxCall('queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&new=True', $(this),'table')" title="Try a new download, skipping all previously tried nzbs" data-success="Downloading new version for '${album['AlbumTitle']}'" data-success="Looking for a new version of '${album['AlbumTitle']}'">new</a>]
|
|
%endif
|
|
%if albumformat in lossy_formats and album['Status'] == 'Skipped':
|
|
[<a id="wantlossless" href="javascript:void(0)" onclick="doAjaxCall('queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&lossless=True', $(this),'table')" data-success="Lossless version of '${album['AlbumTitle']}' added to queue">want lossless</a>]
|
|
%elif albumformat in lossy_formats and (album['Status'] == 'Snatched' or album['Status'] == 'Downloaded'):
|
|
[<a id="wantlossless" href="javascript:void(0)" onclick="doAjaxCall('queueAlbum?AlbumID=${album['AlbumID']}&ArtistID=${album['ArtistID']}&lossless=True', $(this),'table')" data-success="Retrying the same lossless version of '${album['AlbumTitle']}'">retry lossless</a>]
|
|
%endif
|
|
</td>
|
|
<td id="have"><span title="${percent}"><span><div class="progress-container"><div style="width:${percent}%"><div class="havetracks">${havetracks}/${totaltracks}</div></div></div></td>
|
|
<td id="bitrate">${bitrate}</td>
|
|
<td id="albumformat">${albumformat}</td>
|
|
</tr>
|
|
%endfor
|
|
</tbody>
|
|
</table>
|
|
</form>
|
|
</%def>
|
|
|
|
<%def name="headIncludes()">
|
|
<link rel="stylesheet" href="interfaces/default/css/data_table.css">
|
|
</%def>
|
|
|
|
<%def name="javascriptIncludes()">
|
|
<script src="js/libs/jquery.dataTables.min.js"></script>
|
|
|
|
<script>
|
|
function getArtistBio() {
|
|
var id = "${artist['ArtistID']}";
|
|
var elem = $("#artistBio");
|
|
getInfo(elem,id,'artist');
|
|
}
|
|
|
|
<%
|
|
if headphones.CONFIG.SONGKICK_FILTER_ENABLED:
|
|
songkick_filter_enabled = "true"
|
|
else:
|
|
songkick_filter_enabled = "false"
|
|
|
|
if not headphones.CONFIG.SONGKICK_LOCATION:
|
|
songkick_location = "none"
|
|
else:
|
|
songkick_location = headphones.CONFIG.SONGKICK_LOCATION
|
|
|
|
if headphones.CONFIG.SONGKICK_ENABLED:
|
|
songkick_enabled = "true"
|
|
else:
|
|
songkick_enabled = "false"
|
|
|
|
%>
|
|
function getArtistsCalendar() {
|
|
var template, calendarDomNode;
|
|
|
|
calendarDomNode = $("#artistCalendar");
|
|
|
|
template = '<li><a target="_blank" href="URI"><span class="sk-name">NAME</span><span class="sk-location">LOC</span></a></li>';
|
|
|
|
$.getJSON("https://api.songkick.com/api/3.0/artists/mbid:${artist['ArtistID']}/calendar.json?apikey=${headphones.CONFIG.SONGKICK_APIKEY}&jsoncallback=?",
|
|
function(data){
|
|
if (data['resultsPage'].totalEntries >= 1) {
|
|
if (${songkick_filter_enabled}) {
|
|
data.resultsPage.results.event = $.grep(data.resultsPage.results.event, function(element,index){
|
|
return element.venue.metroArea.id == ${songkick_location};
|
|
});
|
|
}
|
|
|
|
if (data.resultsPage.results.event.length > 0) {
|
|
var tourDate;
|
|
|
|
calendarDomNode.show();
|
|
$("#artistImg").addClass('on-tour');
|
|
|
|
jQuery.each(data.resultsPage.results.event, function(i, event) {
|
|
tourDate = template;
|
|
tourDate = tourDate.replace('URI',event.uri);
|
|
tourDate = tourDate.replace('NAME',event.displayName);
|
|
tourDate = tourDate.replace('LOC',event.location.city);
|
|
|
|
calendarDomNode.append(tourDate);
|
|
});
|
|
|
|
calendarDomNode.append('<li><img src="interfaces/default/images/songkick.png" alt="concerts by songkick" class="sk-logo" /></li>');
|
|
|
|
$(function() {
|
|
$("#artistCalendar").each(function() {
|
|
$("li:gt(4)", this).hide(); /* :gt() is zero-indexed */
|
|
$("li:nth-child(5)", this).after("<br><li class='more'><a href='#'>More...</a></li>"); /* :nth-child() is one-indexed */
|
|
});
|
|
$("li.more").on("click", 'a', function() {
|
|
var li = $(this).parents("li:first");
|
|
li.parent().children().show();
|
|
li.remove();
|
|
return false;
|
|
});
|
|
});
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
var loadingMessage = false;
|
|
var spinner_active = false;
|
|
var loadingtext_active = false;
|
|
|
|
function checkArtistStatus() {
|
|
$.getJSON("getArtistjson?ArtistID=${artist['ArtistID']}", function(data) {
|
|
if (data['Status'] == "Loading"){
|
|
refreshTable();
|
|
$('#artistnamelink').text(data["ArtistName"]);
|
|
if (loadingMessage == false){
|
|
$("#ajaxMsg").after( "<div id='ajaxMsg2' class='ajaxMsg'></div>" );
|
|
showArtistMsg("Getting artist information");
|
|
loadingMessage = true;
|
|
}
|
|
if (spinner_active == false){
|
|
$('#artistname').prepend('<i class="fa fa-refresh fa-spin" id="artistnamespinner"></i>')
|
|
spinner_active = true;
|
|
}
|
|
if (loadingtext_active == false){
|
|
$('#artistname').append('<h3 id="loadingtext"><i>(Album information for this artist is currently being loaded)</i></h3>')
|
|
loadingtext_active = true;
|
|
}
|
|
}
|
|
else{
|
|
$('#artistnamespinner').remove()
|
|
$('#loadingtext').remove()
|
|
$('#ajaxMsg2').remove()
|
|
spinner_active = false
|
|
loadingtext_active = false
|
|
loadingMessage = false
|
|
}
|
|
});
|
|
}
|
|
|
|
function initThisPage() {
|
|
$('#menu_link_getextra').click(function(event) {
|
|
$('#dialog').dialog();
|
|
event.preventDefault();
|
|
});
|
|
$('#menu_link_modifyextra').click(function(event) {
|
|
$('#dialog').dialog();
|
|
event.preventDefault();
|
|
});
|
|
$('#album_table').dataTable({
|
|
"bDestroy": true,
|
|
"aoColumns": [
|
|
null,
|
|
null,
|
|
null,
|
|
{ "sType": "date" },
|
|
null,
|
|
null,
|
|
null,
|
|
{ "sType": "title-numeric"},
|
|
null,
|
|
null
|
|
],
|
|
"aoColumnDefs": [
|
|
{ 'bSortable': false, 'aTargets': [ 0,1 ] }
|
|
],
|
|
"bStateSave": true,
|
|
"oLanguage": {
|
|
"sLengthMenu":"Show _MENU_ albums per page",
|
|
"sEmptyTable": "No album information available",
|
|
"sInfo":"Showing _TOTAL_ albums",
|
|
"sInfoEmpty":"Showing 0 to 0 of 0 albums",
|
|
"sInfoFiltered":"(filtered from _MAX_ total albums)",
|
|
"sSearch": ""},
|
|
"bPaginate": false,
|
|
"aaSorting": [[4, 'asc'],[3,'desc']]
|
|
|
|
});
|
|
resetFilters("albums");
|
|
setTimeout(function(){
|
|
initFancybox();
|
|
},1500);
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
initActions();
|
|
initThisPage();
|
|
getArtistBio();
|
|
if( ${songkick_enabled} ){
|
|
getArtistsCalendar();
|
|
}
|
|
checkArtistStatus();
|
|
setInterval(function(){
|
|
checkArtistStatus();
|
|
}, 1500);
|
|
});
|
|
|
|
</script>
|
|
</%def>
|