mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
Bugfix/large playlist crash (#111)
* get all song coverArt as they are rendered doing it all up front was too heavy temporarily disabled mapping artwork in setQueue, need to fix this * use cache data for track artwork when available * fix round art in context menu for songs * set only the first artwork at play time then set the rest in the playback service * handle both cached images and fetching images * remove commented code * fix shuffle fix first thumbnail not being updated on shuffle for now playing background
This commit is contained in:
+150
-3
@@ -1,8 +1,14 @@
|
||||
import { getCurrentTrack, getPlayerState, trackPlayerCommands } from '@app/state/trackplayer'
|
||||
import TrackPlayer, { Event, State } from 'react-native-track-player'
|
||||
import { useStore } from './state/store'
|
||||
import { unstable_batchedUpdates } from 'react-native'
|
||||
import NetInfo, { NetInfoStateType } from '@react-native-community/netinfo'
|
||||
import _ from 'lodash'
|
||||
import { unstable_batchedUpdates } from 'react-native'
|
||||
import TrackPlayer, { Event, State } from 'react-native-track-player'
|
||||
import { fetchAlbum, FetchExisingFileOptions, fetchExistingFile, fetchFile, FetchFileOptions } from './hooks/fetch'
|
||||
import qk from './hooks/queryKeys'
|
||||
import queryClient from './queryClient'
|
||||
import queueService from './queueservice'
|
||||
import { useStore } from './state/store'
|
||||
import { ReturnedPromiseResolvedType } from './util/types'
|
||||
|
||||
const reset = () => {
|
||||
unstable_batchedUpdates(() => {
|
||||
@@ -34,12 +40,81 @@ const rebuildQueue = (forcePlay?: boolean) => {
|
||||
})
|
||||
}
|
||||
|
||||
const updateQueue = () => {
|
||||
unstable_batchedUpdates(() => {
|
||||
useStore.getState().updateQueue()
|
||||
})
|
||||
}
|
||||
|
||||
const setDuckPaused = (duckPaused: boolean) => {
|
||||
unstable_batchedUpdates(() => {
|
||||
useStore.getState().setDuckPaused(duckPaused)
|
||||
})
|
||||
}
|
||||
|
||||
const setQueryDataAlbum = (queryKey: any, data: ReturnedPromiseResolvedType<typeof fetchAlbum>) => {
|
||||
unstable_batchedUpdates(() => {
|
||||
queryClient.setQueryData(queryKey, data)
|
||||
})
|
||||
}
|
||||
|
||||
const setQueryDataExistingFiles = (queryKey: any, data: ReturnedPromiseResolvedType<typeof fetchExistingFile>) => {
|
||||
unstable_batchedUpdates(() => {
|
||||
queryClient.setQueryData(queryKey, data)
|
||||
})
|
||||
}
|
||||
|
||||
const setQueryDataCoverArt = (queryKey: any, data: ReturnedPromiseResolvedType<typeof fetchFile>) => {
|
||||
unstable_batchedUpdates(() => {
|
||||
queryClient.setQueryData(queryKey, data)
|
||||
})
|
||||
}
|
||||
|
||||
function getClient() {
|
||||
const client = useStore.getState().client
|
||||
if (!client) {
|
||||
throw new Error('no client!')
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
async function getAlbum(id: string) {
|
||||
try {
|
||||
const res = await fetchAlbum(id, getClient())
|
||||
setQueryDataAlbum(qk.album(id), res)
|
||||
return res
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function getCoverArtThumbExisting(coverArt: string) {
|
||||
const serverId = useStore.getState().settings.activeServerId
|
||||
const options: FetchExisingFileOptions = { itemType: 'coverArtThumb', itemId: coverArt }
|
||||
|
||||
try {
|
||||
const res = await fetchExistingFile(options, serverId)
|
||||
setQueryDataExistingFiles(qk.existingFiles(options.itemType, options.itemId), res)
|
||||
return res
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function getCoverArtThumb(coverArt: string) {
|
||||
const serverId = useStore.getState().settings.activeServerId
|
||||
const fromUrl = getClient().getCoverArtUri({ id: coverArt, size: '256' })
|
||||
const options: FetchFileOptions = {
|
||||
itemType: 'coverArtThumb',
|
||||
itemId: coverArt,
|
||||
fromUrl,
|
||||
expectedContentType: 'image',
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetchFile(options, serverId)
|
||||
setQueryDataCoverArt(qk.coverArt(coverArt, 'thumbnail'), res)
|
||||
return res
|
||||
} catch {}
|
||||
}
|
||||
|
||||
let serviceCreated = false
|
||||
|
||||
const createService = async () => {
|
||||
@@ -142,6 +217,78 @@ const createService = async () => {
|
||||
rebuildQueue(true)
|
||||
}
|
||||
})
|
||||
|
||||
queueService.addListener('set', async ({ queue }) => {
|
||||
const contextId = useStore.getState().queueContextId
|
||||
const throwIfQueueChanged = () => {
|
||||
if (contextId !== useStore.getState().queueContextId) {
|
||||
throw 'queue-changed'
|
||||
}
|
||||
}
|
||||
|
||||
const albumIds = _.uniq(queue.map(s => s.albumId)).filter((id): id is string => id !== undefined)
|
||||
|
||||
const albumIdImagePath: { [albumId: string]: string | undefined } = {}
|
||||
for (const albumId of albumIds) {
|
||||
let coverArt = queryClient.getQueryData<string>(qk.albumCoverArt(albumId))
|
||||
if (!coverArt) {
|
||||
throwIfQueueChanged()
|
||||
console.log('no cached coverArt for album', albumId, 'getting album...')
|
||||
coverArt = (await getAlbum(albumId))?.album.coverArt
|
||||
if (!coverArt) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
let imagePath =
|
||||
queryClient.getQueryData<string>(qk.existingFiles('coverArtThumb', coverArt)) ||
|
||||
queryClient.getQueryData<string>(qk.coverArt(coverArt, 'thumbnail'))
|
||||
if (!imagePath) {
|
||||
throwIfQueueChanged()
|
||||
console.log('no cached image for', coverArt, 'getting file...')
|
||||
imagePath = (await getCoverArtThumbExisting(coverArt)) || (await getCoverArtThumb(coverArt))
|
||||
if (!imagePath) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
albumIdImagePath[albumId] = imagePath
|
||||
}
|
||||
|
||||
for (let i = 0; i < queue.length; i++) {
|
||||
const track = queue[i]
|
||||
if (typeof track.artwork === 'string') {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!track.albumId) {
|
||||
continue
|
||||
}
|
||||
|
||||
let imagePath = albumIdImagePath[track.albumId]
|
||||
if (!imagePath) {
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
throwIfQueueChanged()
|
||||
|
||||
let trackIdx = i
|
||||
const shuffleOrder = useStore.getState().shuffleOrder
|
||||
if (shuffleOrder) {
|
||||
trackIdx = shuffleOrder.indexOf(i)
|
||||
}
|
||||
|
||||
await TrackPlayer.updateMetadataForTrack(trackIdx, { ...track, artwork: `file://${imagePath}` })
|
||||
} catch {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
await trackPlayerCommands.enqueue(async () => {
|
||||
updateQueue()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = async function () {
|
||||
|
||||
Reference in New Issue
Block a user