Add getMusicDirectory endpoint for folder-based browsing in Amperfy
This commit is contained in:
@@ -98,6 +98,110 @@ router.get('/getMusicFolders.view', authenticateSubsonic, async (req, res) => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get music directory (for browsing by folder structure)
|
||||||
|
router.get('/getMusicDirectory.view', authenticateSubsonic, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.query;
|
||||||
|
|
||||||
|
// Root folder - return all artists
|
||||||
|
if (id === '1') {
|
||||||
|
const artists = await all(`
|
||||||
|
SELECT DISTINCT artist
|
||||||
|
FROM tracks
|
||||||
|
ORDER BY artist
|
||||||
|
`);
|
||||||
|
|
||||||
|
let dirXml = '<directory id="1" name="Music Library">\n';
|
||||||
|
|
||||||
|
artists.forEach(artist => {
|
||||||
|
const artistId = crypto.createHash('md5').update(`artist-${artist.artist}`).digest('hex');
|
||||||
|
dirXml += ` <child id="${artistId}" parent="1" title="${escapeXml(artist.artist)}" isDir="true"/>\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
dirXml += '</directory>';
|
||||||
|
return sendSubsonicResponse(res, dirXml);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Artist folder - return albums for this artist
|
||||||
|
const artists = await all(`SELECT DISTINCT artist FROM tracks`);
|
||||||
|
let targetArtist = null;
|
||||||
|
|
||||||
|
for (const artist of artists) {
|
||||||
|
const testId = crypto.createHash('md5').update(`artist-${artist.artist}`).digest('hex');
|
||||||
|
if (testId === id) {
|
||||||
|
targetArtist = artist.artist;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetArtist) {
|
||||||
|
const albums = await all(`
|
||||||
|
SELECT DISTINCT album, album_artist, year,
|
||||||
|
(SELECT artwork_path FROM tracks t2 WHERE t2.album = tracks.album AND t2.artist = ? LIMIT 1) as artwork_path,
|
||||||
|
COUNT(*) as track_count
|
||||||
|
FROM tracks
|
||||||
|
WHERE artist = ?
|
||||||
|
GROUP BY album, album_artist
|
||||||
|
ORDER BY year DESC, album
|
||||||
|
`, [targetArtist, targetArtist]);
|
||||||
|
|
||||||
|
let dirXml = `<directory id="${id}" parent="1" name="${escapeXml(targetArtist)}">\n`;
|
||||||
|
|
||||||
|
albums.forEach(album => {
|
||||||
|
const albumId = crypto.createHash('md5').update(`album-${album.album}-${album.album_artist}`).digest('hex');
|
||||||
|
const coverArt = album.artwork_path ? albumId : '';
|
||||||
|
dirXml += ` <child id="${albumId}" parent="${id}" title="${escapeXml(album.album)}" `;
|
||||||
|
dirXml += `album="${escapeXml(album.album)}" artist="${escapeXml(targetArtist)}" `;
|
||||||
|
dirXml += `coverArt="${coverArt}" isDir="true"/>\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
dirXml += '</directory>';
|
||||||
|
return sendSubsonicResponse(res, dirXml);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Album folder - return tracks
|
||||||
|
const allAlbums = await all(`SELECT DISTINCT album, album_artist FROM tracks`);
|
||||||
|
let targetAlbum = null;
|
||||||
|
let targetAlbumArtist = null;
|
||||||
|
|
||||||
|
for (const album of allAlbums) {
|
||||||
|
const testId = crypto.createHash('md5').update(`album-${album.album}-${album.album_artist}`).digest('hex');
|
||||||
|
if (testId === id) {
|
||||||
|
targetAlbum = album.album;
|
||||||
|
targetAlbumArtist = album.album_artist;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetAlbum) {
|
||||||
|
const tracks = await all(`
|
||||||
|
SELECT * FROM tracks
|
||||||
|
WHERE album = ? AND album_artist = ?
|
||||||
|
ORDER BY disc_number, track_number, title
|
||||||
|
`, [targetAlbum, targetAlbumArtist]);
|
||||||
|
|
||||||
|
if (tracks.length === 0) {
|
||||||
|
return sendSubsonicError(res, 70, 'Album not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstTrack = tracks[0];
|
||||||
|
let dirXml = `<directory id="${id}" name="${escapeXml(targetAlbum)}">\n`;
|
||||||
|
|
||||||
|
tracks.forEach(track => {
|
||||||
|
dirXml += buildSongXml(track, req);
|
||||||
|
});
|
||||||
|
|
||||||
|
dirXml += '</directory>';
|
||||||
|
return sendSubsonicResponse(res, dirXml);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendSubsonicError(res, 70, 'Directory not found');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in getMusicDirectory:', error);
|
||||||
|
sendSubsonicError(res, 0, error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Get indexes (artists)
|
// Get indexes (artists)
|
||||||
router.get('/getIndexes.view', authenticateSubsonic, async (req, res) => {
|
router.get('/getIndexes.view', authenticateSubsonic, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user