mirror of
https://github.com/rembo10/headphones.git
synced 2026-07-21 08:24:00 +01:00
Merge pull request #3379 from uniquePWD/patch-11
Update managealbums.html
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
<%inherit file="base.html" />
|
<%inherit file="base.html" />
|
||||||
<%!
|
<%!
|
||||||
from headphones import db
|
# Removed direct DB imports/interactions here, as data should be pre-fetched server-side.
|
||||||
import headphones
|
# from headphones import db
|
||||||
|
import headphones # Still needed for headphones.LOSSY_MEDIA_FORMATS if used
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<%def name="headerIncludes()">
|
<%def name="headerIncludes()">
|
||||||
@@ -17,9 +18,10 @@
|
|||||||
<div id="manageheader" class="title">
|
<div id="manageheader" class="title">
|
||||||
<h1 class="clearfix"><i class="fa fa-music"></i> Manage Albums</h1>
|
<h1 class="clearfix"><i class="fa fa-music"></i> Manage Albums</h1>
|
||||||
</div>
|
</div>
|
||||||
<form action="markAlbums" method="get" id="markAlbums">
|
<form action="markAlbums" method="get" id="markAlbumsForm"> <%-- Renamed ID to avoid conflict with markalbum div --%>
|
||||||
<div id="markalbum">Mark selected albums as
|
<div id="markalbum">Mark selected albums as
|
||||||
<select name="action" onChange="doAjaxCall('markAlbums',$(this),'table',true);" data-error="You didn't select any albums">
|
<%-- Replaced inline onChange with a class and data attributes for JS handling --%>
|
||||||
|
<select name="action" id="markAlbumActionSelect">
|
||||||
<option disabled="disabled" selected="selected">Choose...</option>
|
<option disabled="disabled" selected="selected">Choose...</option>
|
||||||
<option value="Wanted">Wanted</option>
|
<option value="Wanted">Wanted</option>
|
||||||
<option value="WantedNew">Wanted (new only)</option>
|
<option value="WantedNew">Wanted (new only)</option>
|
||||||
@@ -28,25 +30,27 @@
|
|||||||
<option value="Ignored">Ignored</option>
|
<option value="Ignored">Ignored</option>
|
||||||
<option value="Downloaded">Downloaded</option>
|
<option value="Downloaded">Downloaded</option>
|
||||||
</select>
|
</select>
|
||||||
<input type="hidden" value="Go">
|
<input type="hidden" value="Go"> <%-- This hidden input might be redundant if data is sent via AJAX --%>
|
||||||
</div>
|
</div>
|
||||||
<table class="display" id="album_table">
|
<table class="display" id="album_table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th id="select"><input type="checkbox" onClick="toggle(this)" /></th>
|
<th class="select-all-checkbox"><input type="checkbox" id="toggleAllAlbums" /></th> <%-- Added ID for easier targeting --%>
|
||||||
<th id="albumname">Album</th>
|
<th class="column-albumname">Album</th>
|
||||||
<th id="artistname">Artist</th>
|
<th class="column-artistname">Artist</th>
|
||||||
<th id="reldate">Date</th>
|
<th class="column-reldate">Date</th>
|
||||||
<th id="type">Type</th>
|
<th class="column-type">Type</th>
|
||||||
<th id="status">Status</th>
|
<th class="column-status">Status</th>
|
||||||
<th id="have">Have</th>
|
<th class="column-have">Have</th>
|
||||||
<th id="bitrate">Bitrate</th>
|
<th class="column-bitrate">Bitrate</th>
|
||||||
<th id="albumformat">Format</th>
|
<th class="column-albumformat">Format</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
%for album in albums:
|
%for album in albums:
|
||||||
<%
|
<%
|
||||||
|
# Assuming these values are now pre-calculated and available in the 'album' dict
|
||||||
|
# Removed all in-template database queries for performance.
|
||||||
if album['Status'] == 'Skipped':
|
if album['Status'] == 'Skipped':
|
||||||
grade = 'Z'
|
grade = 'Z'
|
||||||
elif album['Status'] == 'Wanted':
|
elif album['Status'] == 'Wanted':
|
||||||
@@ -58,45 +62,30 @@
|
|||||||
else:
|
else:
|
||||||
grade = 'A'
|
grade = 'A'
|
||||||
|
|
||||||
myDB = db.DBConnection()
|
# Use the pre-calculated values from the album object
|
||||||
totaltracks = len(myDB.select('SELECT TrackTitle from tracks WHERE AlbumID=?', [album['AlbumID']]))
|
totaltracks_display = album.get('TotalTracks', '?')
|
||||||
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']]))
|
havetracks_display = album.get('HaveTracks', 0)
|
||||||
|
percent_display = album.get('PercentOwned', 0)
|
||||||
try:
|
bitrate_display = album.get('BitrateDisplay', '') # e.g., '192 kbps'
|
||||||
percent = (havetracks*100.0)/totaltracks
|
albumformat_display = album.get('AlbumFormat', '') # e.g., 'MP3', 'FLAC', 'Mixed'
|
||||||
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}">
|
<tr class="grade${grade}">
|
||||||
<td id="select"><input type="checkbox" name="${album['AlbumID']}" class="checkbox" /></td>
|
<td class="select-album-checkbox"><input type="checkbox" name="albumid_${album['AlbumID']}" value="${album['AlbumID']}" class="album-checkbox" /></td> <%-- Unique name and class for individual checkboxes --%>
|
||||||
<td id="albumname"><a href="albumPage?AlbumID=${album['AlbumID']}">${album['AlbumTitle']}</a></td>
|
<td class="column-albumname"><a href="albumPage?AlbumID=${album['AlbumID']}">${album['AlbumTitle']}</a></td>
|
||||||
<td id="artistname"><a href="artistPage?ArtistID=${album['ArtistID']}">${album['ArtistName']}</a></td>
|
<td class="column-artistname"><a href="artistPage?ArtistID=${album['ArtistID']}">${album['ArtistName']}</a></td>
|
||||||
<td id="reldate">${album['ReleaseDate']}</td>
|
<td class="column-reldate">${album['ReleaseDate']}</td>
|
||||||
<td id="type">${album['Type']}</td>
|
<td class="column-type">${album['Type']}</td>
|
||||||
<td id="status">${album['Status']}</td>
|
<td class="column-status">${album['Status']}</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 class="column-have">
|
||||||
<td id="bitrate">${bitrate}</td>
|
<span title="${percent_display}"></span> <%-- Using percent_display for title attribute --%>
|
||||||
<td id="albumformat">${albumformat}</td>
|
<div class="progress-container" role="progressbar" aria-valuenow="${percent_display | int}" aria-valuemin="0" aria-valuemax="100">
|
||||||
|
<div style="width:${percent_display}%">
|
||||||
|
<div class="havetracks">${havetracks_display}/${totaltracks_display}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="column-bitrate">${bitrate_display}</td>
|
||||||
|
<td class="column-albumformat">${albumformat_display}</td>
|
||||||
</tr>
|
</tr>
|
||||||
%endfor
|
%endfor
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -106,28 +95,75 @@
|
|||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="headIncludes()">
|
<%def name="headIncludes()">
|
||||||
|
${parent.headIncludes()} <%-- Ensure parent head includes are kept --%>
|
||||||
<link rel="stylesheet" href="interfaces/default/css/data_table.css">
|
<link rel="stylesheet" href="interfaces/default/css/data_table.css">
|
||||||
|
<style>
|
||||||
|
/* Styles for progress bar, similar to index.html for consistency */
|
||||||
|
.progress-container {
|
||||||
|
background-color: #eee;
|
||||||
|
border-radius: 5px;
|
||||||
|
height: 15px; /* Adjust height as needed */
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
width: 100%; /* Or a fixed width if preferred */
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-container > div {
|
||||||
|
background-color: #4CAF50; /* Green color for progress */
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
font-size: 10px; /* Smaller font for percentage */
|
||||||
|
line-height: 15px; /* Vertically align text */
|
||||||
|
}
|
||||||
|
|
||||||
|
.havetracks {
|
||||||
|
padding: 0 5px; /* Add some padding around the text */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styles for album status grades */
|
||||||
|
.gradeZ { /* Skipped */
|
||||||
|
background-color: #f2dede; /* Light red/pink */
|
||||||
|
}
|
||||||
|
.gradeX { /* Wanted */
|
||||||
|
background-color: #d9edf7; /* Light blue */
|
||||||
|
}
|
||||||
|
.gradeI { /* Ignored */
|
||||||
|
background-color: #fcf8e3; /* Light yellow */
|
||||||
|
}
|
||||||
|
.gradeC { /* Snatched */
|
||||||
|
background-color: #dff0d8; /* Light green */
|
||||||
|
}
|
||||||
|
.gradeA { /* Downloaded/Processed (default) */
|
||||||
|
/* No specific background or subtle light grey */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="javascriptIncludes()">
|
<%def name="javascriptIncludes()">
|
||||||
|
${parent.javascriptIncludes()} <%-- Ensure parent javascript includes are kept --%>
|
||||||
<script src="js/libs/jquery.dataTables.min.js"></script>
|
<script src="js/libs/jquery.dataTables.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function initThisPage() {
|
// Encapsulate page-specific logic
|
||||||
|
var ManageAlbumsPage = ManageAlbumsPage || {};
|
||||||
|
|
||||||
|
ManageAlbumsPage.initDataTable = function() {
|
||||||
$('#album_table').dataTable({
|
$('#album_table').dataTable({
|
||||||
"bDestroy": true,
|
"bDestroy": true,
|
||||||
"aoColumns": [
|
"aoColumns": [
|
||||||
null,
|
null, // Checkbox column (not sortable)
|
||||||
null,
|
null, // Album Name
|
||||||
null,
|
null, // Artist Name
|
||||||
null,
|
null, // Date
|
||||||
null,
|
null, // Type
|
||||||
null,
|
null, // Status
|
||||||
{ "sType": "title-numeric"},
|
{ "sType": "title-numeric"}, // Have (uses title for numeric sort)
|
||||||
null,
|
null, // Bitrate
|
||||||
null
|
null // Format
|
||||||
],
|
],
|
||||||
"aoColumnDefs": [
|
"aoColumnDefs": [
|
||||||
{ 'bSortable': false, 'aTargets': [ 0 ] }
|
{ 'bSortable': false, 'aTargets': [ 0 ] } // Disable sorting for checkbox column
|
||||||
],
|
],
|
||||||
"oLanguage": {
|
"oLanguage": {
|
||||||
"sLengthMenu":"Show _MENU_ albums per page",
|
"sLengthMenu":"Show _MENU_ albums per page",
|
||||||
@@ -136,19 +172,83 @@
|
|||||||
"sInfoEmpty":"Showing 0 to 0 of 0 albums",
|
"sInfoEmpty":"Showing 0 to 0 of 0 albums",
|
||||||
"sInfoFiltered":"(filtered from _MAX_ total albums)",
|
"sInfoFiltered":"(filtered from _MAX_ total albums)",
|
||||||
"sSearch": ""},
|
"sSearch": ""},
|
||||||
"bPaginate": false,
|
"bPaginate": false, // All data loaded on one page
|
||||||
"aaSorting": [[5, 'desc']],
|
"aaSorting": [[5, 'desc']], // Default sort by Status descending
|
||||||
"fnDrawCallback": function (o) {
|
"fnDrawCallback": function (o) {
|
||||||
// Jump to top of page
|
// Jump to top of page
|
||||||
$('html,body').scrollTop(0);
|
$('html,body').scrollTop(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
resetFilters("albums");
|
};
|
||||||
}
|
|
||||||
|
ManageAlbumsPage.initActions = function() {
|
||||||
|
// Event listener for the "Mark selected albums as" dropdown
|
||||||
|
$('#markAlbumActionSelect').on('change', function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var actionValue = $this.val();
|
||||||
|
var selectedAlbumIds = [];
|
||||||
|
|
||||||
|
// Get all checked album checkboxes
|
||||||
|
$('.album-checkbox:checked').each(function() {
|
||||||
|
selectedAlbumIds.push($(this).val());
|
||||||
|
});
|
||||||
|
|
||||||
|
if (selectedAlbumIds.length === 0) {
|
||||||
|
// Display error if no albums are selected
|
||||||
|
if (typeof showMessage === 'function') { // Assuming showMessage is a global utility
|
||||||
|
showMessage($this.data('error') || "You didn't select any albums", 'error');
|
||||||
|
} else {
|
||||||
|
alert($this.data('error') || "You didn't select any albums");
|
||||||
|
}
|
||||||
|
// Reset select box to default
|
||||||
|
$this.val($('option:first', $this).val());
|
||||||
|
return; // Stop execution
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct URL with selected album IDs and action
|
||||||
|
var url = 'markAlbums?action=' + encodeURIComponent(actionValue);
|
||||||
|
$.each(selectedAlbumIds, function(index, id) {
|
||||||
|
url += '&albumid=' + encodeURIComponent(id); // Use a consistent param name if backend expects multiple
|
||||||
|
});
|
||||||
|
|
||||||
|
// Perform AJAX call
|
||||||
|
if (typeof doAjaxCall === 'function') {
|
||||||
|
doAjaxCall(url, $this, 'table', 'Albums marked as ' + actionValue + ' successfully!', 'Error marking albums.');
|
||||||
|
// After successful action, you might want to redraw the table or update rows
|
||||||
|
// $('#album_table').dataTable().fnDraw();
|
||||||
|
} else {
|
||||||
|
console.error("doAjaxCall function is not defined. Cannot mark albums asynchronously.");
|
||||||
|
}
|
||||||
|
// Reset select box to default after action
|
||||||
|
$this.val($('option:first', $this).val());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Event listener for the "toggle all" checkbox
|
||||||
|
$('#toggleAllAlbums').on('click', function() {
|
||||||
|
$('.album-checkbox').prop('checked', this.checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Optionally, reset individual checkboxes if header checkbox is unchecked (and vice-versa if needed)
|
||||||
|
$('.album-checkbox').on('click', function() {
|
||||||
|
if (!this.checked) {
|
||||||
|
$('#toggleAllAlbums').prop('checked', false);
|
||||||
|
} else {
|
||||||
|
// If all are checked, check the header checkbox
|
||||||
|
if ($('.album-checkbox:checked').length === $('.album-checkbox').length) {
|
||||||
|
$('#toggleAllAlbums').prop('checked', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
initThisPage();
|
ManageAlbumsPage.initDataTable();
|
||||||
|
ManageAlbumsPage.initActions();
|
||||||
|
|
||||||
|
// Assuming resetFilters is a global function from common.js
|
||||||
|
if (typeof resetFilters === 'function') {
|
||||||
|
resetFilters("albums");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user