add musicbrainz icon for items where matched

pull/130/head
Broque Thomas 2 months ago
parent 8cdf548561
commit 22eb62bb77

@ -4033,13 +4033,14 @@ class MusicDatabase:
a.name,
a.thumb_url,
a.genres,
a.musicbrainz_id,
COUNT(DISTINCT al.id) as album_count,
COUNT(DISTINCT t.id) as track_count
FROM artists a
LEFT JOIN albums al ON a.id = al.artist_id
LEFT JOIN tracks t ON al.id = t.album_id
WHERE {where_clause}
GROUP BY a.id, a.name, a.thumb_url, a.genres
GROUP BY a.id, a.name, a.thumb_url, a.genres, a.musicbrainz_id
ORDER BY a.name COLLATE NOCASE
LIMIT ? OFFSET ?
"""
@ -4076,6 +4077,7 @@ class MusicDatabase:
'name': artist.name,
'image_url': artist.thumb_url,
'genres': artist.genres,
'musicbrainz_id': row['musicbrainz_id'],
'album_count': row['album_count'] or 0,
'track_count': row['track_count'] or 0
}
@ -4130,7 +4132,7 @@ class MusicDatabase:
# Get artist information
cursor.execute("""
SELECT
id, name, thumb_url, genres, server_source
id, name, thumb_url, genres, server_source, musicbrainz_id
FROM artists
WHERE id = ?
""", (artist_id,))
@ -4173,6 +4175,7 @@ class MusicDatabase:
a.year,
SUM(a.track_count) as track_count,
MAX(a.thumb_url) as thumb_url,
MAX(a.musicbrainz_release_id) as musicbrainz_release_id,
COUNT(t.id) as owned_tracks
FROM albums a
LEFT JOIN tracks t ON a.id = t.album_id
@ -4225,6 +4228,7 @@ class MusicDatabase:
'owned': True, # All albums in our DB are owned
'track_count': album_row['track_count'],
'owned_tracks': owned_tracks,
'musicbrainz_release_id': album_row['musicbrainz_release_id'],
'track_completion': completion_percentage
}
@ -4265,6 +4269,7 @@ class MusicDatabase:
'image_url': artist_image_url,
'genres': genres,
'server_source': artist_row['server_source'],
'musicbrainz_id': artist_row['musicbrainz_id'],
'album_count': album_count,
'track_count': track_count
},

@ -20011,8 +20011,20 @@ function createArtistCardHTML(artist) {
// Track if image needs to be lazy loaded
const needsImage = imageUrl ? 'false' : 'true';
// Check for MusicBrainz ID
let mbIconHTML = '';
if (artist.musicbrainz_id) {
const mbLogoUrl = 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/MusicBrainz_Logo_%282016%29.svg/500px-MusicBrainz_Logo_%282016%29.svg.png'; // Use official SVG logo
mbIconHTML = `
<div class="mb-card-icon" title="View on MusicBrainz" onclick="event.stopPropagation(); window.open('https://musicbrainz.org/artist/${artist.musicbrainz_id}', '_blank')">
<img src="${mbLogoUrl}" style="width: 20px; height: auto; display: block;">
</div>
`;
}
return `
<div class="artist-card" data-artist-id="${artist.id}" data-needs-image="${needsImage}">
${mbIconHTML}
<div class="artist-card-background" style="${backgroundStyle}"></div>
<div class="artist-card-overlay"></div>
<div class="artist-card-content">
@ -20122,6 +20134,17 @@ async function loadArtistDiscography(artistId, artistName = null) {
singles: data.singles || []
};
// Update selected artist with full details from backend (includes MusicBrainz ID)
if (data.artist) {
console.log('✨ Updating artist details with fresh data from backend');
artistsPageState.selectedArtist = {
...artistsPageState.selectedArtist,
...data.artist
};
// Refresh header to show MusicBrainz link
updateArtistDetailHeader(artistsPageState.selectedArtist);
}
console.log(`✅ Loaded ${discography.albums.length} albums and ${discography.singles.length} singles`);
// Cache the results
@ -21120,6 +21143,35 @@ function updateArtistDetailHeader(artist) {
if (nameElement) {
nameElement.textContent = artist.name;
// DEBUG: Log the artist object to check for MBID
console.log(`🔍 [DEBUG] Updating header for ${artist.name}`, artist);
console.log(`🔍 [DEBUG] MBID present?`, artist.musicbrainz_id);
// Add MusicBrainz link if available
if (artist.musicbrainz_id) {
console.log('✅ [DEBUG] Adding MusicBrainz link to header');
// Remove existing MB link if any
const existingMb = nameElement.parentNode.querySelector('.mb-link-btn');
if (existingMb) existingMb.remove();
const mbLink = document.createElement('a');
mbLink.className = 'mb-link-btn';
mbLink.href = `https://musicbrainz.org/artist/${artist.musicbrainz_id}`;
mbLink.target = '_blank';
mbLink.title = 'View on MusicBrainz';
mbLink.innerHTML = `
<img src="https://custom-icon-badges.demolab.com/badge/-MusicBrainz-353535?style=flat&logo=musicbrainz&logoColor=white" style="width: auto; height: 16px; margin: 0;">
`;
// Simplified button style to just be the badge/icon for cleaner look header
mbLink.style.padding = '0';
mbLink.style.border = 'none';
mbLink.style.background = 'transparent';
mbLink.style.marginLeft = '12px';
mbLink.style.verticalAlign = 'middle';
nameElement.appendChild(mbLink);
}
}
if (genresElement) {
@ -25117,6 +25169,26 @@ function createLibraryArtistCard(artist) {
const card = document.createElement("div");
card.className = "library-artist-card";
card.setAttribute("data-artist-id", artist.id);
// Add relative positioning for icon and smooth transition
card.style.position = 'relative';
card.style.transition = 'transform 0.2s, box-shadow 0.2s';
// Add MusicBrainz icon if ID exists
if (artist.musicbrainz_id) {
const mbIcon = document.createElement('div');
mbIcon.className = 'mb-card-icon';
mbIcon.title = 'View on MusicBrainz';
// Use official SVG logo
const mbLogoUrl = 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/MusicBrainz_Logo_%282016%29.svg/500px-MusicBrainz_Logo_%282016%29.svg.png';
mbIcon.innerHTML = `<img src="${mbLogoUrl}" style="width: 20px; height: auto; display: block;">`;
mbIcon.onclick = (e) => {
e.stopPropagation();
window.open(`https://musicbrainz.org/artist/${artist.musicbrainz_id}`, '_blank');
};
card.appendChild(mbIcon);
}
// Create image element
const imageContainer = document.createElement("div");
@ -25329,12 +25401,12 @@ async function loadArtistDetailData(artistId, artistName) {
console.log(`🎨 Main content visibility:`, document.getElementById('artist-detail-main'));
console.log(`🎨 Albums section:`, document.getElementById('albums-section'));
// Update header with artist name now that data is loaded
updateArtistDetailPageHeader(data.artist.name);
// Populate the page with data
// Populate the page with data (which updates the hero section and sets textContent)
populateArtistDetailPage(data);
// Update header with artist name and MusicBrainz link LAST to avoid overwrite
updateArtistDetailPageHeaderWithData(data.artist);
} catch (error) {
console.error(`❌ Error loading artist detail data:`, error);
@ -25358,6 +25430,63 @@ function updateArtistDetailPageHeader(artistName) {
const mainTitle = document.getElementById("artist-info-name");
if (mainTitle) {
mainTitle.textContent = artistName;
// Try to find the artist object in memory to get the MBID
// We can look at the data passed to populateArtistDetailPage if this function accepted the full object
// Or access the state if it was saved
// Actually, let's look at how this is invoked. It's called from loadArtistDetailData which has the full 'data' object.
// But this function only accepts 'artistName'.
// We should query the state or modify the function signature.
// For now, let's try to find the MB link element and update it if we can find the artist in data.
}
}
function updateArtistDetailPageHeaderWithData(artist) {
// Target the visible header element
const mainTitle = document.getElementById("artist-detail-name");
if (mainTitle) {
console.log('✅ [DEBUG] Updating header for:', artist.name);
// We assume textContent is set by updateArtistHeroSection, so we just APPEND the link
// But to be safe, we can ensure name is there.
// If we run AFTER populateArtistDetailPage, textContent is already set.
// If we reset textContent here, we might lose other formatting?
// artist-detail-name usually just contains text.
mainTitle.textContent = artist.name;
if (artist.musicbrainz_id) {
console.log('✅ [DEBUG] Adding MusicBrainz link to DETAIL page header for', artist.name);
// Remove existing link if any (to prevent duplicates)
const existingMb = mainTitle.querySelector('.mb-link-btn');
if (existingMb) existingMb.remove();
const mbLink = document.createElement('a');
mbLink.className = 'mb-link-btn';
mbLink.href = `https://musicbrainz.org/artist/${artist.musicbrainz_id}`;
mbLink.target = '_blank';
mbLink.title = 'View on MusicBrainz';
// Use the specific logo requested by user
const mbLogoUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/MusicBrainz_Logo_%282016%29.svg/500px-MusicBrainz_Logo_%282016%29.svg.png";
mbLink.innerHTML = `
<img src="${mbLogoUrl}" style="height: 24px; width: auto; vertical-align: middle; display: inline-block;">
<span style="color:rgba(255,255,255,0.9); margin-left:10px; font-size: 13px; font-weight: 600; vertical-align: middle;">View on MusicBrainz</span>
`;
mbLink.style.padding = '5px 14px';
mbLink.style.border = '1px solid rgba(255,255,255,0.1)';
mbLink.style.background = 'rgba(0,0,0,0.4)';
mbLink.style.borderRadius = '20px';
mbLink.style.marginLeft = '16px';
mbLink.style.display = 'inline-flex';
mbLink.style.alignItems = 'center';
mbLink.style.textDecoration = 'none';
mbLink.style.verticalAlign = 'middle';
mainTitle.appendChild(mbLink);
}
}
}
@ -25602,6 +25731,28 @@ function createReleaseCard(release) {
card.setAttribute("data-release-id", release.id || "");
card.setAttribute("data-spotify-id", release.spotify_id || "");
// DEBUG: Log release to check for MBID
// console.log(`🔍 [DEBUG] Release: ${release.title}`, release);
// Add MusicBrainz icon if available
let mbIcon = null;
if (release.musicbrainz_release_id) {
console.log(`✅ [DEBUG] Adding MB icon for release: ${release.title}`);
const mbLogoUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/MusicBrainz_Logo_%282016%29.svg/500px-MusicBrainz_Logo_%282016%29.svg.png";
mbIcon = document.createElement("div");
mbIcon.className = "mb-card-icon";
mbIcon.title = "View on MusicBrainz";
// Use image instead of text
mbIcon.innerHTML = `<img src="${mbLogoUrl}" style="width: 20px; height: auto; display: block;">`;
mbIcon.onclick = (e) => {
e.stopPropagation();
window.open(`https://musicbrainz.org/release/${release.musicbrainz_release_id}`, '_blank');
};
// Will append last
}
// Create image
const imageContainer = document.createElement("div");
if (release.image_url && release.image_url.trim() !== "") {
@ -25733,6 +25884,11 @@ function createReleaseCard(release) {
card.appendChild(year);
card.appendChild(completion);
// Add MusicBrainz icon LAST to ensure it's on top
if (release.musicbrainz_release_id && mbIcon) { // Check if mbIcon was created
card.appendChild(mbIcon);
}
// Add click handler for release card
card.addEventListener("click", async () => {
console.log(`Clicked on release: ${release.title} (Owned: ${release.owned})`);

@ -21714,4 +21714,75 @@ body {
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 8px solid rgba(30, 30, 30, 0.98);
}
/* MusicBrainz Integration */
.release-card {
position: relative !important;
/* Ensure positioning context */
}
.mb-link-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 6px 12px;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 6px;
color: #fff;
text-decoration: none;
font-size: 13px;
font-weight: 500;
transition: all 0.2s ease;
margin-left: 10px;
cursor: pointer;
vertical-align: middle;
}
.mb-link-btn:hover {
background: rgba(186, 71, 143, 0.4);
/* MusicBrainz Purple-ish */
border-color: rgba(186, 71, 143, 0.6);
transform: translateY(-1px);
}
.mb-link-btn img,
.mb-link-btn svg {
width: 16px;
height: 16px;
margin-right: 6px;
vertical-align: middle;
}
.mb-card-icon {
position: absolute;
top: 8px;
right: 8px;
width: 28px;
height: 28px;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
/* MusicBrainz Purple - Force visible color */
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.9 !important;
/* Force visible */
transition: transform 0.2s;
cursor: pointer;
z-index: 100 !important;
/* Force on top */
color: white;
font-size: 11px;
font-weight: 800;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}
.mb-card-icon:hover {
transform: scale(1.1);
background: #d466a9;
opacity: 1 !important;
}
Loading…
Cancel
Save