mirror of
https://github.com/austinried/subtracks.git
synced 2026-02-10 15:02:42 +01:00
switched to new playlist w/songs
removed more unused stuff
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
import { selectMusic } from '@app/state/music'
|
|
||||||
import { Store, useStore, useStoreDeep } from '@app/state/store'
|
import { Store, useStore, useStoreDeep } from '@app/state/store'
|
||||||
import { useCallback, useEffect } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
|
|
||||||
@@ -15,32 +14,6 @@ export const useArtistInfo = (id: string) => {
|
|||||||
return artistInfo
|
return artistInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAlbumWithSongs = (id: string) => {
|
|
||||||
const album = useStore(useCallback((state: Store) => state.albumsWithSongs[id], [id]))
|
|
||||||
const fetchAlbum = useStore(selectMusic.fetchAlbumWithSongs)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!album) {
|
|
||||||
fetchAlbum(id)
|
|
||||||
}
|
|
||||||
}, [album, fetchAlbum, id])
|
|
||||||
|
|
||||||
return album
|
|
||||||
}
|
|
||||||
|
|
||||||
export const usePlaylistWithSongs = (id: string) => {
|
|
||||||
const playlist = useStore(useCallback((state: Store) => state.playlistsWithSongs[id], [id]))
|
|
||||||
const fetchPlaylist = useStore(selectMusic.fetchPlaylistWithSongs)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!playlist) {
|
|
||||||
fetchPlaylist(id)
|
|
||||||
}
|
|
||||||
}, [fetchPlaylist, id, playlist])
|
|
||||||
|
|
||||||
return playlist
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useStarred = (id: string, type: string) => {
|
export const useStarred = (id: string, type: string) => {
|
||||||
return useStore(
|
return useStore(
|
||||||
useCallback(
|
useCallback(
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ export interface Album extends AlbumListItem {
|
|||||||
year?: number
|
year?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AlbumWithSongs extends Album {
|
|
||||||
songs: Song[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SearchResults {
|
export interface SearchResults {
|
||||||
artists: Artist[]
|
artists: Artist[]
|
||||||
albums: AlbumListItem[]
|
albums: AlbumListItem[]
|
||||||
@@ -39,10 +35,6 @@ export interface PlaylistListItem {
|
|||||||
coverArt?: string
|
coverArt?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlaylistWithSongs extends PlaylistListItem {
|
|
||||||
songs: Song[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Song {
|
export interface Song {
|
||||||
itemType: 'song'
|
itemType: 'song'
|
||||||
id: string
|
id: string
|
||||||
@@ -62,6 +54,4 @@ export interface Song {
|
|||||||
|
|
||||||
export type ListableItem = Song | AlbumListItem | Artist | PlaylistListItem
|
export type ListableItem = Song | AlbumListItem | Artist | PlaylistListItem
|
||||||
|
|
||||||
export type HomeLists = { [key: string]: AlbumListItem[] }
|
|
||||||
|
|
||||||
export type StarrableItemType = 'song' | 'album' | 'artist'
|
export type StarrableItemType = 'song' | 'album' | 'artist'
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import ImageGradientFlatList from '@app/components/ImageGradientFlatList'
|
|||||||
import ListItem from '@app/components/ListItem'
|
import ListItem from '@app/components/ListItem'
|
||||||
import ListPlayerControls from '@app/components/ListPlayerControls'
|
import ListPlayerControls from '@app/components/ListPlayerControls'
|
||||||
import { useCoverArtFile } from '@app/hooks/cache'
|
import { useCoverArtFile } from '@app/hooks/cache'
|
||||||
import { usePlaylistWithSongs } from '@app/hooks/music'
|
|
||||||
import { Album, PlaylistListItem, Song } from '@app/models/music'
|
import { Album, PlaylistListItem, Song } from '@app/models/music'
|
||||||
import { useStore, useStoreDeep } from '@app/state/store'
|
import { useStore, useStoreDeep } from '@app/state/store'
|
||||||
import { selectTrackPlayer } from '@app/state/trackplayer'
|
import { selectTrackPlayer } from '@app/state/trackplayer'
|
||||||
@@ -128,16 +127,34 @@ const PlaylistView = React.memo<{
|
|||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
}>(({ id, title }) => {
|
}>(({ id, title }) => {
|
||||||
const playlist = usePlaylistWithSongs(id)
|
const playlist = useStoreDeep(useCallback(store => store.entities.playlists[id], [id]))
|
||||||
return <SongListDetails title={title} songList={playlist} subtitle={playlist?.comment} type="playlist" />
|
const songs = useStoreDeep(
|
||||||
|
useCallback(
|
||||||
|
store => {
|
||||||
|
const ids = store.entities.playlistSongs[id]
|
||||||
|
return ids ? ids.map(i => store.entities.songs[i]) : undefined
|
||||||
|
},
|
||||||
|
[id],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
const fetchPlaylist = useStore(store => store.fetchLibraryPlaylist)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!playlist || !songs) {
|
||||||
|
fetchPlaylist(id)
|
||||||
|
}
|
||||||
|
}, [playlist, fetchPlaylist, id, songs])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SongListDetails title={title} songList={playlist} songs={songs} subtitle={playlist?.comment} type="playlist" />
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const AlbumView = React.memo<{
|
const AlbumView = React.memo<{
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
}>(({ id, title }) => {
|
}>(({ id, title }) => {
|
||||||
// const album = useAlbumWithSongs(id)
|
|
||||||
|
|
||||||
const album = useStoreDeep(useCallback(store => store.entities.albums[id], [id]))
|
const album = useStoreDeep(useCallback(store => store.entities.albums[id], [id]))
|
||||||
const songs = useStoreDeep(
|
const songs = useStoreDeep(
|
||||||
useCallback(
|
useCallback(
|
||||||
|
|||||||
@@ -1,28 +1,10 @@
|
|||||||
import {
|
import { AlbumListItem, Artist, PlaylistListItem, SearchResults, StarrableItemType } from '@app/models/music'
|
||||||
AlbumListItem,
|
|
||||||
AlbumWithSongs,
|
|
||||||
Artist,
|
|
||||||
HomeLists,
|
|
||||||
PlaylistListItem,
|
|
||||||
PlaylistWithSongs,
|
|
||||||
SearchResults,
|
|
||||||
StarrableItemType,
|
|
||||||
} from '@app/models/music'
|
|
||||||
import { Store } from '@app/state/store'
|
import { Store } from '@app/state/store'
|
||||||
import { GetAlbumList2Params, GetAlbumList2TypeBase, Search3Params, StarParams } from '@app/subsonic/params'
|
import { GetAlbumList2Params, Search3Params, StarParams } from '@app/subsonic/params'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import { GetState, SetState } from 'zustand'
|
import { GetState, SetState } from 'zustand'
|
||||||
|
|
||||||
export type MusicSlice = {
|
export type MusicSlice = {
|
||||||
//
|
|
||||||
// family-style state
|
|
||||||
//
|
|
||||||
albumsWithSongs: { [id: string]: AlbumWithSongs }
|
|
||||||
fetchAlbumWithSongs: (id: string) => Promise<AlbumWithSongs | undefined>
|
|
||||||
|
|
||||||
playlistsWithSongs: { [id: string]: PlaylistWithSongs }
|
|
||||||
fetchPlaylistWithSongs: (id: string) => Promise<PlaylistWithSongs | undefined>
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// lists-style state
|
// lists-style state
|
||||||
//
|
//
|
||||||
@@ -36,11 +18,6 @@ export type MusicSlice = {
|
|||||||
offset?: number,
|
offset?: number,
|
||||||
) => Promise<SearchResults>
|
) => Promise<SearchResults>
|
||||||
|
|
||||||
homeLists: HomeLists
|
|
||||||
homeListsUpdating: boolean
|
|
||||||
fetchHomeLists: () => Promise<void>
|
|
||||||
clearHomeLists: () => void
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// actions, etc.
|
// actions, etc.
|
||||||
//
|
//
|
||||||
@@ -56,19 +33,11 @@ export type MusicSlice = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const selectMusic = {
|
export const selectMusic = {
|
||||||
fetchAlbumWithSongs: (state: Store) => state.fetchAlbumWithSongs,
|
|
||||||
fetchPlaylistWithSongs: (state: Store) => state.fetchPlaylistWithSongs,
|
|
||||||
|
|
||||||
fetchArtists: (store: MusicSlice) => store.fetchArtists,
|
fetchArtists: (store: MusicSlice) => store.fetchArtists,
|
||||||
fetchPlaylists: (store: MusicSlice) => store.fetchPlaylists,
|
fetchPlaylists: (store: MusicSlice) => store.fetchPlaylists,
|
||||||
fetchAlbums: (store: MusicSlice) => store.fetchAlbums,
|
fetchAlbums: (store: MusicSlice) => store.fetchAlbums,
|
||||||
fetchSearchResults: (store: MusicSlice) => store.fetchSearchResults,
|
fetchSearchResults: (store: MusicSlice) => store.fetchSearchResults,
|
||||||
|
|
||||||
homeLists: (store: MusicSlice) => store.homeLists,
|
|
||||||
homeListsUpdating: (store: MusicSlice) => store.homeListsUpdating,
|
|
||||||
fetchHomeLists: (store: MusicSlice) => store.fetchHomeLists,
|
|
||||||
clearHomeLists: (store: MusicSlice) => store.clearHomeLists,
|
|
||||||
|
|
||||||
starItem: (store: MusicSlice) => store.starItem,
|
starItem: (store: MusicSlice) => store.starItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,55 +55,6 @@ function reduceStarred(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const createMusicSlice = (set: SetState<Store>, get: GetState<Store>): MusicSlice => ({
|
export const createMusicSlice = (set: SetState<Store>, get: GetState<Store>): MusicSlice => ({
|
||||||
albumsWithSongs: {},
|
|
||||||
|
|
||||||
fetchAlbumWithSongs: async id => {
|
|
||||||
const client = get().client
|
|
||||||
if (!client) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await client.getAlbum({ id })
|
|
||||||
const album = await get().mapAlbumID3WithSongstoAlbumWithSongs(response.data.album, response.data.songs)
|
|
||||||
|
|
||||||
set(
|
|
||||||
produce<MusicSlice>(state => {
|
|
||||||
state.albumsWithSongs[id] = album
|
|
||||||
state.starredSongs = reduceStarred(state.starredSongs, album.songs)
|
|
||||||
state.starredAlbums = reduceStarred(state.starredAlbums, [album])
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
return album
|
|
||||||
} catch {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
playlistsWithSongs: {},
|
|
||||||
|
|
||||||
fetchPlaylistWithSongs: async id => {
|
|
||||||
const client = get().client
|
|
||||||
if (!client) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await client.getPlaylist({ id })
|
|
||||||
const playlist = await get().mapPlaylistWithSongs(response.data.playlist)
|
|
||||||
|
|
||||||
set(
|
|
||||||
produce<MusicSlice>(state => {
|
|
||||||
state.playlistsWithSongs[id] = playlist
|
|
||||||
state.starredSongs = reduceStarred(state.starredSongs, playlist.songs)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
return playlist
|
|
||||||
} catch {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchArtists: async () => {
|
fetchArtists: async () => {
|
||||||
const client = get().client
|
const client = get().client
|
||||||
if (!client) {
|
if (!client) {
|
||||||
@@ -270,50 +190,6 @@ export const createMusicSlice = (set: SetState<Store>, get: GetState<Store>): Mu
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
homeLists: {},
|
|
||||||
homeListsUpdating: false,
|
|
||||||
|
|
||||||
fetchHomeLists: async () => {
|
|
||||||
const client = get().client
|
|
||||||
if (!client) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get().homeListsUpdating) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set({ homeListsUpdating: true })
|
|
||||||
|
|
||||||
const types = get().settings.screens.home.lists
|
|
||||||
|
|
||||||
try {
|
|
||||||
const promises: Promise<any>[] = []
|
|
||||||
for (const type of types) {
|
|
||||||
promises.push(
|
|
||||||
client
|
|
||||||
.getAlbumList2({ type: type as GetAlbumList2TypeBase, size: 20 })
|
|
||||||
.then(response => {
|
|
||||||
const list = response.data.albums.map(get().mapAlbumID3toAlbumListItem)
|
|
||||||
set(
|
|
||||||
produce<MusicSlice>(state => {
|
|
||||||
state.homeLists[type] = list
|
|
||||||
state.starredAlbums = reduceStarred(state.starredAlbums, state.homeLists[type])
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.catch(() => {}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
await Promise.all(promises)
|
|
||||||
} finally {
|
|
||||||
set({ homeListsUpdating: false })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
clearHomeLists: () => {
|
|
||||||
set({ homeLists: {} })
|
|
||||||
},
|
|
||||||
|
|
||||||
starredSongs: {},
|
starredSongs: {},
|
||||||
starredAlbums: {},
|
starredAlbums: {},
|
||||||
starredArtists: {},
|
starredArtists: {},
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import { AlbumListItem, AlbumWithSongs, Artist, PlaylistListItem, PlaylistWithSongs, Song } from '@app/models/music'
|
import { AlbumListItem, Artist, PlaylistListItem, Song } from '@app/models/music'
|
||||||
import {
|
import { AlbumID3Element, ArtistID3Element, ChildElement, PlaylistElement } from '@app/subsonic/elements'
|
||||||
AlbumID3Element,
|
|
||||||
ArtistID3Element,
|
|
||||||
ChildElement,
|
|
||||||
PlaylistElement,
|
|
||||||
PlaylistWithSongsElement,
|
|
||||||
} from '@app/subsonic/elements'
|
|
||||||
import { GetState, SetState } from 'zustand'
|
import { GetState, SetState } from 'zustand'
|
||||||
import { Store } from './store'
|
import { Store } from './store'
|
||||||
|
|
||||||
@@ -15,9 +9,7 @@ export type MusicMapSlice = {
|
|||||||
mapArtistID3toArtist: (artist: ArtistID3Element) => Artist
|
mapArtistID3toArtist: (artist: ArtistID3Element) => Artist
|
||||||
mapAlbumID3toAlbumListItem: (album: AlbumID3Element) => AlbumListItem
|
mapAlbumID3toAlbumListItem: (album: AlbumID3Element) => AlbumListItem
|
||||||
mapAlbumID3toAlbum: (album: AlbumID3Element) => AlbumListItem
|
mapAlbumID3toAlbum: (album: AlbumID3Element) => AlbumListItem
|
||||||
mapAlbumID3WithSongstoAlbumWithSongs: (album: AlbumID3Element, songs: ChildElement[]) => Promise<AlbumWithSongs>
|
|
||||||
mapPlaylistListItem: (playlist: PlaylistElement) => PlaylistListItem
|
mapPlaylistListItem: (playlist: PlaylistElement) => PlaylistListItem
|
||||||
mapPlaylistWithSongs: (playlist: PlaylistWithSongsElement) => Promise<PlaylistWithSongs>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createMusicMapSlice = (set: SetState<Store>, get: GetState<Store>): MusicMapSlice => ({
|
export const createMusicMapSlice = (set: SetState<Store>, get: GetState<Store>): MusicMapSlice => ({
|
||||||
@@ -86,13 +78,6 @@ export const createMusicMapSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mapAlbumID3WithSongstoAlbumWithSongs: async (album, songs) => {
|
|
||||||
return {
|
|
||||||
...get().mapAlbumID3toAlbum(album),
|
|
||||||
songs: await get().mapChildrenToSongs(songs),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mapPlaylistListItem: playlist => {
|
mapPlaylistListItem: playlist => {
|
||||||
return {
|
return {
|
||||||
itemType: 'playlist',
|
itemType: 'playlist',
|
||||||
@@ -102,12 +87,4 @@ export const createMusicMapSlice = (set: SetState<Store>, get: GetState<Store>):
|
|||||||
coverArt: playlist.coverArt,
|
coverArt: playlist.coverArt,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mapPlaylistWithSongs: async playlist => {
|
|
||||||
return {
|
|
||||||
...get().mapPlaylistListItem(playlist),
|
|
||||||
songs: await get().mapChildrenToSongs(playlist.songs),
|
|
||||||
coverArt: playlist.coverArt,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user