Fix source artist detail navigation from discover modals
Preserve source metadata for seasonal and cached discover album modals so artist links use real provider IDs instead of falling back to library/name routes. Treat source-only artist detail discographies as clickable missing releases and skip library-only ownership/enhancement checks.
This commit is contained in:
parent
3a4017ea2b
commit
a6282b3009
4 changed files with 89 additions and 20 deletions
|
|
@ -707,7 +707,8 @@ class SeasonalDiscoveryService:
|
|||
artist_name,
|
||||
album_cover_url,
|
||||
release_date,
|
||||
popularity
|
||||
popularity,
|
||||
source
|
||||
FROM seasonal_albums
|
||||
WHERE season_key = ? AND source = ?
|
||||
ORDER BY popularity DESC, album_name ASC
|
||||
|
|
|
|||
|
|
@ -3945,6 +3945,35 @@ function hideSeasonalSections() {
|
|||
}
|
||||
}
|
||||
|
||||
function _buildDiscoverArtistContext(source, artistName, sourceData = {}, albumData = {}) {
|
||||
const normalizedSource = (source || '').toString().toLowerCase();
|
||||
const albumArtist = Array.isArray(albumData.artists) ? albumData.artists[0] : null;
|
||||
const activeSource = (source || sourceData.active_source || sourceData.source || '').toString().toLowerCase();
|
||||
const context = {
|
||||
...sourceData,
|
||||
id: sourceData.active_source_id || sourceData.artist_id || albumArtist?.id || '',
|
||||
name: artistName || sourceData.artist_name || sourceData.name || albumArtist?.name || '',
|
||||
source: normalizedSource || activeSource || '',
|
||||
spotify_artist_id: sourceData.spotify_artist_id || sourceData.artist_spotify_id || ((normalizedSource || activeSource) === 'spotify' ? albumArtist?.id : '') || '',
|
||||
itunes_artist_id: sourceData.itunes_artist_id || sourceData.artist_itunes_id || ((normalizedSource || activeSource) === 'itunes' ? albumArtist?.id : '') || '',
|
||||
deezer_artist_id: sourceData.deezer_artist_id || sourceData.artist_deezer_id || sourceData.deezer_id || ((normalizedSource || activeSource) === 'deezer' ? albumArtist?.id : '') || '',
|
||||
discogs_artist_id: sourceData.discogs_artist_id || sourceData.artist_discogs_id || sourceData.discogs_id || '',
|
||||
amazon_artist_id: sourceData.amazon_artist_id || sourceData.artist_amazon_id || sourceData.amazon_id || '',
|
||||
soul_id: sourceData.soul_id || sourceData.hydrabase_artist_id || '',
|
||||
};
|
||||
|
||||
const sourceIdBySource = {
|
||||
spotify: context.spotify_artist_id,
|
||||
itunes: context.itunes_artist_id,
|
||||
deezer: context.deezer_artist_id,
|
||||
discogs: context.discogs_artist_id,
|
||||
amazon: context.amazon_artist_id,
|
||||
hydrabase: context.soul_id,
|
||||
};
|
||||
context.id = sourceIdBySource[normalizedSource || activeSource] || context.id;
|
||||
return context;
|
||||
}
|
||||
|
||||
async function openDownloadModalForSeasonalAlbum(albumIndex) {
|
||||
const album = discoverSeasonalAlbums[albumIndex];
|
||||
if (!album) {
|
||||
|
|
@ -4004,14 +4033,12 @@ async function openDownloadModalForSeasonalAlbum(albumIndex) {
|
|||
const virtualPlaylistId = `seasonal_album_${albumId}`;
|
||||
|
||||
// Pass proper artist/album context for album download (1 worker + source reuse)
|
||||
const artistContext = {
|
||||
name: album.artist_name,
|
||||
source: source
|
||||
};
|
||||
const artistContext = _buildDiscoverArtistContext(source, album.artist_name, album, albumData);
|
||||
|
||||
const albumContext = {
|
||||
id: albumData.id,
|
||||
name: albumData.name,
|
||||
source: source,
|
||||
album_type: albumData.album_type || 'album',
|
||||
total_tracks: albumData.total_tracks || 0,
|
||||
release_date: albumData.release_date || '',
|
||||
|
|
@ -6986,7 +7013,7 @@ async function openCacheDiscoverAlbum(sectionKey, index) {
|
|||
duration_ms: track.duration_ms || 0, track_number: track.track_number || 0,
|
||||
};
|
||||
});
|
||||
const artistContext = { id: albumData.artists?.[0]?.id || '', name: artistName, source: resolvedSource };
|
||||
const artistContext = _buildDiscoverArtistContext(resolvedSource, artistName, item, albumData);
|
||||
const albumContext = { id: albumData.id, name: albumData.name, album_type: albumData.album_type || 'album', total_tracks: albumData.total_tracks || 0, release_date: albumData.release_date || '', images: albumData.images || [] };
|
||||
await openDownloadMissingModalForYouTube(`discover_cache_${resolvedId}`, albumData.name, spotifyTracks, artistContext, albumContext);
|
||||
hideLoadingOverlay();
|
||||
|
|
@ -7046,11 +7073,7 @@ async function openCacheDiscoverAlbum(sectionKey, index) {
|
|||
};
|
||||
});
|
||||
|
||||
const artistContext = {
|
||||
id: albumData.artists?.[0]?.id || '',
|
||||
name: item.artist_name || albumData.artists?.[0]?.name || '',
|
||||
source: source,
|
||||
};
|
||||
const artistContext = _buildDiscoverArtistContext(source, item.artist_name || albumData.artists?.[0]?.name || '', item, albumData);
|
||||
const albumContext = {
|
||||
id: albumData.id,
|
||||
name: albumData.name,
|
||||
|
|
@ -7970,11 +7993,7 @@ async function openDownloadModalForRecentAlbum(albumIndex) {
|
|||
const virtualPlaylistId = `discover_album_${albumId}`;
|
||||
|
||||
// CRITICAL FIX: Pass proper artist/album context for modal display
|
||||
const artistContext = {
|
||||
id: source === 'spotify' ? album.artist_spotify_id : source === 'deezer' ? album.artist_deezer_id : album.artist_itunes_id,
|
||||
name: album.artist_name,
|
||||
source: source
|
||||
};
|
||||
const artistContext = _buildDiscoverArtistContext(source, album.artist_name, album, albumData);
|
||||
|
||||
const albumContext = {
|
||||
id: albumData.id,
|
||||
|
|
|
|||
|
|
@ -501,7 +501,10 @@ async function openDownloadMissingModalForYouTube(virtualPlaylistId, playlistNam
|
|||
const heroContext = isDiscoverAlbum && album && artist ? {
|
||||
type: 'album',
|
||||
artist: {
|
||||
...artist,
|
||||
name: artist.name,
|
||||
id: artist.id || artist.artist_id || null,
|
||||
source: artist.source || album.source || null,
|
||||
image_url: artist.image_url || null
|
||||
},
|
||||
album: {
|
||||
|
|
@ -634,9 +637,42 @@ function _navigateToArtistFromModal(artistId, artistName, imageUrl, source, play
|
|||
if (!artistName) return;
|
||||
// Close the download modal
|
||||
const process = playlistId ? activeDownloadProcesses[playlistId] : null;
|
||||
const resolvedSource = source || process?.artist?.source || process?.album?.source || process?.source || null;
|
||||
const artistContext = process?.artist || {};
|
||||
const inferredSource = artistContext.spotify_artist_id ? 'spotify'
|
||||
: artistContext.itunes_artist_id ? 'itunes'
|
||||
: (artistContext.deezer_artist_id || artistContext.deezer_id) ? 'deezer'
|
||||
: (artistContext.discogs_artist_id || artistContext.discogs_id) ? 'discogs'
|
||||
: (artistContext.amazon_artist_id || artistContext.amazon_id) ? 'amazon'
|
||||
: (artistContext.soul_id || artistContext.hydrabase_artist_id) ? 'hydrabase'
|
||||
: null;
|
||||
const resolvedSource = source || process?.artist?.source || process?.album?.source || process?.source || inferredSource;
|
||||
const sourceKey = (resolvedSource || '').toString().toLowerCase();
|
||||
const sourceIdFields = {
|
||||
spotify: ['spotify_artist_id', 'id', 'artist_id'],
|
||||
itunes: ['itunes_artist_id', 'artist_id', 'id'],
|
||||
deezer: ['deezer_artist_id', 'deezer_id', 'artist_id', 'id'],
|
||||
discogs: ['discogs_artist_id', 'discogs_id', 'artist_id', 'id'],
|
||||
amazon: ['amazon_artist_id', 'amazon_id', 'artist_id', 'id'],
|
||||
hydrabase: ['soul_id', 'hydrabase_artist_id', 'artist_id', 'id'],
|
||||
musicbrainz: ['musicbrainz_id', 'artist_id', 'id'],
|
||||
};
|
||||
let resolvedArtistId = artistId;
|
||||
for (const field of (sourceIdFields[sourceKey] || ['artist_id', 'id'])) {
|
||||
const candidate = artistContext?.[field];
|
||||
if (candidate) {
|
||||
resolvedArtistId = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (resolvedArtistId && String(resolvedArtistId).toLowerCase() === String(artistName).toLowerCase()) {
|
||||
resolvedArtistId = null;
|
||||
}
|
||||
if (playlistId) closeDownloadMissingModal(playlistId);
|
||||
navigateToArtistDetail(artistId || artistName, artistName, resolvedSource || null);
|
||||
if (!resolvedArtistId || !resolvedSource) {
|
||||
showToast(`Artist details are not available for ${artistName}`, 'warning');
|
||||
return;
|
||||
}
|
||||
navigateToArtistDetail(resolvedArtistId, artistName, resolvedSource);
|
||||
}
|
||||
|
||||
async function closeDownloadMissingModal(playlistId) {
|
||||
|
|
|
|||
|
|
@ -1042,6 +1042,17 @@ async function loadArtistDetailData(artistId, artistName) {
|
|||
throw new Error(data.error || 'Failed to load artist data');
|
||||
}
|
||||
|
||||
const isSourceOnlyArtist = !data.artist?.server_source;
|
||||
if (isSourceOnlyArtist && data.discography) {
|
||||
for (const bucket of ['albums', 'eps', 'singles']) {
|
||||
for (const release of (data.discography[bucket] || [])) {
|
||||
if (release.owned === null || typeof release.owned === 'undefined') {
|
||||
release.owned = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Loaded artist detail data:`, data);
|
||||
|
||||
// Hide loading and show all content
|
||||
|
|
@ -1077,7 +1088,7 @@ async function loadArtistDetailData(artistId, artistName) {
|
|||
renderArtistEnrichmentCoverage(data.enrichment_coverage);
|
||||
|
||||
// Start streaming ownership checks if we have Spotify discography with checking state
|
||||
if (data.discography && data.discography.albums) {
|
||||
if (!isSourceOnlyArtist && data.discography && data.discography.albums) {
|
||||
const hasChecking = [...(data.discography.albums || []), ...(data.discography.eps || []), ...(data.discography.singles || [])]
|
||||
.some(r => r.owned === null);
|
||||
if (hasChecking) {
|
||||
|
|
@ -1091,7 +1102,9 @@ async function loadArtistDetailData(artistId, artistName) {
|
|||
// Use currentArtistId (not the closure arg) because the library-upgrade
|
||||
// branch above may have rewritten it from the source ID to the library PK,
|
||||
// and /api/library/artist/<id>/quality-analysis only works on library PKs.
|
||||
if (!isSourceOnlyArtist) {
|
||||
checkArtistEnhanceEligibility(artistDetailPageState.currentArtistId);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Error loading artist detail data:`, error);
|
||||
|
|
|
|||
Loading…
Reference in a new issue