Add play button to repair findings & increase finding image sizes
- Play button on acoustid_mismatch, acoustid_no_match, track_number_mismatch, fake_lossless, dead_file, orphan_file findings - Uses playLibraryTrack() for proper media player integration (track info, sidebar, album art) - Data attributes for safe escaping instead of inline onclick strings - Finding images increased from 56px to 150px with hover effects - Improved detail panel spacing and media card layout
This commit is contained in:
parent
078b1130f8
commit
186671aa2e
2 changed files with 87 additions and 22 deletions
|
|
@ -50535,6 +50535,33 @@ function _formatFileSize(bytes) {
|
||||||
return (bytes / 1048576).toFixed(1) + ' MB';
|
return (bytes / 1048576).toFixed(1) + ' MB';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _renderPlayButton(f) {
|
||||||
|
const d = f.details || {};
|
||||||
|
const filePath = f.file_path || d.file_path || d.original_path;
|
||||||
|
if (!filePath) return '';
|
||||||
|
const title = d.expected_title || d.title || d.file_title || d.matched_title || '';
|
||||||
|
const artist = d.expected_artist || d.artist || d.artist_name || '';
|
||||||
|
const album = d.album || d.album_title || '';
|
||||||
|
const albumArt = d.album_thumb_url || '';
|
||||||
|
return `<button class="repair-finding-play-btn" onclick="event.stopPropagation(); playFindingTrack(this)"
|
||||||
|
data-path="${_escFinding(filePath)}" data-title="${_escFinding(title)}"
|
||||||
|
data-artist="${_escFinding(artist)}" data-album="${_escFinding(album)}"
|
||||||
|
data-art="${_escFinding(albumArt)}" data-entity-id="${_escFinding(f.entity_id || '')}" title="Play this track">
|
||||||
|
<svg viewBox="0 0 24 24"><polygon points="5,3 19,12 5,21"/></svg> Play
|
||||||
|
</button>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function playFindingTrack(btn) {
|
||||||
|
const track = {
|
||||||
|
file_path: btn.dataset.path,
|
||||||
|
title: btn.dataset.title || 'Unknown Track',
|
||||||
|
id: btn.dataset.entityId || null
|
||||||
|
};
|
||||||
|
const albumTitle = btn.dataset.album || '';
|
||||||
|
const artistName = btn.dataset.artist || '';
|
||||||
|
playLibraryTrack(track, albumTitle, artistName);
|
||||||
|
}
|
||||||
|
|
||||||
function _renderFindingMedia(d) {
|
function _renderFindingMedia(d) {
|
||||||
const albumUrl = d.album_thumb_url;
|
const albumUrl = d.album_thumb_url;
|
||||||
const artistUrl = d.artist_thumb_url;
|
const artistUrl = d.artist_thumb_url;
|
||||||
|
|
@ -50572,7 +50599,7 @@ function _renderFindingDetail(f) {
|
||||||
if (d.title) rows.push(['Title', d.title]);
|
if (d.title) rows.push(['Title', d.title]);
|
||||||
if (d.track_id) rows.push(['Track ID', d.track_id]);
|
if (d.track_id) rows.push(['Track ID', d.track_id]);
|
||||||
if (d.original_path) rows.push(['Original Path', d.original_path, 'path']);
|
if (d.original_path) rows.push(['Original Path', d.original_path, 'path']);
|
||||||
return media + _gridRows(rows);
|
return media + _gridRows(rows) + _renderPlayButton(f);
|
||||||
|
|
||||||
case 'orphan_file':
|
case 'orphan_file':
|
||||||
if (d.folder) rows.push(['Folder', d.folder, 'path']);
|
if (d.folder) rows.push(['Folder', d.folder, 'path']);
|
||||||
|
|
@ -50580,7 +50607,7 @@ function _renderFindingDetail(f) {
|
||||||
if (d.file_size) rows.push(['File Size', _formatFileSize(d.file_size)]);
|
if (d.file_size) rows.push(['File Size', _formatFileSize(d.file_size)]);
|
||||||
if (d.modified) rows.push(['Last Modified', d.modified]);
|
if (d.modified) rows.push(['Last Modified', d.modified]);
|
||||||
if (f.file_path) rows.push(['Full Path', f.file_path, 'path']);
|
if (f.file_path) rows.push(['Full Path', f.file_path, 'path']);
|
||||||
return _gridRows(rows);
|
return _gridRows(rows) + _renderPlayButton(f);
|
||||||
|
|
||||||
case 'acoustid_mismatch': {
|
case 'acoustid_mismatch': {
|
||||||
let html = media + '<div style="margin-bottom:8px">';
|
let html = media + '<div style="margin-bottom:8px">';
|
||||||
|
|
@ -50593,14 +50620,14 @@ function _renderFindingDetail(f) {
|
||||||
rows.push(['AcoustID Title', d.acoustid_title || '-', 'highlight']);
|
rows.push(['AcoustID Title', d.acoustid_title || '-', 'highlight']);
|
||||||
rows.push(['AcoustID Artist', d.acoustid_artist || '-', 'highlight']);
|
rows.push(['AcoustID Artist', d.acoustid_artist || '-', 'highlight']);
|
||||||
if (f.file_path) rows.push(['File', f.file_path, 'path']);
|
if (f.file_path) rows.push(['File', f.file_path, 'path']);
|
||||||
return html + _gridRows(rows);
|
return html + _gridRows(rows) + _renderPlayButton(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'acoustid_no_match':
|
case 'acoustid_no_match':
|
||||||
if (d.expected_title) rows.push(['Expected Title', d.expected_title]);
|
if (d.expected_title) rows.push(['Expected Title', d.expected_title]);
|
||||||
if (d.expected_artist) rows.push(['Expected Artist', d.expected_artist]);
|
if (d.expected_artist) rows.push(['Expected Artist', d.expected_artist]);
|
||||||
if (f.file_path) rows.push(['File', f.file_path, 'path']);
|
if (f.file_path) rows.push(['File', f.file_path, 'path']);
|
||||||
return media + _gridRows(rows);
|
return media + _gridRows(rows) + _renderPlayButton(f);
|
||||||
|
|
||||||
case 'fake_lossless': {
|
case 'fake_lossless': {
|
||||||
const cutoff = d.detected_cutoff_khz || 0;
|
const cutoff = d.detected_cutoff_khz || 0;
|
||||||
|
|
@ -50628,7 +50655,7 @@ function _renderFindingDetail(f) {
|
||||||
if (d.bitrate) rows.push(['Bitrate', `${d.bitrate} kbps`]);
|
if (d.bitrate) rows.push(['Bitrate', `${d.bitrate} kbps`]);
|
||||||
if (d.file_size) rows.push(['File Size', _formatFileSize(d.file_size)]);
|
if (d.file_size) rows.push(['File Size', _formatFileSize(d.file_size)]);
|
||||||
if (f.file_path) rows.push(['File', f.file_path, 'path']);
|
if (f.file_path) rows.push(['File', f.file_path, 'path']);
|
||||||
return flHtml + _gridRows(rows);
|
return flHtml + _gridRows(rows) + _renderPlayButton(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'duplicate_tracks':
|
case 'duplicate_tracks':
|
||||||
|
|
@ -50736,6 +50763,7 @@ function _renderFindingDetail(f) {
|
||||||
tnHtml += `<div class="repair-detail-sublist">${d.changes.map(c => `
|
tnHtml += `<div class="repair-detail-sublist">${d.changes.map(c => `
|
||||||
<div class="repair-detail-subitem"><strong>${_escFinding(c)}</strong></div>`).join('')}</div>`;
|
<div class="repair-detail-subitem"><strong>${_escFinding(c)}</strong></div>`).join('')}</div>`;
|
||||||
}
|
}
|
||||||
|
tnHtml += _renderPlayButton(f);
|
||||||
return tnHtml;
|
return tnHtml;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -40547,10 +40547,10 @@ tr.tag-diff-same {
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.04);
|
border-top: 1px solid rgba(255, 255, 255, 0.04);
|
||||||
}
|
}
|
||||||
.repair-finding-detail-inner {
|
.repair-finding-detail-inner {
|
||||||
padding: 12px 14px 14px;
|
padding: 16px 18px 18px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detail key-value rows */
|
/* Detail key-value rows */
|
||||||
|
|
@ -40646,41 +40646,78 @@ tr.tag-diff-same {
|
||||||
/* Finding media thumbnails (album art + artist image) */
|
/* Finding media thumbnails (album art + artist image) */
|
||||||
.repair-finding-media {
|
.repair-finding-media {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 14px;
|
gap: 18px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 14px;
|
||||||
padding: 10px 12px;
|
padding: 14px 16px;
|
||||||
background: rgba(255, 255, 255, 0.03);
|
background: rgba(255, 255, 255, 0.025);
|
||||||
border-radius: 10px;
|
border-radius: 12px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
.repair-finding-media-card {
|
.repair-finding-media-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 8px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.repair-finding-media-img {
|
.repair-finding-media-img {
|
||||||
width: 56px;
|
width: 150px;
|
||||||
height: 56px;
|
height: 150px;
|
||||||
border-radius: 8px;
|
border-radius: 10px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
.repair-finding-media-img:hover {
|
||||||
|
transform: scale(1.03);
|
||||||
|
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
.repair-finding-media-img.artist {
|
.repair-finding-media-img.artist {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
.repair-finding-media-label {
|
.repair-finding-media-label {
|
||||||
font-size: 10px;
|
font-size: 11px;
|
||||||
color: rgba(255, 255, 255, 0.45);
|
color: rgba(255, 255, 255, 0.5);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
max-width: 72px;
|
max-width: 150px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
line-height: 1.2;
|
line-height: 1.3;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Play button for findings */
|
||||||
|
.repair-finding-play-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 14px;
|
||||||
|
background: rgba(var(--accent-rgb, 99, 102, 241), 0.12);
|
||||||
|
border: 1px solid rgba(var(--accent-rgb, 99, 102, 241), 0.25);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: rgb(var(--accent-light-rgb, 129, 140, 248));
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.repair-finding-play-btn:hover {
|
||||||
|
background: rgba(var(--accent-rgb, 99, 102, 241), 0.2);
|
||||||
|
border-color: rgba(var(--accent-rgb, 99, 102, 241), 0.4);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
.repair-finding-play-btn:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
.repair-finding-play-btn svg {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Artwork preview (for missing cover art) */
|
/* Artwork preview (for missing cover art) */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue