diff --git a/src/components/CoverImage.tsx b/src/components/CoverImage.tsx index 9698e6e..9ca7b5a 100644 --- a/src/components/CoverImage.tsx +++ b/src/components/CoverImage.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState } from 'react'; +import React, { useMemo } from 'react'; import { Dimensions, ViewProps } from 'react-native'; import { Canvas, Blur, Image as SkiaImage, useImage, Offset, Mask, RoundedRect, Shadow } from '@shopify/react-native-skia'; import useDefaultStyles, { useUserOrSystemScheme } from './Colors'; @@ -49,9 +49,8 @@ function CoverImage({ }: Props) { const defaultStyles = useDefaultStyles(); const colorScheme = useUserOrSystemScheme(); - const [hasFailed, setFailed] = useState(false); - const image = useImage(src || null, () => setFailed(true)); + const image = useImage(src || null); const fallback = useImage(colorScheme === 'light' ? emptyAlbumLight : emptyAlbumDark); const { canvasSize, imageSize } = useMemo(() => { const imageSize = Screen.width - margin; @@ -59,8 +58,6 @@ function CoverImage({ return { imageSize, canvasSize }; }, [blurRadius, margin]); - console.log({ src, hasFailed }); - return ( diff --git a/src/store/downloads/actions.ts b/src/store/downloads/actions.ts index 89893d3..330b652 100644 --- a/src/store/downloads/actions.ts +++ b/src/store/downloads/actions.ts @@ -17,16 +17,17 @@ export const failDownload = createAction<{ id: string }>('download/fail'); export const downloadTrack = createAsyncThunk( '/downloads/track', - async (id: string, { dispatch }) => { + async (id: string, { dispatch, getState }) => { // Generate the URL we can use to download the file + const entity = (getState() as AppState).music.tracks.entities[id]; const audioUrl = generateTrackUrl(id); - const imageUrl = getImage(id); + const imageUrl = getImage(entity); // Get the content-type from the URL by doing a HEAD-only request const [audioExt, imageExt] = await Promise.all([ getExtensionForUrl(audioUrl), // Image files may be absent - getExtensionForUrl(imageUrl).catch(() => null) + imageUrl ? getExtensionForUrl(imageUrl).catch(() => null) : null ]); // Then generate the proper location @@ -51,7 +52,7 @@ export const downloadTrack = createAsyncThunk( const { promise: imagePromise } = imageExt && imageLocation ? downloadFile({ - fromUrl: imageUrl, + fromUrl: imageUrl!, toFile: imageLocation, background: true, }) diff --git a/src/utility/JellyfinApi/lib.ts b/src/utility/JellyfinApi/lib.ts index c61c0e7..587edb7 100644 --- a/src/utility/JellyfinApi/lib.ts +++ b/src/utility/JellyfinApi/lib.ts @@ -112,25 +112,36 @@ function formatImageUri(ItemId: string | number, baseUri: string): string { */ export function getImage(item: string | number | Album | AlbumTrack | Playlist | ArtistItem | null, credentials?: AppState['settings']['credentials']): string | undefined { // Either accept provided credentials, or retrieve them directly from the store - const { uri: serverUri } = credentials - ?? asyncFetchStore().getState().settings.credentials ?? {}; + const state = asyncFetchStore().getState(); + const { uri: serverUri } = credentials ?? state.settings.credentials ?? {}; if (!item || !serverUri) { return undefined; - // GUARD: If the item's just the id, we'll pass it on directly. - } else if (typeof item === 'string' || typeof item === 'number') { + } + + // Get the item ID + const itemId = typeof item === 'string' || typeof item === 'number' + ? item + : 'PrimaryImageItemId' in item + ? item.PrimaryImageItemId || item.Id + : item.Id; + + // Check if we have a downloaded image for this item + const downloadEntity = state.downloads.entities[itemId]; + if (downloadEntity?.image) { + return downloadEntity.image; + } + + // If no downloaded image, fall back to server URL + if (typeof item === 'string' || typeof item === 'number') { if (__DEV__) { console.warn('useGetImage: supplied item is string or number. Please submit an item object instead.', { item }); } return formatImageUri(item, serverUri); - // GUARD: If the item has an `PrimaryImageItemId` (for Emby servers), - // we'll attemp to return that } else if ('PrimaryImageItemId' in item) { return formatImageUri(item.PrimaryImageItemId || item.Id, serverUri); - } else { - if ('ImageTags' in item && item.ImageTags.Primary) { - return formatImageUri(item.Id, serverUri); - } + } else if ('ImageTags' in item && item.ImageTags.Primary) { + return formatImageUri(item.Id, serverUri); } return undefined;