Refactor
This commit is contained in:
parent
652be207be
commit
184ba91a2d
7 changed files with 81 additions and 58 deletions
|
@ -137,11 +137,11 @@ export const getPreviewableImage = async (
|
|||
await CastDownloadManager.downloadFile(castToken, file),
|
||||
).blob();
|
||||
if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
|
||||
const livePhoto = await decodeLivePhoto(
|
||||
const { imageData } = await decodeLivePhoto(
|
||||
file.metadata.title,
|
||||
fileBlob,
|
||||
);
|
||||
fileBlob = new Blob([livePhoto.image]);
|
||||
fileBlob = new Blob([imageData]);
|
||||
}
|
||||
const fileType = await getFileType(
|
||||
new File([fileBlob], file.metadata.title),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { decodeLivePhoto } from "@/media/live-photo";
|
||||
import { ensureElectron } from "@/next/electron";
|
||||
import log from "@/next/log";
|
||||
import { CustomError } from "@ente/shared/error";
|
||||
|
@ -38,7 +39,6 @@ import { writeStream } from "utils/native-stream";
|
|||
import { getAllLocalCollections } from "../collectionService";
|
||||
import downloadManager from "../download";
|
||||
import { getAllLocalFiles } from "../fileService";
|
||||
import { decodeLivePhoto } from "@/media/live-photo";
|
||||
import { migrateExport } from "./migration";
|
||||
|
||||
/** Name of the JSON file in which we keep the state of the export. */
|
||||
|
@ -1015,18 +1015,18 @@ class ExportService {
|
|||
fileStream: ReadableStream<any>,
|
||||
file: EnteFile,
|
||||
) {
|
||||
const electron = ensureElectron();
|
||||
const fs = ensureElectron().fs;
|
||||
const fileBlob = await new Response(fileStream).blob();
|
||||
const livePhoto = await decodeLivePhoto(file.metadata.title, fileBlob);
|
||||
const imageExportName = await safeFileName(
|
||||
collectionExportPath,
|
||||
livePhoto.imageNameTitle,
|
||||
electron.fs.exists,
|
||||
livePhoto.imageFileName,
|
||||
fs.exists,
|
||||
);
|
||||
const videoExportName = await safeFileName(
|
||||
collectionExportPath,
|
||||
livePhoto.videoNameTitle,
|
||||
electron.fs.exists,
|
||||
livePhoto.videoFileName,
|
||||
fs.exists,
|
||||
);
|
||||
const livePhotoExportName = getLivePhotoExportName(
|
||||
imageExportName,
|
||||
|
@ -1038,7 +1038,9 @@ class ExportService {
|
|||
livePhotoExportName,
|
||||
);
|
||||
try {
|
||||
const imageStream = generateStreamFromArrayBuffer(livePhoto.image);
|
||||
const imageStream = generateStreamFromArrayBuffer(
|
||||
livePhoto.imageData,
|
||||
);
|
||||
await this.saveMetadataFile(
|
||||
collectionExportPath,
|
||||
imageExportName,
|
||||
|
@ -1049,7 +1051,9 @@ class ExportService {
|
|||
imageStream,
|
||||
);
|
||||
|
||||
const videoStream = generateStreamFromArrayBuffer(livePhoto.video);
|
||||
const videoStream = generateStreamFromArrayBuffer(
|
||||
livePhoto.videoData,
|
||||
);
|
||||
await this.saveMetadataFile(
|
||||
collectionExportPath,
|
||||
videoExportName,
|
||||
|
@ -1061,9 +1065,7 @@ class ExportService {
|
|||
videoStream,
|
||||
);
|
||||
} catch (e) {
|
||||
await electron.fs.rm(
|
||||
`${collectionExportPath}/${imageExportName}`,
|
||||
);
|
||||
await fs.rm(`${collectionExportPath}/${imageExportName}`);
|
||||
throw e;
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -318,18 +318,18 @@ async function getFileExportNamesFromExportedFiles(
|
|||
if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
|
||||
const fileStream = await downloadManager.getFile(file);
|
||||
const fileBlob = await new Response(fileStream).blob();
|
||||
const livePhoto = await decodeLivePhoto(
|
||||
const { imageFileName, videoFileName } = await decodeLivePhoto(
|
||||
file.metadata.title,
|
||||
fileBlob,
|
||||
);
|
||||
const imageExportName = getUniqueFileExportNameForMigration(
|
||||
collectionPath,
|
||||
livePhoto.imageNameTitle,
|
||||
imageFileName,
|
||||
usedFilePaths,
|
||||
);
|
||||
const videoExportName = getUniqueFileExportNameForMigration(
|
||||
collectionPath,
|
||||
livePhoto.videoNameTitle,
|
||||
videoFileName,
|
||||
usedFilePaths,
|
||||
);
|
||||
fileExportName = getLivePhotoExportName(
|
||||
|
|
|
@ -101,16 +101,16 @@ export async function readLivePhoto(
|
|||
},
|
||||
);
|
||||
|
||||
const image = await getUint8ArrayView(livePhotoAssets.image);
|
||||
const imageData = await getUint8ArrayView(livePhotoAssets.image);
|
||||
|
||||
const video = await getUint8ArrayView(livePhotoAssets.video);
|
||||
const videoData = await getUint8ArrayView(livePhotoAssets.video);
|
||||
|
||||
return {
|
||||
filedata: await encodeLivePhoto({
|
||||
image,
|
||||
video,
|
||||
imageNameTitle: livePhotoAssets.image.name,
|
||||
videoNameTitle: livePhotoAssets.video.name,
|
||||
imageFileName: livePhotoAssets.image.name,
|
||||
imageData,
|
||||
videoFileName: livePhotoAssets.video.name,
|
||||
videoData,
|
||||
}),
|
||||
thumbnail,
|
||||
hasStaticThumbnail,
|
||||
|
|
|
@ -97,22 +97,20 @@ export async function downloadFile(file: EnteFile) {
|
|||
await DownloadManager.getFile(file),
|
||||
).blob();
|
||||
if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
|
||||
const livePhoto = await decodeLivePhoto(
|
||||
file.metadata.title,
|
||||
fileBlob,
|
||||
);
|
||||
const image = new File([livePhoto.image], livePhoto.imageNameTitle);
|
||||
const { imageFileName, imageData, videoFileName, videoData } =
|
||||
await decodeLivePhoto(file.metadata.title, fileBlob);
|
||||
const image = new File([imageData], imageFileName);
|
||||
const imageType = await getFileType(image);
|
||||
const tempImageURL = URL.createObjectURL(
|
||||
new Blob([livePhoto.image], { type: imageType.mimeType }),
|
||||
new Blob([imageData], { type: imageType.mimeType }),
|
||||
);
|
||||
const video = new File([livePhoto.video], livePhoto.videoNameTitle);
|
||||
const video = new File([videoData], videoFileName);
|
||||
const videoType = await getFileType(video);
|
||||
const tempVideoURL = URL.createObjectURL(
|
||||
new Blob([livePhoto.video], { type: videoType.mimeType }),
|
||||
new Blob([videoData], { type: videoType.mimeType }),
|
||||
);
|
||||
downloadUsingAnchor(tempImageURL, livePhoto.imageNameTitle);
|
||||
downloadUsingAnchor(tempVideoURL, livePhoto.videoNameTitle);
|
||||
downloadUsingAnchor(tempImageURL, imageFileName);
|
||||
downloadUsingAnchor(tempVideoURL, videoFileName);
|
||||
} else {
|
||||
const fileType = await getFileType(
|
||||
new File([fileBlob], file.metadata.title),
|
||||
|
@ -350,9 +348,9 @@ async function getRenderableLivePhotoURL(
|
|||
|
||||
const getRenderableLivePhotoImageURL = async () => {
|
||||
try {
|
||||
const imageBlob = new Blob([livePhoto.image]);
|
||||
const imageBlob = new Blob([livePhoto.imageData]);
|
||||
const convertedImageBlob = await getRenderableImage(
|
||||
livePhoto.imageNameTitle,
|
||||
livePhoto.imageFileName,
|
||||
imageBlob,
|
||||
);
|
||||
|
||||
|
@ -365,10 +363,9 @@ async function getRenderableLivePhotoURL(
|
|||
|
||||
const getRenderableLivePhotoVideoURL = async () => {
|
||||
try {
|
||||
const videoBlob = new Blob([livePhoto.video]);
|
||||
|
||||
const videoBlob = new Blob([livePhoto.videoData]);
|
||||
const convertedVideoBlob = await getPlayableVideo(
|
||||
livePhoto.videoNameTitle,
|
||||
livePhoto.videoFileName,
|
||||
videoBlob,
|
||||
forceConvert,
|
||||
true,
|
||||
|
|
|
@ -134,11 +134,11 @@ async function getOriginalConvertedFile(file: EnteFile, queue?: PQueue) {
|
|||
if (file.metadata.fileType === FILE_TYPE.IMAGE) {
|
||||
return await getRenderableImage(file.metadata.title, fileBlob);
|
||||
} else {
|
||||
const livePhoto = await decodeLivePhoto(file.metadata.title, fileBlob);
|
||||
return await getRenderableImage(
|
||||
livePhoto.imageNameTitle,
|
||||
new Blob([livePhoto.image]),
|
||||
const { imageFileName, imageData } = await decodeLivePhoto(
|
||||
file.metadata.title,
|
||||
fileBlob,
|
||||
);
|
||||
return await getRenderableImage(imageFileName, new Blob([imageData]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import { fileNameFromComponents, nameAndExtension } from "@/next/file";
|
||||
import JSZip from "jszip";
|
||||
|
||||
class LivePhoto {
|
||||
image: Uint8Array;
|
||||
video: Uint8Array;
|
||||
imageNameTitle: string;
|
||||
videoNameTitle: string;
|
||||
/**
|
||||
* An in-memory representation of a live photo.
|
||||
*/
|
||||
interface LivePhoto {
|
||||
imageFileName: string;
|
||||
imageData: Uint8Array;
|
||||
videoFileName: string;
|
||||
videoData: Uint8Array;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,23 +26,39 @@ class LivePhoto {
|
|||
* @param zipBlob A blob contained the zipped data (i.e. the binary serialized
|
||||
* live photo).
|
||||
*/
|
||||
export const decodeLivePhoto = async (fileName: string, zipBlob: Blob) => {
|
||||
export const decodeLivePhoto = async (
|
||||
fileName: string,
|
||||
zipBlob: Blob,
|
||||
): Promise<LivePhoto> => {
|
||||
let imageFileName, videoFileName: string | undefined;
|
||||
let imageData, videoData: Uint8Array | undefined;
|
||||
|
||||
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")) {
|
||||
const [, imageExt] = nameAndExtension(zipFileName);
|
||||
livePhoto.imageNameTitle = fileNameFromComponents([name, imageExt]);
|
||||
livePhoto.image = await zip.files[zipFileName].async("uint8array");
|
||||
imageFileName = fileNameFromComponents([name, imageExt]);
|
||||
imageData = await zip.files[zipFileName]?.async("uint8array");
|
||||
} else if (zipFileName.startsWith("video")) {
|
||||
const [, videoExt] = nameAndExtension(zipFileName);
|
||||
livePhoto.videoNameTitle = fileNameFromComponents([name, videoExt]);
|
||||
livePhoto.video = await zip.files[zipFileName].async("uint8array");
|
||||
videoFileName = fileNameFromComponents([name, videoExt]);
|
||||
videoData = await zip.files[zipFileName]?.async("uint8array");
|
||||
}
|
||||
}
|
||||
return livePhoto;
|
||||
|
||||
if (!imageFileName || !imageData)
|
||||
throw new Error(
|
||||
`Decoded live photo ${fileName} does not have an image`,
|
||||
);
|
||||
|
||||
if (!videoFileName || !videoData)
|
||||
throw new Error(
|
||||
`Decoded live photo ${fileName} does not have an image`,
|
||||
);
|
||||
|
||||
return { imageFileName, imageData, videoFileName, videoData };
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -52,12 +71,17 @@ export const decodeLivePhoto = async (fileName: string, zipBlob: Blob) => {
|
|||
*
|
||||
* @param livePhoto The in-mem photo to serialized.
|
||||
*/
|
||||
export const encodeLivePhoto = async (livePhoto: LivePhoto) => {
|
||||
const [, imageExt] = nameAndExtension(livePhoto.imageNameTitle);
|
||||
const [, videoExt] = nameAndExtension(livePhoto.videoNameTitle);
|
||||
export const encodeLivePhoto = async ({
|
||||
imageFileName,
|
||||
imageData,
|
||||
videoFileName,
|
||||
videoData,
|
||||
}: LivePhoto) => {
|
||||
const [, imageExt] = nameAndExtension(imageFileName);
|
||||
const [, videoExt] = nameAndExtension(videoFileName);
|
||||
|
||||
const zip = new JSZip();
|
||||
zip.file(fileNameFromComponents(["image", imageExt]), livePhoto.image);
|
||||
zip.file(fileNameFromComponents(["video", videoExt]), livePhoto.video);
|
||||
zip.file(fileNameFromComponents(["image", imageExt]), imageData);
|
||||
zip.file(fileNameFromComponents(["video", videoExt]), videoData);
|
||||
return await zip.generateAsync({ type: "uint8array" });
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue