diff --git a/components/downloads/DownloadSize.tsx b/components/downloads/DownloadSize.tsx index cc94306b..a69fc4a0 100644 --- a/components/downloads/DownloadSize.tsx +++ b/components/downloads/DownloadSize.tsx @@ -2,19 +2,49 @@ import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; import React, {useEffect, useMemo, useState} from "react"; import {Text} from "@/components/common/Text"; import useDownloadHelper from "@/utils/download"; +import {useDownload} from "@/providers/DownloadProvider"; interface DownloadSizeProps { items: BaseItemDto[]; } +interface DownloadSizes { + knownSize: number; + itemsNeedingSize: BaseItemDto[]; +} + export const DownloadSize: React.FC = ({ items }) => { + const { downloadedFiles, saveDownloadedItemInfo } = useDownload(); const { getDownloadSize } = useDownloadHelper(); const [size, setSize] = useState(); + const itemIds = useMemo(() => items.map(i => i.Id), [items]) + useEffect(() => { - getDownloadSize(...items).then(setSize) + if (!downloadedFiles) + return + + const {knownSize, itemsNeedingSize} = downloadedFiles + .filter(f => itemIds.includes(f.item.Id)) + ?.reduce((acc, file) => { + if (file?.size && file.size > 0) + acc.knownSize += file.size + else + acc.itemsNeedingSize.push(file.item) + return acc + }, { + knownSize: 0, + itemsNeedingSize: [] + }) + + getDownloadSize( + (item, size) => saveDownloadedItemInfo(item, size), + ...itemsNeedingSize + ).then(sizeSum => { + setSize(bytesToReadable((sizeSum + knownSize))) + }) }, - [items] + [items, itemIds] ); const sizeText = useMemo(() => { @@ -23,6 +53,14 @@ export const DownloadSize: React.FC = ({ items }) => { return size }, [size]) + const bytesToReadable = (bytes: number) => { + const gb = bytes / 1e+9; + + if (gb >= 1) + return `${gb.toFixed(2)} GB` + return `${(bytes / 1024 / 1024).toFixed(2)} MB` + } + return ( <> {sizeText} diff --git a/hooks/useRemuxHlsToMp4.ts b/hooks/useRemuxHlsToMp4.ts index 205205da..dfbec4da 100644 --- a/hooks/useRemuxHlsToMp4.ts +++ b/hooks/useRemuxHlsToMp4.ts @@ -128,7 +128,8 @@ export const useRemuxHlsToMp4 = () => { }s` ); if (!item) throw new Error("Item is undefined"); - await saveDownloadedItemInfo(item); + const stat = await session.getLastReceivedStatistics(); + await saveDownloadedItemInfo(item, stat.getSize()); toast.success("Download completed"); await queryClient.invalidateQueries({ queryKey: ["downloadedItems"], diff --git a/providers/DownloadProvider.tsx b/providers/DownloadProvider.tsx index c1e712bc..997411bd 100644 --- a/providers/DownloadProvider.tsx +++ b/providers/DownloadProvider.tsx @@ -51,6 +51,7 @@ import useDownloadHelper from "@/utils/download"; export type DownloadedItem = { item: Partial; mediaSource: MediaSourceInfo; + size: number | undefined; }; function onAppStateChange(status: AppStateStatus) { @@ -260,8 +261,8 @@ function useDownloadProvider() { ) ); }) - .done(async () => { - await saveDownloadedItemInfo(process.item); + .done(async (doneHandler) => { + await saveDownloadedItemInfo(process.item, doneHandler.bytesDownloaded); toast.success(`Download completed for ${process.item.Name}`, { duration: 3000, action: { @@ -522,7 +523,7 @@ function useDownloadProvider() { } } - function saveDownloadedItemInfo(item: BaseItemDto) { + function saveDownloadedItemInfo(item: BaseItemDto, size: number = 0) { try { const downloadedItems = storage.getString("downloadedItems"); let items: DownloadedItem[] = downloadedItems @@ -538,7 +539,7 @@ function useDownloadProvider() { "Media source not found in tmp storage. Did you forget to save it before starting download?" ); - const newItem = { item, mediaSource: data.mediaSource }; + const newItem = { item, size, mediaSource: data.mediaSource }; if (existingItemIndex !== -1) { items[existingItemIndex] = newItem; diff --git a/utils/download.ts b/utils/download.ts index 1c0dc9eb..92d3a391 100644 --- a/utils/download.ts +++ b/utils/download.ts @@ -5,9 +5,10 @@ import {apiAtom} from "@/providers/JellyfinProvider"; import {useAtom} from "jotai"; import {storage} from "@/utils/mmkv"; import {getDownloadedFileUrl} from "@/hooks/useDownloadedFileOpener"; -import * as FileSystem from 'expo-file-system' +import * as FileSystem from 'expo-file-system'; import {FileInfo} from "expo-file-system"; + const useDownloadHelper = () => { const [api] = useAtom(apiAtom); const {saveImage} = useImageStorage(); @@ -18,7 +19,10 @@ const useDownloadHelper = () => { } } - const getDownloadSize = async (...items: BaseItemDto[]) => { + const getDownloadSize = async ( + onNewItemSizeFetched: (item: BaseItemDto, size: number) => void, + ...items: BaseItemDto[] + ) => { const sizes: number[] = []; await Promise.all(items.map(item => { @@ -26,18 +30,17 @@ const useDownloadHelper = () => { const url = await getDownloadedFileUrl(item.Id!); if (url) { const fileInfo: FileInfo = await FileSystem.getInfoAsync(url); - sizes.push(fileInfo.size); - resolve(sizes); - } else reject(); + if (fileInfo.exists) { + onNewItemSizeFetched(item, fileInfo.size) + sizes.push(fileInfo.size); + resolve(sizes) + } + } + reject(); }) })); - const size = sizes.reduce((sum, size) => sum + size, 0); - const gb = size / 1e+9; - - if (gb >= 1) - return `${gb.toFixed(2)} GB`; - return `${(size / 1024 / 1024).toFixed(2)} MB`; + return sizes.reduce((sum, size) => sum + size, 0); } return { saveSeriesPrimaryImage, getDownloadSize }