diff --git a/app/(auth)/(tabs)/(home)/downloads/index.tsx b/app/(auth)/(tabs)/(home)/downloads/index.tsx index 75562a3b..26d90486 100644 --- a/app/(auth)/(tabs)/(home)/downloads/index.tsx +++ b/app/(auth)/(tabs)/(home)/downloads/index.tsx @@ -146,23 +146,25 @@ export default function page() { }); const deleteOtherMedia = () => Promise.all( - otherMedia.map((item) => - deleteFileByType(item.item.Type) - .then(() => - toast.success( - t("home.downloads.toasts.deleted_media_successfully", { - type: item.item.Type, - }), - ), - ) - .catch((reason) => { - writeToLog("ERROR", reason); - toast.error( - t("home.downloads.toasts.failed_to_delete_media", { - type: item.item.Type, - }), - ); - }), + otherMedia.map( + (item) => + item.item.Type && + deleteFileByType(item.item.Type) + .then(() => + toast.success( + t("home.downloads.toasts.deleted_media_successfully", { + type: item.item.Type, + }), + ), + ) + .catch((reason) => { + writeToLog("ERROR", reason); + toast.error( + t("home.downloads.toasts.failed_to_delete_media", { + type: item.item.Type, + }), + ); + }), ), ); diff --git a/components/downloads/SeriesCard.tsx b/components/downloads/SeriesCard.tsx index 8b2d4911..85b1a89e 100644 --- a/components/downloads/SeriesCard.tsx +++ b/components/downloads/SeriesCard.tsx @@ -19,7 +19,13 @@ export const SeriesCard: React.FC<{ items: BaseItemDto[] }> = ({ items }) => { return storage.getString(items[0].SeriesId!); }, []); - const deleteSeries = useCallback(async () => deleteItems(items), [items]); + const deleteSeries = useCallback( + async () => + deleteItems( + items.map((item) => item.Id).filter((id) => id !== undefined), + ), + [items], + ); const showActionSheet = useCallback(() => { const options = ["Delete", "Cancel"]; diff --git a/providers/DownloadProvider.tsx b/providers/DownloadProvider.tsx index eb63ba6a..c9014178 100644 --- a/providers/DownloadProvider.tsx +++ b/providers/DownloadProvider.tsx @@ -91,6 +91,7 @@ function useDownloadProvider() { deleteFile, deleteItems, deleteAllFiles, + deleteFileByType, appSizeUsage, } = useDownloadOperations({ taskMapRef, @@ -109,6 +110,7 @@ function useDownloadProvider() { deleteAllFiles, deleteFile, deleteItems, + deleteFileByType, removeProcess, cancelDownload, getDownloadedItemSize, @@ -119,7 +121,6 @@ function useDownloadProvider() { startDownload: async () => {}, pauseDownload: async () => {}, resumeDownload: async () => {}, - deleteFileByType: async () => {}, cleanCacheDirectory: async () => {}, updateDownloadedItem: () => {}, dumpDownloadDiagnostics: async () => "", @@ -138,12 +139,12 @@ export function useDownload() { deleteAllFiles: async () => {}, deleteFile: async () => {}, deleteItems: async () => {}, + deleteFileByType: async () => {}, removeProcess: () => {}, cancelDownload: async () => {}, startDownload: async () => {}, pauseDownload: async () => {}, resumeDownload: async () => {}, - deleteFileByType: async () => {}, getDownloadedItemSize: () => 0, getDownloadedItemById: () => undefined, APP_CACHE_DOWNLOAD_DIRECTORY: "", diff --git a/providers/Downloads/hooks/useDownloadOperations.ts b/providers/Downloads/hooks/useDownloadOperations.ts index 5238b685..7d15537c 100644 --- a/providers/Downloads/hooks/useDownloadOperations.ts +++ b/providers/Downloads/hooks/useDownloadOperations.ts @@ -214,6 +214,52 @@ export function useDownloadOperations({ toast.success(t("home.downloads.toasts.all_files_deleted")); }, [t]); + const deleteFileByType = useCallback( + async (itemType: string) => { + const allItems = getAllDownloadedItems(); + const itemsToDelete = allItems.filter( + (item) => item.item.Type === itemType, + ); + + if (itemsToDelete.length === 0) { + console.log(`[DELETE] No items found with type: ${itemType}`); + return; + } + + console.log( + `[DELETE] Deleting ${itemsToDelete.length} items of type: ${itemType}`, + ); + + for (const item of itemsToDelete) { + try { + deleteAllAssociatedFiles(item); + removeDownloadedItem(item.item.Id || ""); + } catch (error) { + console.error( + `Failed to delete ${itemType} file ${item.item.Name}:`, + error, + ); + } + } + + const itemLabel = + itemType === "Movie" + ? t("common.movies") + : itemType === "Episode" + ? t("common.episodes") + : itemType; + + toast.success( + t("home.downloads.toasts.files_deleted_by_type", { + count: itemsToDelete.length, + type: itemLabel, + defaultValue: `${itemsToDelete.length} ${itemLabel} deleted`, + }), + ); + }, + [t], + ); + const appSizeUsage = useCallback(async () => { const totalSize = calculateTotalDownloadedSize(); @@ -230,6 +276,7 @@ export function useDownloadOperations({ deleteFile, deleteItems, deleteAllFiles, + deleteFileByType, appSizeUsage, }; } diff --git a/providers/Downloads/index.ts b/providers/Downloads/index.ts index 7150254c..198cfd06 100644 --- a/providers/Downloads/index.ts +++ b/providers/Downloads/index.ts @@ -42,7 +42,6 @@ export type { JobStatus, MediaTimeSegment, TrickPlayData, - UserData, } from "./types"; // Utility functions export { generateFilename, uriToFilePath } from "./utils"; diff --git a/translations/en.json b/translations/en.json index 98d1daa7..1bbc2cc1 100644 --- a/translations/en.json +++ b/translations/en.json @@ -308,7 +308,8 @@ "all_files_folders_and_jobs_deleted_successfully": "All files, folders, and jobs deleted successfully", "failed_to_clean_cache_directory": "Failed to clean cache directory", "could_not_get_download_url_for_item": "Could not get download URL for {{itemName}}", - "go_to_downloads": "Go to Downloads" + "go_to_downloads": "Go to Downloads", + "file_deleted": "{{item}} deleted" } } },