koel/resources/assets/js/stores/albumStore.ts

97 lines
2.7 KiB
TypeScript
Raw Normal View History

2022-07-24 11:47:18 +00:00
import { reactive, UnwrapNestedRefs } from 'vue'
import { differenceBy, merge, unionBy } from 'lodash'
import { cache, http } from '@/services'
2022-07-24 11:47:18 +00:00
import { arrayify, logger } from '@/utils'
2022-06-10 10:47:46 +00:00
import { songStore } from '@/stores'
2022-04-15 14:24:30 +00:00
const UNKNOWN_ALBUM_ID = 1
export const albumStore = {
2024-07-05 12:20:30 +00:00
vault: new Map<Album['id'], Album>(),
2022-04-15 14:24:30 +00:00
2022-06-10 10:47:46 +00:00
state: reactive({
albums: [] as Album[]
2022-04-21 09:38:24 +00:00
}),
2022-04-15 14:24:30 +00:00
2024-07-05 12:20:30 +00:00
byId (id: Album['id']) {
2022-06-10 10:47:46 +00:00
return this.vault.get(id)
2022-04-15 14:24:30 +00:00
},
2024-07-05 12:20:30 +00:00
removeByIds (ids: Album['id'][]) {
2022-07-22 21:56:13 +00:00
this.state.albums = differenceBy(this.state.albums, ids.map(id => this.byId(id)), 'id')
ids.forEach(id => {
this.vault.delete(id)
cache.remove(['album', id])
})
2022-04-15 14:24:30 +00:00
},
2024-07-05 12:20:30 +00:00
isUnknown: (album: Album | Album['id']) => {
2022-07-22 21:56:13 +00:00
if (typeof album === 'number') return album === UNKNOWN_ALBUM_ID
return album.id === UNKNOWN_ALBUM_ID
},
2024-07-05 12:20:30 +00:00
syncWithVault (albums: MaybeArray<Album>) {
2022-07-22 21:56:13 +00:00
return arrayify(albums).map(album => {
let local = this.vault.get(album.id)
local = reactive(local ? merge(local, album) : album)
this.vault.set(album.id, local)
return local
})
},
2022-06-10 10:47:46 +00:00
/**
* Upload a cover for an album.
*
* @param {Album} album The album object
* @param {string} cover The content data string of the cover
*/
async uploadCover (album: Album, cover: string) {
2024-02-24 15:37:01 +00:00
album.cover = (await http.put<{ cover_url: string }>(`albums/${album.id}/cover`, { cover })).cover_url
2022-06-10 10:47:46 +00:00
songStore.byAlbum(album).forEach(song => song.album_cover = album.cover)
// sync to vault
this.byId(album.id)!.cover = album.cover
2022-06-10 10:47:46 +00:00
return album.cover
2022-04-15 14:24:30 +00:00
},
2022-06-10 10:47:46 +00:00
/**
* Fetch the (blurry) thumbnail-sized version of an album's cover.
*/
2024-07-05 12:20:30 +00:00
fetchThumbnail: async (id: Album['id']) => {
2024-02-24 15:37:01 +00:00
return (await http.get<{ thumbnailUrl: string }>(`albums/${id}/thumbnail`)).thumbnailUrl
2022-04-15 14:24:30 +00:00
},
2024-07-05 12:20:30 +00:00
async resolve (id: Album['id']) {
2022-06-10 10:47:46 +00:00
let album = this.byId(id)
2022-04-15 14:24:30 +00:00
2022-06-10 10:47:46 +00:00
if (!album) {
2022-07-24 11:47:18 +00:00
try {
album = this.syncWithVault(
await cache.remember<Album>(['album', id], async () => await http.get<Album>(`albums/${id}`))
2022-07-24 11:47:18 +00:00
)[0]
} catch (error: unknown) {
logger.error(error)
2022-07-24 11:47:18 +00:00
}
2022-04-15 14:24:30 +00:00
}
2022-06-10 10:47:46 +00:00
return album
2022-04-15 14:24:30 +00:00
},
2022-07-22 21:56:13 +00:00
async paginate (page: number) {
2024-07-05 10:04:31 +00:00
const resource = await http.get<PaginatorResource<Album>>(`albums?page=${page}`)
2022-07-22 21:56:13 +00:00
this.state.albums = unionBy(this.state.albums, this.syncWithVault(resource.data), 'id')
2022-04-15 14:24:30 +00:00
2022-06-10 10:47:46 +00:00
return resource.links.next ? ++resource.meta.current_page : null
},
2024-07-05 12:20:30 +00:00
async fetchForArtist (artist: Artist | Artist['id']) {
const id = typeof artist === 'number' ? artist : artist.id
return this.syncWithVault(
await cache.remember<Album[]>(['artist-albums', id], async () => await http.get<Album[]>(`artists/${id}/albums`))
)
2022-06-10 10:47:46 +00:00
}
2022-04-15 14:24:30 +00:00
}