diff --git a/web/apps/photos/src/services/livePhotoService.ts b/web/apps/photos/src/services/livePhotoService.ts index 4d96e812c..2fa11c2ca 100644 --- a/web/apps/photos/src/services/livePhotoService.ts +++ b/web/apps/photos/src/services/livePhotoService.ts @@ -5,6 +5,9 @@ import { getFileNameWithoutExtension, } from "utils/file"; +/** + * An in-memory representation of a live photo + */ class LivePhoto { image: Uint8Array; video: Uint8Array; @@ -31,6 +34,16 @@ export const decodeLivePhoto = async (file: EnteFile, zipBlob: Blob) => { return livePhoto; }; +/** + * Return a binary serialized representation of a live photo. + * + * This function takes the (in-memory) image and video data from the + * {@link livePhoto} object, writes them to a zip file (using the respective + * filenames), and returns the {@link Uint8Array} that represent the bytes of + * this zip file. + * + * @param livePhoto The in-mem photo to serialized. + */ export const encodeLivePhoto = async (livePhoto: LivePhoto) => { const zip = new JSZip(); zip.file( diff --git a/web/apps/photos/src/services/upload/livePhotoService.ts b/web/apps/photos/src/services/upload/livePhotoService.ts index 392b5b9c8..025c67e62 100644 --- a/web/apps/photos/src/services/upload/livePhotoService.ts +++ b/web/apps/photos/src/services/upload/livePhotoService.ts @@ -4,7 +4,7 @@ import { CustomError } from "@ente/shared/error"; import { Remote } from "comlink"; import { FILE_TYPE } from "constants/file"; import { LIVE_PHOTO_ASSET_SIZE_LIMIT } from "constants/upload"; -import { encodeLivePhoto } from "services/livePhotoService"; +import { encodeLivePhoto } from "@/media/live-photo"; import { getFileType } from "services/typeDetectionService"; import { ElectronFile, diff --git a/web/packages/media/live-photo.ts b/web/packages/media/live-photo.ts index 2d58c4c44..c5c1566e3 100644 --- a/web/packages/media/live-photo.ts +++ b/web/packages/media/live-photo.ts @@ -1,3 +1,4 @@ +import { nameAndExtension } from "@/next/file"; import JSZip from "jszip"; class LivePhoto { @@ -20,33 +21,30 @@ export function getFileExtensionWithDot(filename: string) { } export const decodeLivePhoto = async (fileName: string, zipBlob: Blob) => { - const originalName = getFileNameWithoutExtension(fileName); + const [name] = nameAndExtension(fileName); const zip = await JSZip.loadAsync(zipBlob, { createFolders: true }); const livePhoto = new LivePhoto(); - for (const zipFilename in zip.files) { - if (zipFilename.startsWith("image")) { + for (const zipFileName in zip.files) { + if (zipFileName.startsWith("image")) { livePhoto.imageNameTitle = - originalName + getFileExtensionWithDot(zipFilename); - livePhoto.image = await zip.files[zipFilename].async("uint8array"); - } else if (zipFilename.startsWith("video")) { + name + getFileExtensionWithDot(zipFileName); + livePhoto.image = await zip.files[zipFileName].async("uint8array"); + } else if (zipFileName.startsWith("video")) { livePhoto.videoNameTitle = - originalName + getFileExtensionWithDot(zipFilename); - livePhoto.video = await zip.files[zipFilename].async("uint8array"); + name + getFileExtensionWithDot(zipFileName); + livePhoto.video = await zip.files[zipFileName].async("uint8array"); } } return livePhoto; }; export const encodeLivePhoto = async (livePhoto: LivePhoto) => { + const [, imageExt] = nameAndExtension(livePhoto.imageNameTitle); + const [, videoExt] = nameAndExtension(livePhoto.videoNameTitle); + const zip = new JSZip(); - zip.file( - "image" + getFileExtensionWithDot(livePhoto.imageNameTitle), - livePhoto.image, - ); - zip.file( - "video" + getFileExtensionWithDot(livePhoto.videoNameTitle), - livePhoto.video, - ); + zip.file(["image", imageExt].filter((x) => !!x).join("."), livePhoto.image); + zip.file(["video", videoExt].filter((x) => !!x).join("."), livePhoto.video); return await zip.generateAsync({ type: "uint8array" }); };