diff --git a/src/routes/subsonic.js b/src/routes/subsonic.js index 0c91ff8..113aabe 100644 --- a/src/routes/subsonic.js +++ b/src/routes/subsonic.js @@ -208,6 +208,49 @@ router.get('/getMusicDirectory.view', authenticateSubsonic, async (req, res) => } }); +// Get artists (ID3 tags) +router.get('/getArtists.view', authenticateSubsonic, async (req, res) => { + try { + const artists = await all(` + SELECT DISTINCT artist, COUNT(DISTINCT album) as album_count + FROM tracks + GROUP BY artist + ORDER BY artist + `); + + // Group by first letter + const grouped = {}; + artists.forEach(artist => { + const firstChar = (artist.artist || 'Unknown')[0].toUpperCase(); + const letter = /[A-Z]/.test(firstChar) ? firstChar : '#'; + if (!grouped[letter]) grouped[letter] = []; + + const artistId = crypto.createHash('md5').update(`artist-${artist.artist}`).digest('hex'); + grouped[letter].push({ + id: artistId, + name: artist.artist, + albumCount: artist.album_count + }); + }); + + let artistsXml = '\n'; + + Object.keys(grouped).sort().forEach(letter => { + artistsXml += ` \n`; + grouped[letter].forEach(artist => { + artistsXml += ` \n`; + }); + artistsXml += ` \n`; + }); + + artistsXml += ''; + + sendSubsonicResponse(res, artistsXml); + } catch (error) { + sendSubsonicError(res, 0, error.message); + } +}); + // Get indexes (artists) router.get('/getIndexes.view', authenticateSubsonic, async (req, res) => { try {