diff --git a/backend/novasonic-server.js b/backend/novasonic-server.js index 5004cb4..58c98eb 100644 --- a/backend/novasonic-server.js +++ b/backend/novasonic-server.js @@ -56,6 +56,16 @@ function sanitize(s) { return (s || 'Unknown').replace(/[\\/:*?"<>|]/g, '_').trim().slice(0, 100); } +// Convert "Artist feat. B" / "Artist ft. B" / "Artist featuring B" → "Artist / B" +// so Navidrome splits on "/" and lists each as a separate artist +function navidromeArtist(name) { + if (!name) return name; + return name + .replace(/\s+feat\.?\s+/gi, ' / ') + .replace(/\s+ft\.?\s+/gi, ' / ') + .replace(/\s+featuring\s+/gi, ' / '); +} + function updateJob(id, update) { const job = jobs.get(id); if (job) jobs.set(id, { ...job, ...update, updatedAt: Date.now() }); @@ -179,7 +189,7 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t '-map_metadata', '-1', // strip all existing tags (removes blurry YT thumbnail) '-id3v2_version', '3', '-metadata', `title=${title}`, - '-metadata', `artist=${artist}`, + '-metadata', `artist=${navidromeArtist(artist)}`, '-metadata', `album_artist=${mainArtist}`, ); if (album) ffArgs.push('-metadata', `album=${album}`);