diff --git a/webui/static/script.js b/webui/static/script.js
index 492997d9..dcac7ea3 100644
--- a/webui/static/script.js
+++ b/webui/static/script.js
@@ -7112,18 +7112,22 @@ function formatArtists(artists) {
if (!artists || !Array.isArray(artists)) {
return 'Unknown Artist';
}
-
+
// Handle both string arrays and object arrays with 'name' property
const artistNames = artists.map(artist => {
+ let artistName;
if (typeof artist === 'string') {
- return artist;
+ artistName = artist;
} else if (artist && typeof artist === 'object' && artist.name) {
- return artist.name;
+ artistName = artist.name;
} else {
- return 'Unknown Artist';
+ artistName = 'Unknown Artist';
}
+
+ // Clean featured artists from the name
+ return cleanArtistName(artistName);
});
-
+
return artistNames.join(', ') || 'Unknown Artist';
}
@@ -26661,6 +26665,31 @@ async function loadListenBrainzPlaylistTracks(identifier, playlistId) {
}
}
+/**
+ * Clean artist name by removing featured artists
+ * e.g., "Blackstreet feat. Dr. Dre & Queen Pen" -> "Blackstreet"
+ */
+function cleanArtistName(artistName) {
+ if (!artistName) return artistName;
+
+ // Remove everything after common featuring patterns (case insensitive)
+ const patterns = [
+ /\s+feat\.?\s+.*/i, // "feat." or "feat"
+ /\s+featuring\s+.*/i, // "featuring"
+ /\s+ft\.?\s+.*/i, // "ft." or "ft"
+ /\s+with\s+.*/i, // "with"
+ /\s+\&\s+.*/, // " & " (if it appears without feat/ft)
+ /\s+x\s+.*/i // " x " (common in collaborations)
+ ];
+
+ let cleaned = artistName;
+ for (const pattern of patterns) {
+ cleaned = cleaned.replace(pattern, '');
+ }
+
+ return cleaned.trim();
+}
+
function displayListenBrainzTracks(tracks, playlistId) {
const playlistContainer = document.getElementById(`${playlistId}-playlist`);
if (!playlistContainer) return;
@@ -26700,7 +26729,7 @@ function displayListenBrainzTracks(tracks, playlistId) {
${escapeHtml(track.track_name || 'Unknown Track')}
-
${escapeHtml(track.artist_name || 'Unknown Artist')}
+
${escapeHtml(cleanArtistName(track.artist_name) || 'Unknown Artist')}
${albumName}
${duration}
@@ -26731,7 +26760,7 @@ async function startListenBrainzPlaylistSync(identifier, title, playlistId) {
const spotifyTracks = tracks.map(track => ({
id: null, // No Spotify ID for ListenBrainz tracks
name: track.track_name,
- artists: [track.artist_name], // Array of strings for sync compatibility
+ artists: [cleanArtistName(track.artist_name)], // Clean featured artists, array of strings for sync compatibility
album: {
name: track.album_name,
images: track.album_cover_url ? [{ url: track.album_cover_url }] : []
@@ -26867,7 +26896,7 @@ async function openDownloadModalForListenBrainzPlaylist(identifier, title) {
const spotifyTracks = tracks.map(track => ({
id: null, // No Spotify ID for ListenBrainz tracks
name: track.track_name,
- artists: [track.artist_name],
+ artists: [cleanArtistName(track.artist_name)], // Clean featured artists
album: {
name: track.album_name,
images: track.album_cover_url ? [{ url: track.album_cover_url }] : []
@@ -26916,7 +26945,7 @@ async function openListenBrainzPlaylist(playlistMbid, playlistName) {
const spotifyTracks = tracks.map(track => ({
id: track.recording_mbid || '',
name: track.title || 'Unknown',
- artists: [track.creator || 'Unknown'],
+ artists: [cleanArtistName(track.creator || 'Unknown')], // Clean featured artists
album: {
name: track.album || 'Unknown Album',
images: []
@@ -28514,7 +28543,7 @@ async function rehydrateDiscoverDownloadModal(playlistId) {
const spotifyTracks = tracks.map(track => ({
id: null,
name: track.track_name,
- artists: [track.artist_name],
+ artists: [cleanArtistName(track.artist_name)], // Clean featured artists
album: {
name: track.album_name,
images: track.album_cover_url ? [{ url: track.album_cover_url }] : []