From 5c900165e0585e327362ed1981142714deacf2a6 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 2 Mar 2023 12:48:12 +0530 Subject: [PATCH 1/4] fix all promise related eslint issue for export --- src/components/ExportModal.tsx | 228 +++++++++++++++++++-------------- src/services/exportService.ts | 76 ++++++----- src/utils/error/index.ts | 1 + 3 files changed, 179 insertions(+), 126 deletions(-) diff --git a/src/components/ExportModal.tsx b/src/components/ExportModal.tsx index 0450b43fe..2f6985701 100644 --- a/src/components/ExportModal.tsx +++ b/src/components/ExportModal.tsx @@ -70,14 +70,20 @@ export default function ExportModal(props: Props) { if (!isElectron()) { return; } - setExportFolder(getData(LS_KEYS.EXPORT)?.folder); + try { + setExportFolder(getData(LS_KEYS.EXPORT)?.folder); - exportService.electronAPIs.registerStopExportListener(stopExport); - exportService.electronAPIs.registerPauseExportListener(pauseExport); - exportService.electronAPIs.registerResumeExportListener(resumeExport); - exportService.electronAPIs.registerRetryFailedExportListener( - retryFailedExport - ); + exportService.electronAPIs.registerStopExportListener(stopExport); + exportService.electronAPIs.registerPauseExportListener(pauseExport); + exportService.electronAPIs.registerResumeExportListener( + resumeExport + ); + exportService.electronAPIs.registerRetryFailedExportListener( + retryFailedExport + ); + } catch (e) { + logError(e, 'error in exportModal'); + } }, []); useEffect(() => { @@ -85,19 +91,25 @@ export default function ExportModal(props: Props) { return; } const main = async () => { - const exportInfo = await exportService.getExportRecord(); - setExportStage(exportInfo?.stage ?? ExportStage.INIT); - setLastExportTime(exportInfo?.lastAttemptTimestamp); - setExportProgress(exportInfo?.progress ?? { current: 0, total: 0 }); - setExportStats({ - success: exportInfo?.exportedFiles?.length ?? 0, - failed: exportInfo?.failedFiles?.length ?? 0, - }); - if (exportInfo?.stage === ExportStage.INPROGRESS) { - resumeExport(); + try { + const exportInfo = await exportService.getExportRecord(); + setExportStage(exportInfo?.stage ?? ExportStage.INIT); + setLastExportTime(exportInfo?.lastAttemptTimestamp); + setExportProgress( + exportInfo?.progress ?? { current: 0, total: 0 } + ); + setExportStats({ + success: exportInfo?.exportedFiles?.length ?? 0, + failed: exportInfo?.failedFiles?.length ?? 0, + }); + if (exportInfo?.stage === ExportStage.INPROGRESS) { + resumeExport(); + } + } catch (e) { + logError(e, 'error handling exportFolder change'); } }; - main(); + void main(); }, [exportFolder]); useEffect(() => { @@ -117,7 +129,7 @@ export default function ExportModal(props: Props) { const failedFilesCnt = exportRecord.failedFiles?.length; const syncedFilesCnt = userPersonalFiles.length; if (syncedFilesCnt > exportedFileCnt + failedFilesCnt) { - updateExportProgress({ + await updateExportProgress({ current: exportedFileCnt + failedFilesCnt, total: syncedFilesCnt, }); @@ -131,11 +143,11 @@ export default function ExportModal(props: Props) { getExportRecordFileUID(file) ) ); - exportService.addFilesQueuedRecord( + await exportService.addFilesQueuedRecord( exportFolder, unExportedFiles ); - updateExportStage(ExportStage.PAUSED); + await updateExportStage(ExportStage.PAUSED); } } catch (e) { setExportStage(ExportStage.INIT); @@ -143,7 +155,7 @@ export default function ExportModal(props: Props) { } } }; - main(); + void main(); }, [props.show]); useEffect(() => { @@ -158,19 +170,21 @@ export default function ExportModal(props: Props) { setData(LS_KEYS.EXPORT, { folder: newFolder }); }; - const updateExportStage = (newStage: ExportStage) => { + const updateExportStage = async (newStage: ExportStage) => { setExportStage(newStage); - exportService.updateExportRecord({ stage: newStage }); + await exportService.updateExportRecord({ stage: newStage }); }; - const updateExportTime = (newTime: number) => { + const updateExportTime = async (newTime: number) => { setLastExportTime(newTime); - exportService.updateExportRecord({ lastAttemptTimestamp: newTime }); + await exportService.updateExportRecord({ + lastAttemptTimestamp: newTime, + }); }; - const updateExportProgress = (newProgress: ExportProgress) => { + const updateExportProgress = async (newProgress: ExportProgress) => { setExportProgress(newProgress); - exportService.updateExportRecord({ progress: newProgress }); + await exportService.updateExportRecord({ progress: newProgress }); }; // ====================== @@ -182,15 +196,15 @@ export default function ExportModal(props: Props) { if (!exportFolder) { await selectExportDirectory(); } - updateExportStage(ExportStage.INPROGRESS); + await updateExportStage(ExportStage.INPROGRESS); await sleep(100); }; const postExportRun = async (exportResult?: { paused?: boolean }) => { if (!exportResult?.paused) { - updateExportStage(ExportStage.FINISHED); + await updateExportStage(ExportStage.FINISHED); await sleep(100); - updateExportTime(Date.now()); - syncExportStatsWithRecord(); + await updateExportTime(Date.now()); + await syncExportStatsWithRecord(); } }; @@ -214,86 +228,106 @@ export default function ExportModal(props: Props) { // UI functions // ============= - const startExport = async () => { - try { - await preExportRun(); - updateExportProgress({ current: 0, total: 0 }); - const exportResult = await exportService.exportFiles( - updateExportProgress, - ExportType.NEW - ); - await postExportRun(exportResult); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'startExport failed'); + const startExport = () => { + const main = async () => { + try { + await preExportRun(); + await updateExportProgress({ current: 0, total: 0 }); + const exportResult = await exportService.exportFiles( + updateExportProgress, + ExportType.NEW + ); + await postExportRun(exportResult); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'startExport failed'); + } } - } + }; + void main(); }; - const stopExport = async () => { - try { - exportService.stopRunningExport(); - postExportRun(); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'stopExport failed'); + const stopExport = () => { + const main = async () => { + try { + exportService.stopRunningExport(); + await postExportRun(); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'stopExport failed'); + } } - } + }; + void main(); }; const pauseExport = () => { - try { - updateExportStage(ExportStage.PAUSED); - exportService.pauseRunningExport(); - postExportRun({ paused: true }); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'pauseExport failed'); + const main = async () => { + try { + await updateExportStage(ExportStage.PAUSED); + exportService.pauseRunningExport(); + await postExportRun({ paused: true }); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'pauseExport failed'); + } } - } + }; + void main(); }; - const resumeExport = async () => { - try { - const exportRecord = await exportService.getExportRecord(); - await preExportRun(); + const resumeExport = () => { + const main = async () => { + try { + const exportRecord = await exportService.getExportRecord(); + await preExportRun(); - const pausedStageProgress = exportRecord.progress; - setExportProgress(pausedStageProgress); + const pausedStageProgress = exportRecord.progress; + setExportProgress(pausedStageProgress); - const updateExportStatsWithOffset = (progress: ExportProgress) => - updateExportProgress({ - current: pausedStageProgress.current + progress.current, - total: pausedStageProgress.current + progress.total, + const updateExportStatsWithOffset = ( + progress: ExportProgress + ) => + updateExportProgress({ + current: pausedStageProgress.current + progress.current, + total: pausedStageProgress.current + progress.total, + }); + const exportResult = await exportService.exportFiles( + updateExportStatsWithOffset, + ExportType.PENDING + ); + + await postExportRun(exportResult); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'resumeExport failed'); + } + } + }; + void main(); + }; + + const retryFailedExport = () => { + const main = async () => { + try { + await preExportRun(); + await updateExportProgress({ + current: 0, + total: exportStats.failed, }); - const exportResult = await exportService.exportFiles( - updateExportStatsWithOffset, - ExportType.PENDING - ); - await postExportRun(exportResult); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'resumeExport failed'); + const exportResult = await exportService.exportFiles( + updateExportProgress, + ExportType.RETRY_FAILED + ); + await postExportRun(exportResult); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'retryFailedExport failed'); + } } - } - }; - - const retryFailedExport = async () => { - try { - await preExportRun(); - updateExportProgress({ current: 0, total: exportStats.failed }); - - const exportResult = await exportService.exportFiles( - updateExportProgress, - ExportType.RETRY_FAILED - ); - await postExportRun(exportResult); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'retryFailedExport failed'); - } - } + }; + void main(); }; const ExportDynamicContent = () => { diff --git a/src/services/exportService.ts b/src/services/exportService.ts index 68a905dc6..120bfb155 100644 --- a/src/services/exportService.ts +++ b/src/services/exportService.ts @@ -49,6 +49,7 @@ import { User } from 'types/user'; import { FILE_TYPE, TYPE_JPEG, TYPE_JPG } from 'constants/file'; import { ExportType, ExportNotification, RecordType } from 'constants/export'; import { ElectronAPIs } from 'types/electron'; +import { CustomError } from 'utils/error'; const LATEST_EXPORT_VERSION = 1; const EXPORT_RECORD_FILE_NAME = 'export_status.json'; @@ -83,10 +84,11 @@ class ExportService { this.pauseExport = true; } async exportFiles( - updateProgress: (progress: ExportProgress) => void, + updateProgress: (progress: ExportProgress) => Promise, exportType: ExportType ) { try { + // eslint-disable-next-line @typescript-eslint/no-misused-promises if (this.exportInProgress) { this.electronAPIs.sendNotification( ExportNotification.IN_PROGRESS @@ -177,7 +179,7 @@ class ExportService { newCollections: Collection[], renamedCollections: Collection[], collectionIDPathMap: CollectionIDPathMap, - updateProgress: (progress: ExportProgress) => void, + updateProgress: (progress: ExportProgress) => Promise, exportDir: string ): Promise<{ paused: boolean }> { try { @@ -212,7 +214,7 @@ class ExportService { this.electronAPIs.showOnTray({ export_progress: `0 / ${files.length} files exported`, }); - updateProgress({ + await updateProgress({ current: 0, total: files.length, }); @@ -239,6 +241,12 @@ class ExportService { RecordType.SUCCESS ); } catch (e) { + if ( + e.message === + CustomError.ADD_FILE_EXPORTED_RECORD_FAILED + ) { + throw e; + } await this.addFileExportedRecord( exportDir, file, @@ -255,7 +263,10 @@ class ExportService { files.length } files exported`, }); - updateProgress({ current: index + 1, total: files.length }); + await updateProgress({ + current: index + 1, + total: files.length, + }); } if (this.stopExport) { this.electronAPIs.sendNotification(ExportNotification.ABORT); @@ -266,7 +277,7 @@ class ExportService { } else if (failedFileCount > 0) { this.electronAPIs.sendNotification(ExportNotification.FAILED); this.electronAPIs.showOnTray({ - retry_export: `export failed - retry export`, + retry_export: `Retry failed export`, }); } else { this.electronAPIs.sendNotification(ExportNotification.FINISH); @@ -289,32 +300,37 @@ class ExportService { file: EnteFile, type: RecordType ) { - const fileUID = getExportRecordFileUID(file); - const exportRecord = await this.getExportRecord(folder); - exportRecord.queuedFiles = exportRecord.queuedFiles.filter( - (queuedFilesUID) => queuedFilesUID !== fileUID - ); - if (type === RecordType.SUCCESS) { - if (!exportRecord.exportedFiles) { - exportRecord.exportedFiles = []; - } - exportRecord.exportedFiles.push(fileUID); - exportRecord.failedFiles && - (exportRecord.failedFiles = exportRecord.failedFiles.filter( - (FailedFileUID) => FailedFileUID !== fileUID - )); - } else { - if (!exportRecord.failedFiles) { - exportRecord.failedFiles = []; - } - if (!exportRecord.failedFiles.find((x) => x === fileUID)) { - exportRecord.failedFiles.push(fileUID); + try { + const fileUID = getExportRecordFileUID(file); + const exportRecord = await this.getExportRecord(folder); + exportRecord.queuedFiles = exportRecord.queuedFiles.filter( + (queuedFilesUID) => queuedFilesUID !== fileUID + ); + if (type === RecordType.SUCCESS) { + if (!exportRecord.exportedFiles) { + exportRecord.exportedFiles = []; + } + exportRecord.exportedFiles.push(fileUID); + exportRecord.failedFiles && + (exportRecord.failedFiles = exportRecord.failedFiles.filter( + (FailedFileUID) => FailedFileUID !== fileUID + )); + } else { + if (!exportRecord.failedFiles) { + exportRecord.failedFiles = []; + } + if (!exportRecord.failedFiles.find((x) => x === fileUID)) { + exportRecord.failedFiles.push(fileUID); + } } + exportRecord.exportedFiles = dedupe(exportRecord.exportedFiles); + exportRecord.queuedFiles = dedupe(exportRecord.queuedFiles); + exportRecord.failedFiles = dedupe(exportRecord.failedFiles); + await this.updateExportRecord(exportRecord, folder); + } catch (e) { + logError(e, 'addFileExportedRecord failed'); + throw Error(CustomError.ADD_FILE_EXPORTED_RECORD_FAILED); } - exportRecord.exportedFiles = dedupe(exportRecord.exportedFiles); - exportRecord.queuedFiles = dedupe(exportRecord.queuedFiles); - exportRecord.failedFiles = dedupe(exportRecord.failedFiles); - await this.updateExportRecord(exportRecord, folder); } async addCollectionExportedRecord( @@ -354,6 +370,7 @@ class ExportService { ); } catch (e) { logError(e, 'error updating Export Record'); + throw e; } } @@ -372,6 +389,7 @@ class ExportService { } } catch (e) { logError(e, 'export Record JSON parsing failed '); + throw e; } } diff --git a/src/utils/error/index.ts b/src/utils/error/index.ts index 557d7c7f2..a4bf9a7c2 100644 --- a/src/utils/error/index.ts +++ b/src/utils/error/index.ts @@ -55,6 +55,7 @@ export const CustomError = { 'Windows native image processing is not supported', NETWORK_ERROR: 'Network Error', NOT_FILE_OWNER: 'not file owner', + ADD_FILE_EXPORTED_RECORD_FAILED: 'add file exported record failed', }; export function parseUploadErrorCodes(error) { From b19922212f9686462996351fc18fce5b4d80f3e9 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 2 Mar 2023 13:11:13 +0530 Subject: [PATCH 2/4] added handler function for export utils so that can passed as button onClick handlers --- src/components/ExportModal.tsx | 197 +++++++++++++++++---------------- 1 file changed, 100 insertions(+), 97 deletions(-) diff --git a/src/components/ExportModal.tsx b/src/components/ExportModal.tsx index 2f6985701..ef336534d 100644 --- a/src/components/ExportModal.tsx +++ b/src/components/ExportModal.tsx @@ -73,13 +73,17 @@ export default function ExportModal(props: Props) { try { setExportFolder(getData(LS_KEYS.EXPORT)?.folder); - exportService.electronAPIs.registerStopExportListener(stopExport); - exportService.electronAPIs.registerPauseExportListener(pauseExport); + exportService.electronAPIs.registerStopExportListener( + stopExportHandler + ); + exportService.electronAPIs.registerPauseExportListener( + pauseExportHandler + ); exportService.electronAPIs.registerResumeExportListener( - resumeExport + resumeExportHandler ); exportService.electronAPIs.registerRetryFailedExportListener( - retryFailedExport + retryFailedExportHandler ); } catch (e) { logError(e, 'error in exportModal'); @@ -103,7 +107,7 @@ export default function ExportModal(props: Props) { failed: exportInfo?.failedFiles?.length ?? 0, }); if (exportInfo?.stage === ExportStage.INPROGRESS) { - resumeExport(); + await resumeExport(); } } catch (e) { logError(e, 'error handling exportFolder change'); @@ -228,112 +232,111 @@ export default function ExportModal(props: Props) { // UI functions // ============= - const startExport = () => { - const main = async () => { - try { - await preExportRun(); - await updateExportProgress({ current: 0, total: 0 }); - const exportResult = await exportService.exportFiles( - updateExportProgress, - ExportType.NEW - ); - await postExportRun(exportResult); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'startExport failed'); - } + const startExport = async () => { + try { + await preExportRun(); + await updateExportProgress({ current: 0, total: 0 }); + const exportResult = await exportService.exportFiles( + updateExportProgress, + ExportType.NEW + ); + await postExportRun(exportResult); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'startExport failed'); } - }; - void main(); + } }; - const stopExport = () => { - const main = async () => { - try { - exportService.stopRunningExport(); - await postExportRun(); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'stopExport failed'); - } + const stopExport = async () => { + try { + exportService.stopRunningExport(); + await postExportRun(); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'stopExport failed'); } - }; - void main(); + } }; - const pauseExport = () => { - const main = async () => { - try { - await updateExportStage(ExportStage.PAUSED); - exportService.pauseRunningExport(); - await postExportRun({ paused: true }); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'pauseExport failed'); - } + const pauseExport = async () => { + try { + await updateExportStage(ExportStage.PAUSED); + exportService.pauseRunningExport(); + await postExportRun({ paused: true }); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'pauseExport failed'); } - }; - void main(); + } }; - const resumeExport = () => { - const main = async () => { - try { - const exportRecord = await exportService.getExportRecord(); - await preExportRun(); + const resumeExport = async () => { + try { + const exportRecord = await exportService.getExportRecord(); + await preExportRun(); - const pausedStageProgress = exportRecord.progress; - setExportProgress(pausedStageProgress); + const pausedStageProgress = exportRecord.progress; + setExportProgress(pausedStageProgress); - const updateExportStatsWithOffset = ( - progress: ExportProgress - ) => - updateExportProgress({ - current: pausedStageProgress.current + progress.current, - total: pausedStageProgress.current + progress.total, - }); - const exportResult = await exportService.exportFiles( - updateExportStatsWithOffset, - ExportType.PENDING - ); - - await postExportRun(exportResult); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'resumeExport failed'); - } - } - }; - void main(); - }; - - const retryFailedExport = () => { - const main = async () => { - try { - await preExportRun(); - await updateExportProgress({ - current: 0, - total: exportStats.failed, + const updateExportStatsWithOffset = (progress: ExportProgress) => + updateExportProgress({ + current: pausedStageProgress.current + progress.current, + total: pausedStageProgress.current + progress.total, }); + const exportResult = await exportService.exportFiles( + updateExportStatsWithOffset, + ExportType.PENDING + ); - const exportResult = await exportService.exportFiles( - updateExportProgress, - ExportType.RETRY_FAILED - ); - await postExportRun(exportResult); - } catch (e) { - if (e.message !== CustomError.REQUEST_CANCELLED) { - logError(e, 'retryFailedExport failed'); - } + await postExportRun(exportResult); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'resumeExport failed'); } - }; - void main(); + } + }; + + const retryFailedExport = async () => { + try { + await preExportRun(); + await updateExportProgress({ + current: 0, + total: exportStats.failed, + }); + + const exportResult = await exportService.exportFiles( + updateExportProgress, + ExportType.RETRY_FAILED + ); + await postExportRun(exportResult); + } catch (e) { + if (e.message !== CustomError.REQUEST_CANCELLED) { + logError(e, 'retryFailedExport failed'); + } + } + }; + + const startExportHandler = () => { + void startExport(); + }; + const stopExportHandler = () => { + void stopExport(); + }; + const pauseExportHandler = () => { + void pauseExport(); + }; + const resumeExportHandler = () => { + void resumeExport(); + }; + const retryFailedExportHandler = () => { + void retryFailedExport(); }; const ExportDynamicContent = () => { switch (exportStage) { case ExportStage.INIT: - return ; + return ; case ExportStage.INPROGRESS: case ExportStage.PAUSED: @@ -341,9 +344,9 @@ export default function ExportModal(props: Props) { ); case ExportStage.FINISHED: @@ -352,8 +355,8 @@ export default function ExportModal(props: Props) { onHide={props.onHide} lastExportTime={lastExportTime} exportStats={exportStats} - exportFiles={startExport} - retryFailed={retryFailedExport} + exportFiles={startExportHandler} + retryFailed={retryFailedExportHandler} /> ); From 84a2a00c61fca4e7c3bd55fb204e8c3d2b9899bf Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 2 Mar 2023 13:19:36 +0530 Subject: [PATCH 3/4] update tray message --- src/services/exportService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/exportService.ts b/src/services/exportService.ts index 120bfb155..43b7e3dd1 100644 --- a/src/services/exportService.ts +++ b/src/services/exportService.ts @@ -277,7 +277,7 @@ class ExportService { } else if (failedFileCount > 0) { this.electronAPIs.sendNotification(ExportNotification.FAILED); this.electronAPIs.showOnTray({ - retry_export: `Retry failed export`, + retry_export: `Retry failed exports`, }); } else { this.electronAPIs.sendNotification(ExportNotification.FINISH); From 60fcf46c63bb2bc69228e0da06b1d1741d6c6ca4 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 2 Mar 2023 13:23:19 +0530 Subject: [PATCH 4/4] improve error logging --- src/services/exportService.ts | 73 +++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/src/services/exportService.ts b/src/services/exportService.ts index 43b7e3dd1..87b6339a3 100644 --- a/src/services/exportService.ts +++ b/src/services/exportService.ts @@ -241,6 +241,7 @@ class ExportService { RecordType.SUCCESS ); } catch (e) { + logError(e, 'export failed for a file'); if ( e.message === CustomError.ADD_FILE_EXPORTED_RECORD_FAILED @@ -252,11 +253,6 @@ class ExportService { file, RecordType.FAILED ); - - logError( - e, - 'download and save failed for file during export' - ); } this.electronAPIs.showOnTray({ export_progress: `${index + 1} / ${ @@ -446,36 +442,45 @@ class ExportService { } async downloadAndSave(file: EnteFile, collectionPath: string) { - file.metadata = mergeMetadata([file])[0].metadata; - const fileSaveName = getUniqueFileSaveName( - collectionPath, - file.metadata.title, - file.id - ); - let fileStream = await retryAsyncFunction(() => - downloadManager.downloadFile(file) - ); - const fileType = getFileExtension(file.metadata.title); - if ( - file.pubMagicMetadata?.data.editedTime && - (fileType === TYPE_JPEG || fileType === TYPE_JPG) - ) { - const fileBlob = await new Response(fileStream).blob(); - if (!this.fileReader) { - this.fileReader = new FileReader(); - } - const updatedFileBlob = await updateFileCreationDateInEXIF( - this.fileReader, - fileBlob, - new Date(file.pubMagicMetadata.data.editedTime / 1000) + try { + file.metadata = mergeMetadata([file])[0].metadata; + const fileSaveName = getUniqueFileSaveName( + collectionPath, + file.metadata.title, + file.id ); - fileStream = updatedFileBlob.stream(); - } - if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) { - await this.exportMotionPhoto(fileStream, file, collectionPath); - } else { - await this.saveMediaFile(collectionPath, fileSaveName, fileStream); - await this.saveMetadataFile(collectionPath, fileSaveName, file); + let fileStream = await retryAsyncFunction(() => + downloadManager.downloadFile(file) + ); + const fileType = getFileExtension(file.metadata.title); + if ( + file.pubMagicMetadata?.data.editedTime && + (fileType === TYPE_JPEG || fileType === TYPE_JPG) + ) { + const fileBlob = await new Response(fileStream).blob(); + if (!this.fileReader) { + this.fileReader = new FileReader(); + } + const updatedFileBlob = await updateFileCreationDateInEXIF( + this.fileReader, + fileBlob, + new Date(file.pubMagicMetadata.data.editedTime / 1000) + ); + fileStream = updatedFileBlob.stream(); + } + if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) { + await this.exportMotionPhoto(fileStream, file, collectionPath); + } else { + await this.saveMediaFile( + collectionPath, + fileSaveName, + fileStream + ); + await this.saveMetadataFile(collectionPath, fileSaveName, file); + } + } catch (e) { + logError(e, 'download and save failed'); + throw e; } }