mirror of
https://github.com/rembo10/headphones.git
synced 2026-03-21 12:19:27 +00:00
348 lines
14 KiB
HTML
348 lines
14 KiB
HTML
<%inherit file="base.html" />
|
|
<%!
|
|
import headphones
|
|
# Removed direct DB imports and queries from template.
|
|
# These operations (fetching artists and creating json_artists)
|
|
# should be performed in the Python view/controller and passed
|
|
# to the template as part of its context.
|
|
# import json
|
|
# from headphones import db, helpers
|
|
# myDB = db.DBConnection()
|
|
# artist_json = {}
|
|
# counter = 0
|
|
# artist_list = myDB.action("SELECT ArtistName from artists ORDER BY ArtistName COLLATE NOCASE")
|
|
# for artist in artist_list:
|
|
# artist_json[counter] = artist['ArtistName']
|
|
# counter+=1
|
|
# json_artists = json.dumps(artist_json)
|
|
%>
|
|
|
|
<%def name="headerIncludes()">
|
|
<div id="subhead_container">
|
|
<div id="subhead_menu">
|
|
<a class="menu_link_edit" href="manageManual"><i class="fa fa-pencil"></i> Manage Manually Matched & Ignored</a>
|
|
</div>
|
|
</div>
|
|
<a href="manage" class="back">« Back to manage overview</a>
|
|
</%def>
|
|
|
|
|
|
<%def name="body()">
|
|
<div class="table_wrapper">
|
|
<div id="manageheader" class="title">
|
|
<h1 class="clearfix"><i class="fa fa-music"></i> Manage Unmatched Albums</h1>
|
|
</div>
|
|
|
|
<table class="display" id="unmatched_album_table"> <%-- Changed ID for clarity --%>
|
|
<thead>
|
|
<tr>
|
|
<th class="column-artist">Local Artist</th>
|
|
<th class="column-album">Local Album</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% count_albums=0 %> <%-- Still useful for unique IDs if needed, but aiming for generic dialogs --%>
|
|
%for album in unmatchedalbums:
|
|
<tr class="gradeZ">
|
|
<%
|
|
# Pre-escape for direct use in data-attributes where JS string is needed.
|
|
# URL encoding will happen in JS with encodeURIComponent.
|
|
old_artist_js_str = album['ArtistName'].replace("'","\\'").replace('"','"')
|
|
old_album_js_str = album['AlbumTitle'].replace("'","\\'").replace('"','"')
|
|
%>
|
|
<td class="column-artist">
|
|
${album['ArtistName']}<BR>
|
|
<%-- Data attributes to pass context to JS --%>
|
|
<button type="button" class="action-button ignore-artist-button"
|
|
data-artist-name="${album['ArtistName']}"
|
|
data-old-artist-js="${old_artist_js_str}">
|
|
(-) Ignore Artist
|
|
</button>
|
|
|
|
<button type="button" class="action-button match-artist-button"
|
|
data-artist-name="${album['ArtistName']}"
|
|
data-old-artist-js="${old_artist_js_str}">
|
|
(->) Match Artist
|
|
</button>
|
|
</td>
|
|
<td class="column-album">
|
|
${album['AlbumTitle']}<BR>
|
|
<button type="button" class="action-button ignore-album-button"
|
|
data-artist-name="${album['ArtistName']}"
|
|
data-album-title="${album['AlbumTitle']}"
|
|
data-old-artist-js="${old_artist_js_str}"
|
|
data-old-album-js="${old_album_js_str}">
|
|
(-) Ignore Album
|
|
</button>
|
|
|
|
<button type="button" class="action-button match-album-button"
|
|
data-artist-name="${album['ArtistName']}"
|
|
data-album-title="${album['AlbumTitle']}"
|
|
data-old-artist-js="${old_artist_js_str}"
|
|
data-old-album-js="${old_album_js_str}">
|
|
(->) Match Album
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<% count_albums+=1 %>
|
|
%endfor
|
|
</tbody>
|
|
</table>
|
|
|
|
<%-- Generic Ignore Confirmation Dialog --%>
|
|
<div id="ignore_dialog" title="Confirm Ignore" style="display:none">
|
|
<p class="dialog-message"></p>
|
|
<p class="dialog-actions" align="right"><BR>
|
|
<button type="button" class="confirm-ignore-button"></button>
|
|
</p>
|
|
</div>
|
|
|
|
<%-- Generic Match Dialog --%>
|
|
<div id="match_dialog" title="Match Album" style="display:none">
|
|
<p><strong>Local Artist:</strong> <span id="local-artist-display"></span></p>
|
|
<p><strong>Local Album:</strong> <span id="local-album-display"></span></p>
|
|
|
|
<div id="artist-match-section">
|
|
<p>Match Artist:</p>
|
|
<select id="match-artist-options" name="new_artist"></select>
|
|
</div>
|
|
|
|
<div id="album-match-section">
|
|
<p>Match Album:</p>
|
|
<select id="match-album-options" name="new_album"></select>
|
|
</div>
|
|
|
|
<p class="dialog-actions" align="right"><BR>
|
|
<button type="button" class="confirm-match-button"></button>
|
|
</p>
|
|
</div>
|
|
|
|
</div>
|
|
</%def>
|
|
|
|
<%def name="headIncludes()">
|
|
${parent.headIncludes()} <%-- Ensure parent head includes are kept --%>
|
|
<link rel="stylesheet" href="interfaces/default/css/data_table.css">
|
|
</%def>
|
|
|
|
<%def name="javascriptIncludes()">
|
|
${parent.javascriptIncludes()} <%-- Ensure parent javascript includes are kept --%>
|
|
<script src="js/libs/jquery.dataTables.min.js"></script>
|
|
<script>
|
|
// Encapsulate page-specific logic
|
|
var ManageUnmatchedPage = ManageUnmatchedPage || {};
|
|
|
|
ManageUnmatchedPage.jsonArtists = ${json_artists | n, unicode}; // Assuming json_artists is passed from backend
|
|
|
|
ManageUnmatchedPage.initDataTable = function() {
|
|
$('#unmatched_album_table').dataTable({ <%-- Use the updated ID --%>
|
|
"bStateSave": true,
|
|
"bPaginate": true,
|
|
"oLanguage": {
|
|
"sSearch": "",
|
|
"sLengthMenu":"Show _MENU_ albums per page",
|
|
"sInfo":"Showing _START_ to _END_ of _TOTAL_ albums",
|
|
"sInfoEmpty":"Showing 0 to 0 of 0 albums",
|
|
"sInfoFiltered":"(filtered from _MAX_ total albums)",
|
|
"sEmptyTable": " ",
|
|
},
|
|
"sPaginationType": "full_numbers",
|
|
"fnDrawCallback": function (o) {
|
|
// Jump to top of page
|
|
$('html,body').scrollTop(0);
|
|
}
|
|
});
|
|
};
|
|
|
|
ManageUnmatchedPage.initDialogs = function() {
|
|
// Initialize the generic ignore dialog
|
|
$('#ignore_dialog').dialog({
|
|
autoOpen: false,
|
|
modal: true,
|
|
resizable: false,
|
|
width: 500,
|
|
height: 'auto',
|
|
buttons: {
|
|
"Cancel": function() {
|
|
$(this).dialog('close');
|
|
}
|
|
}
|
|
});
|
|
|
|
// Initialize the generic match dialog
|
|
$('#match_dialog').dialog({
|
|
autoOpen: false,
|
|
modal: true,
|
|
resizable: false,
|
|
width: 700,
|
|
height: 'auto',
|
|
buttons: {
|
|
"Cancel": function() {
|
|
$(this).dialog('close');
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
ManageUnmatchedPage.initActions = function() {
|
|
// --- Ignore Artist/Album Logic ---
|
|
$(document).on('click', '.ignore-artist-button, .ignore-album-button', function() {
|
|
var $button = $(this);
|
|
var isArtistIgnore = $button.hasClass('ignore-artist-button');
|
|
var artistName = $button.data('artist-name');
|
|
var albumTitle = $button.data('album-title');
|
|
var oldArtistJs = $button.data('old-artist-js'); // JS escaped, needs URI encoding for URL
|
|
var oldAlbumJs = $button.data('old-album-js'); // JS escaped, needs URI encoding for URL
|
|
|
|
var $dialog = $('#ignore_dialog');
|
|
var $dialogMessage = $dialog.find('.dialog-message');
|
|
var $confirmButton = $dialog.find('.confirm-ignore-button');
|
|
|
|
var message = "";
|
|
var actionUrl = "";
|
|
var successMessage = "";
|
|
|
|
if (isArtistIgnore) {
|
|
message = "Are you sure you want to ignore Local Artist: " + artistName + " from future matching?";
|
|
actionUrl = 'markUnmatched?action=ignoreArtist&existing_artist=' + encodeURIComponent(oldArtistJs);
|
|
successMessage = "Successfully ignored " + artistName + " from future matching";
|
|
$confirmButton.text('Ignore Artist');
|
|
} else { // ignore-album-button
|
|
message = "Are you sure you want to ignore Local Album: " + albumTitle + " from future matching?";
|
|
actionUrl = 'markUnmatched?action=ignoreAlbum&existing_artist=' + encodeURIComponent(oldArtistJs) + '&existing_album=' + encodeURIComponent(oldAlbumJs);
|
|
successMessage = "Successfully ignored " + albumTitle + " from future matching";
|
|
$confirmButton.text('Ignore Album');
|
|
}
|
|
|
|
$dialogMessage.text(message);
|
|
|
|
$confirmButton.off('click').on('click', function() {
|
|
if (typeof doAjaxCall === 'function') {
|
|
doAjaxCall(actionUrl, $button, 'page', successMessage);
|
|
} else {
|
|
console.error("doAjaxCall function is not defined. Cannot perform ignore action.");
|
|
}
|
|
$dialog.dialog('close');
|
|
});
|
|
|
|
$dialog.dialog('open');
|
|
});
|
|
|
|
// --- Match Artist/Album Logic ---
|
|
$(document).on('click', '.match-artist-button, .match-album-button', function() {
|
|
var $button = $(this);
|
|
var isArtistMatch = $button.hasClass('match-artist-button');
|
|
var artistName = $button.data('artist-name');
|
|
var albumTitle = $button.data('album-title');
|
|
var oldArtistJs = $button.data('old-artist-js');
|
|
var oldAlbumJs = $button.data('old-album-js');
|
|
|
|
var $dialog = $('#match_dialog');
|
|
var $localArtistDisplay = $('#local-artist-display');
|
|
var $localAlbumDisplay = $('#local-album-display');
|
|
var $artistMatchSection = $('#artist-match-section');
|
|
var $albumMatchSection = $('#album-match-section');
|
|
var $matchArtistOptions = $('#match-artist-options');
|
|
var $matchAlbumOptions = $('#match-album-options');
|
|
var $confirmButton = $dialog.find('.confirm-match-button');
|
|
|
|
// Reset dialog state
|
|
$localArtistDisplay.text(artistName);
|
|
$matchArtistOptions.empty();
|
|
$matchAlbumOptions.empty();
|
|
$confirmButton.off('click'); // Clear previous click handlers
|
|
|
|
// Populate artist options
|
|
$.each(ManageUnmatchedPage.jsonArtists, function(key, value) {
|
|
$matchArtistOptions.append($("<option/>", {
|
|
value: value,
|
|
text: value
|
|
}));
|
|
});
|
|
|
|
if (isArtistMatch) {
|
|
$localAlbumDisplay.closest('p').hide(); // Hide local album row
|
|
$albumMatchSection.hide(); // Hide match album section
|
|
$localArtistDisplay.text(artistName);
|
|
$artistMatchSection.show(); // Show match artist section
|
|
$confirmButton.text('Match Artist');
|
|
|
|
$confirmButton.on('click', function() {
|
|
var newArtist = $matchArtistOptions.val();
|
|
var actionUrl = 'markUnmatched?action=matchArtist&existing_artist=' + encodeURIComponent(oldArtistJs) + '&new_artist=' + encodeURIComponent(newArtist);
|
|
var successMessage = 'Successfully matched ' + artistName + ' with ' + newArtist;
|
|
if (typeof doAjaxCall === 'function') {
|
|
doAjaxCall(actionUrl, $button, 'page', successMessage);
|
|
} else {
|
|
console.error("doAjaxCall function is not defined. Cannot match artist.");
|
|
}
|
|
$dialog.dialog('close');
|
|
});
|
|
|
|
} else { // match-album-button
|
|
$localAlbumDisplay.closest('p').show(); // Show local album row
|
|
$albumMatchSection.show(); // Show match album section
|
|
$localAlbumDisplay.text(albumTitle);
|
|
$artistMatchSection.show(); // Show match artist section (for selecting matched album's artist)
|
|
$confirmButton.text('Match Album');
|
|
|
|
// Load albums for selected artist initially
|
|
ManageUnmatchedPage.loadAlbumsForArtist($matchArtistOptions.val(), $matchAlbumOptions);
|
|
|
|
// Handle artist selection change
|
|
$matchArtistOptions.off('change').on('change', function() {
|
|
ManageUnmatchedPage.loadAlbumsForArtist($(this).val(), $matchAlbumOptions);
|
|
});
|
|
|
|
$confirmButton.on('click', function() {
|
|
var newArtist = $matchArtistOptions.val();
|
|
var newAlbum = $matchAlbumOptions.val();
|
|
var actionUrl = 'markUnmatched?action=matchAlbum&existing_artist=' + encodeURIComponent(oldArtistJs) + '&new_artist=' + encodeURIComponent(newArtist) + '&existing_album=' + encodeURIComponent(oldAlbumJs) + '&new_album=' + encodeURIComponent(newAlbum);
|
|
var successMessage = 'Successfully matched ' + albumTitle + ' with ' + newAlbum + ' by ' + newArtist;
|
|
if (typeof doAjaxCall === 'function') {
|
|
doAjaxCall(actionUrl, $button, 'page', successMessage);
|
|
} else {
|
|
console.error("doAjaxCall function is not defined. Cannot match album.");
|
|
}
|
|
$dialog.dialog('close');
|
|
});
|
|
}
|
|
$dialog.dialog('open');
|
|
});
|
|
|
|
// Helper function to load albums for a given artist
|
|
ManageUnmatchedPage.loadAlbumsForArtist = function(artistName, $targetSelect) {
|
|
$targetSelect.empty().append($("<option/>", { value: "", text: "Loading albums..." })); // Add loading message
|
|
var cleanArtistName = encodeURIComponent(artistName);
|
|
$.getJSON("getAlbumsByArtist_json?artist=" + cleanArtistName, function(data) {
|
|
$targetSelect.empty();
|
|
if (Object.keys(data).length > 0) {
|
|
$.each(data, function(key, value) {
|
|
$targetSelect.append($("<option/>", {
|
|
value: value,
|
|
text: value
|
|
}));
|
|
});
|
|
} else {
|
|
$targetSelect.append($("<option/>", { value: "", text: "No albums found" }));
|
|
}
|
|
}).fail(function() {
|
|
$targetSelect.empty().append($("<option/>", { value: "", text: "Error loading albums" }));
|
|
});
|
|
};
|
|
|
|
// Assuming initActions from common.js is called globally
|
|
if (typeof initActions === 'function') {
|
|
initActions();
|
|
}
|
|
};
|
|
|
|
$(document).ready(function() {
|
|
ManageUnmatchedPage.initDataTable();
|
|
ManageUnmatchedPage.initDialogs();
|
|
ManageUnmatchedPage.initActions();
|
|
});
|
|
|
|
</script>
|
|
</%def>
|