import { AlbumListItem, AlbumWithSongs, Artist, ArtistInfo, PlaylistListItem, PlaylistWithSongs, Song, } from '@app/models/music' import { AlbumID3Element, ArtistID3Element, ArtistInfo2Element, ChildElement, PlaylistElement, PlaylistWithSongsElement, } from '@app/subsonic/elements' import { GetArtistResponse } from '@app/subsonic/responses' import { GetState, SetState } from 'zustand' import { Store } from './store' export type MusicMapSlice = { mapChildToSong: (child: ChildElement, coverArt?: string) => Promise mapChildrenToSongs: (children: ChildElement[], coverArt?: string) => Promise mapArtistID3toArtist: (artist: ArtistID3Element) => Artist mapArtistInfo: ( artistResponse: GetArtistResponse, info: ArtistInfo2Element, topSongs: ChildElement[], ) => Promise mapAlbumID3toAlbumListItem: (album: AlbumID3Element) => AlbumListItem mapAlbumID3toAlbum: (album: AlbumID3Element) => AlbumListItem mapAlbumID3WithSongstoAlbumWithSongs: (album: AlbumID3Element, songs: ChildElement[]) => Promise mapPlaylistListItem: (playlist: PlaylistElement) => PlaylistListItem mapPlaylistWithSongs: (playlist: PlaylistWithSongsElement) => Promise } export const createMusicMapSlice = (set: SetState, get: GetState): MusicMapSlice => ({ mapChildToSong: async (child, coverArt) => { return { itemType: 'song', id: child.id, album: child.album, albumId: child.albumId, artist: child.artist, artistId: child.artistId, title: child.title, track: child.track, discNumber: child.discNumber, duration: child.duration, starred: child.starred, coverArt: coverArt || (await get().getAlbumCoverArt(child.albumId)), streamUri: get().buildStreamUri(child.id), } }, mapChildrenToSongs: async (children, coverArt) => { const albumIds = children.reduce((acc, val) => { if (val.albumId && !(val.albumId in acc)) { acc[val.albumId] = get().getAlbumCoverArt(val.albumId) } return acc }, {} as Record>) await Promise.all(Object.values(albumIds)) const songs: Song[] = [] for (const child of children) { songs.push(await get().mapChildToSong(child, coverArt || (await get().getAlbumCoverArt(child.albumId)))) } return songs }, mapArtistID3toArtist: artist => { return { itemType: 'artist', id: artist.id, name: artist.name, starred: artist.starred, coverArt: artist.coverArt, } }, mapArtistInfo: async (artistResponse, info, topSongs) => { const { artist, albums } = artistResponse const mappedAlbums = albums.map(get().mapAlbumID3toAlbum) return { ...get().mapArtistID3toArtist(artist), albums: mappedAlbums, smallImageUrl: info.smallImageUrl, largeImageUrl: info.largeImageUrl, topSongs: (await get().mapChildrenToSongs(topSongs)).slice(0, 5), } }, mapAlbumID3toAlbumListItem: album => { return { itemType: 'album', id: album.id, name: album.name, artist: album.artist, artistId: album.artistId, starred: album.starred, coverArt: album.coverArt, } }, mapAlbumID3toAlbum: album => { return { ...get().mapAlbumID3toAlbumListItem(album), coverArt: album.coverArt, year: album.year, } }, mapAlbumID3WithSongstoAlbumWithSongs: async (album, songs) => { return { ...get().mapAlbumID3toAlbum(album), songs: await get().mapChildrenToSongs(songs), } }, mapPlaylistListItem: playlist => { return { itemType: 'playlist', id: playlist.id, name: playlist.name, comment: playlist.comment, coverArt: playlist.coverArt, } }, mapPlaylistWithSongs: async playlist => { return { ...get().mapPlaylistListItem(playlist), songs: await get().mapChildrenToSongs(playlist.songs), coverArt: playlist.coverArt, } }, })