Merge pull request #356 from kettui/fix/album-track-source-propagation

Fix album track source propagation
This commit is contained in:
BoulderBadgeDad 2026-04-22 11:39:16 -07:00 committed by GitHub
commit 200b68e65e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 58 additions and 12 deletions

View file

@ -500,7 +500,7 @@ async function selectArtistForDetail(artist, options = {}) {
// Update state // Update state
artistsPageState.selectedArtist = artist; artistsPageState.selectedArtist = artist;
artistsPageState.currentView = 'detail'; artistsPageState.currentView = 'detail';
artistsPageState.sourceOverride = options.source || null; artistsPageState.sourceOverride = options.source || artist.source || null;
artistsPageState.pluginOverride = options.plugin || null; artistsPageState.pluginOverride = options.plugin || null;
// Show detail state // Show detail state
@ -510,7 +510,7 @@ async function selectArtistForDetail(artist, options = {}) {
updateArtistDetailHeader(artist); updateArtistDetailHeader(artist);
// Load discography (pass artist name for cross-source fallback) // Load discography (pass artist name for cross-source fallback)
await loadArtistDiscography(artist.id, artist.name, options.source, options.plugin); await loadArtistDiscography(artist.id, artist.name, artistsPageState.sourceOverride, options.plugin);
} }
/** /**
@ -528,6 +528,13 @@ async function loadArtistDiscography(artistId, artistName = null, sourceOverride
if (artistsPageState.cache.discography[cacheKey]) { if (artistsPageState.cache.discography[cacheKey]) {
console.log('📦 Using cached discography'); console.log('📦 Using cached discography');
const cachedDiscography = artistsPageState.cache.discography[cacheKey]; const cachedDiscography = artistsPageState.cache.discography[cacheKey];
if (artistsPageState.selectedArtist) {
artistsPageState.selectedArtist = {
...artistsPageState.selectedArtist,
source: cachedDiscography.source || sourceOverride || artistsPageState.selectedArtist.source || null,
};
}
artistsPageState.sourceOverride = cachedDiscography.source || sourceOverride || artistsPageState.sourceOverride || null;
displayArtistDiscography(cachedDiscography); displayArtistDiscography(cachedDiscography);
// Load similar artists in parallel (don't wait) — always uses primary source // Load similar artists in parallel (don't wait) — always uses primary source
@ -574,6 +581,16 @@ async function loadArtistDiscography(artistId, artistName = null, sourceOverride
source: data.source || sourceOverride || null, source: data.source || sourceOverride || null,
}; };
// Keep the resolved metadata source on the selected artist so album clicks
// can pass it through to /api/album/<id>/tracks.
if (artistsPageState.selectedArtist) {
artistsPageState.selectedArtist = {
...artistsPageState.selectedArtist,
source: discography.source,
};
}
artistsPageState.sourceOverride = discography.source || artistsPageState.sourceOverride || null;
// Update selected artist with full details from backend (includes MusicBrainz ID) // Update selected artist with full details from backend (includes MusicBrainz ID)
if (data.artist) { if (data.artist) {
console.log('✨ Updating artist details with fresh data from backend'); console.log('✨ Updating artist details with fresh data from backend');
@ -2127,8 +2144,9 @@ async function createArtistAlbumVirtualPlaylist(album, albumType) {
// Fetch album tracks from backend (pass name/artist for Hydrabase support) // Fetch album tracks from backend (pass name/artist for Hydrabase support)
const _aat1 = new URLSearchParams({ name: album.name || '', artist: artist.name || '' }); const _aat1 = new URLSearchParams({ name: album.name || '', artist: artist.name || '' });
if (artistsPageState.sourceOverride) { const albumSource = artistsPageState.sourceOverride || album.source || artist.source || artistsPageState.artistDiscography?.source || null;
_aat1.set('source', artistsPageState.sourceOverride); if (albumSource) {
_aat1.set('source', albumSource);
} }
if (artistsPageState.pluginOverride) { if (artistsPageState.pluginOverride) {
_aat1.set('plugin', artistsPageState.pluginOverride); _aat1.set('plugin', artistsPageState.pluginOverride);
@ -2227,7 +2245,8 @@ async function openDownloadMissingModalForArtistAlbum(virtualPlaylistId, playlis
// Additional metadata for artist albums // Additional metadata for artist albums
artist: artist, artist: artist,
album: album, album: album,
albumType: album.album_type albumType: album.album_type,
source: artist?.source || album?.source || artistsPageState.artistDiscography?.source || null
}; };
// Generate hero section — 'artist_album' for releases, 'playlist' for charts/compilations // Generate hero section — 'artist_album' for releases, 'playlist' for charts/compilations
@ -4608,4 +4627,3 @@ function renderEnrichmentCards(enrichment) {
} }
// =============================== // ===============================

View file

@ -639,6 +639,7 @@ let artistDetailPageState = {
isInitialized: false, isInitialized: false,
currentArtistId: null, currentArtistId: null,
currentArtistName: null, currentArtistName: null,
currentArtistSource: null,
enhancedView: false, enhancedView: false,
enhancedData: null, enhancedData: null,
expandedAlbums: new Set(), expandedAlbums: new Set(),
@ -671,6 +672,7 @@ function navigateToArtistDetail(artistId, artistName) {
// Store current artist info and reset enhanced view state // Store current artist info and reset enhanced view state
artistDetailPageState.currentArtistId = artistId; artistDetailPageState.currentArtistId = artistId;
artistDetailPageState.currentArtistName = artistName; artistDetailPageState.currentArtistName = artistName;
artistDetailPageState.currentArtistSource = null;
artistDetailPageState.enhancedData = null; artistDetailPageState.enhancedData = null;
artistDetailPageState.expandedAlbums = new Set(); artistDetailPageState.expandedAlbums = new Set();
artistDetailPageState.selectedTracks = new Set(); artistDetailPageState.selectedTracks = new Set();
@ -788,6 +790,9 @@ async function loadArtistDetailData(artistId, artistName) {
// Populate the page with data (which updates the hero section and sets textContent) // Populate the page with data (which updates the hero section and sets textContent)
populateArtistDetailPage(data); populateArtistDetailPage(data);
// Keep the resolved metadata source for album-track lookups.
artistDetailPageState.currentArtistSource = data.discography?.source || data.artist?.source || null;
// Update header with artist name and MusicBrainz link LAST to avoid overwrite // Update header with artist name and MusicBrainz link LAST to avoid overwrite
updateArtistDetailPageHeaderWithData(data.artist); updateArtistDetailPageHeaderWithData(data.artist);
@ -1504,7 +1509,8 @@ function createReleaseCard(release) {
const currentArtist = artistDetailPageState.currentArtistName ? { const currentArtist = artistDetailPageState.currentArtistName ? {
id: artistDetailPageState.currentArtistId, id: artistDetailPageState.currentArtistId,
name: artistDetailPageState.currentArtistName, name: artistDetailPageState.currentArtistName,
image_url: getArtistImageFromPage() || '' // Get artist image from page image_url: getArtistImageFromPage() || '', // Get artist image from page
source: artistDetailPageState.currentArtistSource || null
} : null; } : null;
if (!currentArtist) { if (!currentArtist) {
@ -1515,6 +1521,9 @@ function createReleaseCard(release) {
// Load tracks for the album (pass name/artist for Hydrabase support) // Load tracks for the album (pass name/artist for Hydrabase support)
const _aat2 = new URLSearchParams({ name: albumData.name || '', artist: currentArtist.name || '' }); const _aat2 = new URLSearchParams({ name: albumData.name || '', artist: currentArtist.name || '' });
if (currentArtist.source) {
_aat2.set('source', currentArtist.source);
}
const response = await fetch(`/api/album/${albumData.id}/tracks?${_aat2}`); const response = await fetch(`/api/album/${albumData.id}/tracks?${_aat2}`);
if (!response.ok) { if (!response.ok) {
throw new Error(`Failed to load album tracks: ${response.status}`); throw new Error(`Failed to load album tracks: ${response.status}`);
@ -1997,8 +2006,10 @@ async function openDiscographyModal() {
discography = { albums: data.albums || [], singles: data.singles || [] }; discography = { albums: data.albums || [], singles: data.singles || [] };
if (discography.albums.length > 0 || discography.singles.length > 0) { if (discography.albums.length > 0 || discography.singles.length > 0) {
artistsPageState.artistDiscography = discography; artistsPageState.artistDiscography = discography;
artistsPageState.sourceOverride = data.source || artistsPageState.sourceOverride || null;
// Use metadata source ID for the modal (needed for download API calls) // Use metadata source ID for the modal (needed for download API calls)
if (metadataArtistId) artist.id = metadataArtistId; if (metadataArtistId) artist.id = metadataArtistId;
artist.source = data.source || null;
artistsPageState.selectedArtist = artist; artistsPageState.selectedArtist = artist;
} else { } else {
discography = null; discography = null;
@ -6650,4 +6661,3 @@ async function updateLibraryWatchlistButtonStatus(artistId) {
} }
// ================================= // =================================

View file

@ -129,7 +129,18 @@ async function rehydrateArtistAlbumModal(virtualPlaylistId, playlistName, batchI
// Fetch the album tracks to get proper artist and album data // Fetch the album tracks to get proper artist and album data
try { try {
const response = await fetch(`/api/album/${albumId}/tracks`); const rehydrateProcess = activeDownloadProcesses[virtualPlaylistId];
const albumSource = rehydrateProcess?.source || rehydrateProcess?.artist?.source || rehydrateProcess?.album?.source || null;
const artistName = rehydrateProcess?.artist?.name || '';
const params = new URLSearchParams({
name: playlistName || '',
artist: artistName
});
if (albumSource) {
params.set('source', albumSource);
}
const response = await fetch(`/api/album/${albumId}/tracks?${params}`);
const data = await response.json(); const data = await response.json();
if (!data.success || !data.album || !data.tracks) { if (!data.success || !data.album || !data.tracks) {
@ -139,12 +150,17 @@ async function rehydrateArtistAlbumModal(virtualPlaylistId, playlistName, batchI
const album = data.album; const album = data.album;
const tracks = data.tracks; const tracks = data.tracks;
const source = data.source || tracks[0]?._source || albumSource || null;
// Extract artist info from the first track (all tracks should have same artist) // Extract artist info from the first track (all tracks should have same artist)
const artist = { const artist = {
id: artistId, id: artistId,
name: tracks[0].artists[0] // Use first artist name from first track name: tracks[0].artists[0], // Use first artist name from first track
source
}; };
if (source) {
album.source = source;
}
console.log(`✅ Retrieved album data: "${album.name}" by ${artist.name} (${tracks.length} tracks)`); console.log(`✅ Retrieved album data: "${album.name}" by ${artist.name} (${tracks.length} tracks)`);
@ -2536,4 +2552,3 @@ function _extractM3UTracks(tracks) {
} }
// ================================================================================== // ==================================================================================

View file

@ -2389,6 +2389,10 @@ async function confirmMatch() {
const artistId = currentMatchingData.selectedArtist.id; const artistId = currentMatchingData.selectedArtist.id;
const albumId = currentMatchingData.selectedAlbum.id; const albumId = currentMatchingData.selectedAlbum.id;
const _aat3 = new URLSearchParams({ name: currentMatchingData.selectedAlbum.name || '', artist: currentMatchingData.selectedArtist.name || '' }); const _aat3 = new URLSearchParams({ name: currentMatchingData.selectedAlbum.name || '', artist: currentMatchingData.selectedArtist.name || '' });
const albumSource = currentMatchingData.selectedAlbum?.source || currentMatchingData.selectedArtist?.source || null;
if (albumSource) {
_aat3.set('source', albumSource);
}
const tracksResponse = await fetch(`/api/album/${albumId}/tracks?${_aat3}`); const tracksResponse = await fetch(`/api/album/${albumId}/tracks?${_aat3}`);
if (!tracksResponse.ok) { if (!tracksResponse.ok) {
@ -7167,4 +7171,3 @@ function updateDbProgressUI(state) {
} }
// =================================================================== // ===================================================================