diff --git a/web/apps/photos/src/components/FixCreationTime.tsx b/web/apps/photos/src/components/FixCreationTime.tsx index 41e344aac6..7dd5136d8b 100644 --- a/web/apps/photos/src/components/FixCreationTime.tsx +++ b/web/apps/photos/src/components/FixCreationTime.tsx @@ -1,10 +1,9 @@ import log from "@/base/log"; import type { ParsedMetadataDate } from "@/media/file-metadata"; +import { FileType } from "@/media/file-type"; import { PhotoDateTimePicker } from "@/new/photos/components/PhotoDateTimePicker"; -import { - updateDateTimeOfEnteFiles, - type FixOption, -} from "@/new/photos/services/fix-exif"; +import downloadManager from "@/new/photos/services/download"; +import { extractExifDates } from "@/new/photos/services/exif"; import { EnteFile } from "@/new/photos/types/file"; import { fileLogID } from "@/new/photos/utils/file"; import DialogBox from "@ente/shared/components/DialogBox/"; @@ -22,20 +21,30 @@ import { useFormik } from "formik"; import { t } from "i18next"; import { GalleryContext } from "pages/gallery"; import React, { useContext, useEffect, useState } from "react"; - -export interface FixCreationTimeAttributes { - files: EnteFile[]; -} +import { + changeFileCreationTime, + updateExistingFilePubMetadata, +} from "utils/file"; /** The current state of the fixing process. */ type Status = "running" | "completed" | "completed-with-errors"; +export type FixOption = + | "date-time-original" + | "date-time-digitized" + | "metadata-date" + | "custom"; + interface FormValues { option: FixOption; /* Only valid when {@link option} is "custom-time". */ customDate: ParsedMetadataDate | undefined; } +export interface FixCreationTimeAttributes { + files: EnteFile[]; +} + interface FixCreationTimeProps { isOpen: boolean; hide: () => void; @@ -63,7 +72,7 @@ const FixCreationTime: React.FC = ({ const onSubmit = async (values: FormValues) => { console.log({ values }); setStatus("running"); - const completedWithErrors = await updateDateTimeOfEnteFiles( + const completedWithErrors = await updateFiles( attributes.files, values.option, values.customDate, @@ -282,3 +291,61 @@ const updateFiles = async ( } return hadErrors; }; + +/** + * Update the date associated with a given {@link enteFile}. + * + * This is generally treated as the creation date of the underlying asset + * (photo, video, live photo) that this file stores. + * + * - For images, this function allows us to update this date from the Exif and + * other metadata embedded in the file. + * + * - For all types of files (including images), this function allows us to + * update this date to an explicitly provided value. + * + * If an Exif-involving {@link fixOption} is passed for an non-image file, then + * that file is just skipped over. Similarly, if an Exif-involving + * {@link fixOption} is provided, but the given underlying image for the given + * {@link enteFile} does not have a corresponding Exif (or related) value, then + * that file is skipped. + * + * Note that metadata associated with an {@link EnteFile} is immutable, and we + * instead modify the mutable metadata section associated with the file. See + * [Note: Metadatum] for more details. + */ +export const updateEnteFileDate = async ( + enteFile: EnteFile, + fixOption: FixOption, + customDate: ParsedMetadataDate, +) => { + let newDate: ParsedMetadataDate | undefined; + if (fixOption === "custom") { + newDate = customDate; + } else if (enteFile.metadata.fileType == FileType.image) { + const stream = await downloadManager.getFile(enteFile); + const blob = await new Response(stream).blob(); + const file = new File([blob], enteFile.metadata.title); + const { DateTimeOriginal, DateTimeDigitized, MetadataDate, DateTime } = + await extractExifDates(file); + switch (fixOption) { + case "date-time-original": + newDate = DateTimeOriginal ?? DateTime; + break; + case "date-time-digitized": + newDate = DateTimeDigitized; + break; + case "metadata-date": + newDate = MetadataDate; + break; + } + } + + if (newDate && newDate.timestamp !== enteFile.metadata.creationTime) { + const updatedFile = await changeFileCreationTime( + enteFile, + newDate.timestamp, + ); + updateExistingFilePubMetadata(enteFile, updatedFile); + } +}; diff --git a/web/packages/new/photos/services/fix-exif.ts b/web/packages/new/photos/services/fix-exif.ts deleted file mode 100644 index 8d7452e942..0000000000 --- a/web/packages/new/photos/services/fix-exif.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { ParsedMetadataDate } from "@/media/file-metadata"; -import { - changeFileCreationTime, - updateExistingFilePubMetadata, -} from "@/media/file-metadata"; -import { FileType } from "@/media/file-type"; -import downloadManager from "@/new/photos/services/download"; -import type { EnteFile } from "@/new/photos/types/file"; -import { extractExifDates } from "./exif"; - -export type FixOption = - | "date-time-original" - | "date-time-digitized" - | "metadata-date" - | "custom"; - -/** - * Update the date associated with a given {@link enteFile}. - * - * This is generally treated as the creation date of the underlying asset - * (photo, video, live photo) that this file stores. - * - * - For images, this function allows us to update this date from the Exif and - * other metadata embedded in the file. - * - * - For all types of files (including images), this function allows us to - * update this date to an explicitly provided value. - * - * If an Exif-involving {@link fixOption} is passed for an non-image file, then - * that file is just skipped over. Similarly, if an Exif-involving - * {@link fixOption} is provided, but the given underlying image for the given - * {@link enteFile} does not have a corresponding Exif (or related) value, then - * that file is skipped. - * - * Note that metadata associated with an {@link EnteFile} is immutable, and we - * instead modify the mutable metadata section associated with the file. See - * [Note: Metadatum] for more details. - */ -export const updateEnteFileDate = async ( - enteFile: EnteFile, - fixOption: FixOption, - customDate: ParsedMetadataDate, -) => { - let newDate: ParsedMetadataDate | undefined; - if (fixOption === "custom") { - newDate = customDate; - } else if (enteFile.metadata.fileType == FileType.image) { - const stream = await downloadManager.getFile(enteFile); - const blob = await new Response(stream).blob(); - const file = new File([blob], enteFile.metadata.title); - const { DateTimeOriginal, DateTimeDigitized, MetadataDate, DateTime } = - await extractExifDates(file); - switch (fixOption) { - case "date-time-original": - newDate = DateTimeOriginal ?? DateTime; - break; - case "date-time-digitized": - newDate = DateTimeDigitized; - break; - case "metadata-date": - newDate = MetadataDate; - break; - } - } - - if (newDate && newDate.timestamp !== enteFile.metadata.creationTime) { - const updatedFile = await changeFileCreationTime( - enteFile, - newDate.timestamp, - ); - updateExistingFilePubMetadata(enteFile, updatedFile); - } -};