Tinker
This commit is contained in:
parent
9103dadc6f
commit
2bee444078
2 changed files with 72 additions and 96 deletions
|
@ -1,4 +1,4 @@
|
|||
import { getFileNameSize } from "@/next/file";
|
||||
import { getFileNameSize, nameAndExtension } from "@/next/file";
|
||||
import log from "@/next/log";
|
||||
import { ElectronFile } from "@/next/types/file";
|
||||
import { DedicatedCryptoWorker } from "@ente/shared/crypto/internal/crypto.worker";
|
||||
|
@ -188,13 +188,6 @@ async function getVideoMetadata(file: File | ElectronFile) {
|
|||
return videoMetadata;
|
||||
}
|
||||
|
||||
interface LivePhotoIdentifier {
|
||||
collectionID: number;
|
||||
fileType: FILE_TYPE;
|
||||
name: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
const UNDERSCORE_THREE = "_3";
|
||||
// Note: The icloud-photos-downloader library appends _HVEC to the end of the filename in case of live photos
|
||||
// https://github.com/icloud-photos-downloader/icloud_photos_downloader
|
||||
|
@ -312,74 +305,64 @@ export function getLivePhotoSize(livePhotoAssets: LivePhotoAssets) {
|
|||
return livePhotoAssets.image.size + livePhotoAssets.video.size;
|
||||
}
|
||||
|
||||
export async function clusterLivePhotoFiles(mediaFiles: FileWithCollection2[]) {
|
||||
/**
|
||||
* Go through the given files, combining any sibling image + video assets into a
|
||||
* single live photo when appropriate.
|
||||
*/
|
||||
export const clusterLivePhotos = (mediaFiles: FileWithCollection2[]) => {
|
||||
try {
|
||||
const analysedMediaFiles: FileWithCollection2[] = [];
|
||||
const result: FileWithCollection2[] = [];
|
||||
mediaFiles
|
||||
.sort((firstMediaFile, secondMediaFile) =>
|
||||
splitFilenameAndExtension(
|
||||
getFileName(firstMediaFile.file),
|
||||
)[0].localeCompare(
|
||||
splitFilenameAndExtension(
|
||||
getFileName(secondMediaFile.file),
|
||||
)[0],
|
||||
.sort((f, g) =>
|
||||
nameAndExtension(getFileName(f.file))[0].localeCompare(
|
||||
nameAndExtension(getFileName(g.file))[0],
|
||||
),
|
||||
)
|
||||
.sort(
|
||||
(firstMediaFile, secondMediaFile) =>
|
||||
firstMediaFile.collectionID - secondMediaFile.collectionID,
|
||||
);
|
||||
.sort((f, g) => f.collectionID - g.collectionID);
|
||||
let index = 0;
|
||||
while (index < mediaFiles.length - 1) {
|
||||
if (uploadCancelService.isUploadCancelationRequested()) {
|
||||
throw Error(CustomError.UPLOAD_CANCELLED);
|
||||
}
|
||||
const firstMediaFile = mediaFiles[index];
|
||||
const secondMediaFile = mediaFiles[index + 1];
|
||||
const firstFileType =
|
||||
getFileTypeFromExtensionForLivePhotoClustering(
|
||||
getFileName(firstMediaFile.file),
|
||||
);
|
||||
const secondFileType =
|
||||
getFileTypeFromExtensionForLivePhotoClustering(
|
||||
getFileName(secondMediaFile.file),
|
||||
);
|
||||
const firstFileIdentifier: LivePhotoIdentifier = {
|
||||
collectionID: firstMediaFile.collectionID,
|
||||
fileType: firstFileType,
|
||||
name: getFileName(firstMediaFile.file),
|
||||
const f = mediaFiles[index];
|
||||
const g = mediaFiles[index + 1];
|
||||
const fFileType = getFileTypeFromExtensionForLivePhotoClustering(
|
||||
getFileName(f.file),
|
||||
);
|
||||
const gFileType = getFileTypeFromExtensionForLivePhotoClustering(
|
||||
getFileName(g.file),
|
||||
);
|
||||
const fFileIdentifier: LivePhotoIdentifier = {
|
||||
collectionID: f.collectionID,
|
||||
fileType: fFileType,
|
||||
name: getFileName(f.file),
|
||||
/* TODO(MR): ElectronFile changes */
|
||||
size: (firstMediaFile as FileWithCollection).file.size,
|
||||
size: (f as FileWithCollection).file.size,
|
||||
};
|
||||
const secondFileIdentifier: LivePhotoIdentifier = {
|
||||
collectionID: secondMediaFile.collectionID,
|
||||
fileType: secondFileType,
|
||||
name: getFileName(secondMediaFile.file),
|
||||
const gFileIdentifier: LivePhotoIdentifier = {
|
||||
collectionID: g.collectionID,
|
||||
fileType: gFileType,
|
||||
name: getFileName(g.file),
|
||||
/* TODO(MR): ElectronFile changes */
|
||||
size: (secondMediaFile as FileWithCollection).file.size,
|
||||
size: (g as FileWithCollection).file.size,
|
||||
};
|
||||
if (
|
||||
areFilesLivePhotoAssets(
|
||||
firstFileIdentifier,
|
||||
secondFileIdentifier,
|
||||
)
|
||||
) {
|
||||
if (areLivePhotoAssets(fFileIdentifier, gFileIdentifier)) {
|
||||
let imageFile: File | ElectronFile | string;
|
||||
let videoFile: File | ElectronFile | string;
|
||||
if (
|
||||
firstFileType === FILE_TYPE.IMAGE &&
|
||||
secondFileType === FILE_TYPE.VIDEO
|
||||
fFileType === FILE_TYPE.IMAGE &&
|
||||
gFileType === FILE_TYPE.VIDEO
|
||||
) {
|
||||
imageFile = firstMediaFile.file;
|
||||
videoFile = secondMediaFile.file;
|
||||
imageFile = f.file;
|
||||
videoFile = g.file;
|
||||
} else {
|
||||
videoFile = firstMediaFile.file;
|
||||
imageFile = secondMediaFile.file;
|
||||
videoFile = f.file;
|
||||
imageFile = g.file;
|
||||
}
|
||||
const livePhotoLocalID = firstMediaFile.localID;
|
||||
analysedMediaFiles.push({
|
||||
const livePhotoLocalID = f.localID;
|
||||
result.push({
|
||||
localID: livePhotoLocalID,
|
||||
collectionID: firstMediaFile.collectionID,
|
||||
collectionID: f.collectionID,
|
||||
isLivePhoto: true,
|
||||
livePhotoAssets: {
|
||||
image: imageFile,
|
||||
|
@ -388,20 +371,20 @@ export async function clusterLivePhotoFiles(mediaFiles: FileWithCollection2[]) {
|
|||
});
|
||||
index += 2;
|
||||
} else {
|
||||
analysedMediaFiles.push({
|
||||
...firstMediaFile,
|
||||
result.push({
|
||||
...f,
|
||||
isLivePhoto: false,
|
||||
});
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
if (index === mediaFiles.length - 1) {
|
||||
analysedMediaFiles.push({
|
||||
result.push({
|
||||
...mediaFiles[index],
|
||||
isLivePhoto: false,
|
||||
});
|
||||
}
|
||||
return analysedMediaFiles;
|
||||
return result;
|
||||
} catch (e) {
|
||||
if (e.message === CustomError.UPLOAD_CANCELLED) {
|
||||
throw e;
|
||||
|
@ -410,42 +393,44 @@ export async function clusterLivePhotoFiles(mediaFiles: FileWithCollection2[]) {
|
|||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
interface LivePhotoIdentifier {
|
||||
collectionID: number;
|
||||
fileType: FILE_TYPE;
|
||||
name: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
function areFilesLivePhotoAssets(
|
||||
firstFileIdentifier: LivePhotoIdentifier,
|
||||
secondFileIdentifier: LivePhotoIdentifier,
|
||||
) {
|
||||
const haveSameCollectionID =
|
||||
firstFileIdentifier.collectionID === secondFileIdentifier.collectionID;
|
||||
const areNotSameFileType =
|
||||
firstFileIdentifier.fileType !== secondFileIdentifier.fileType;
|
||||
const areLivePhotoAssets = (f: LivePhotoIdentifier, g: LivePhotoIdentifier) => {
|
||||
const haveSameCollectionID = f.collectionID === g.collectionID;
|
||||
const areNotSameFileType = f.fileType !== g.fileType;
|
||||
|
||||
let firstFileNameWithoutSuffix: string;
|
||||
let secondFileNameWithoutSuffix: string;
|
||||
if (firstFileIdentifier.fileType === FILE_TYPE.IMAGE) {
|
||||
if (f.fileType === FILE_TYPE.IMAGE) {
|
||||
firstFileNameWithoutSuffix = removePotentialLivePhotoSuffix(
|
||||
getFileNameWithoutExtension(firstFileIdentifier.name),
|
||||
getFileNameWithoutExtension(f.name),
|
||||
// Note: The Google Live Photo image file can have video extension appended as suffix, passing that to removePotentialLivePhotoSuffix to remove it
|
||||
// Example: IMG_20210630_0001.mp4.jpg (Google Live Photo image file)
|
||||
getFileExtensionWithDot(secondFileIdentifier.name),
|
||||
getFileExtensionWithDot(g.name),
|
||||
);
|
||||
secondFileNameWithoutSuffix = removePotentialLivePhotoSuffix(
|
||||
getFileNameWithoutExtension(secondFileIdentifier.name),
|
||||
getFileNameWithoutExtension(g.name),
|
||||
);
|
||||
} else {
|
||||
firstFileNameWithoutSuffix = removePotentialLivePhotoSuffix(
|
||||
getFileNameWithoutExtension(firstFileIdentifier.name),
|
||||
getFileNameWithoutExtension(f.name),
|
||||
);
|
||||
secondFileNameWithoutSuffix = removePotentialLivePhotoSuffix(
|
||||
getFileNameWithoutExtension(secondFileIdentifier.name),
|
||||
getFileExtensionWithDot(firstFileIdentifier.name),
|
||||
getFileNameWithoutExtension(g.name),
|
||||
getFileExtensionWithDot(f.name),
|
||||
);
|
||||
}
|
||||
if (
|
||||
haveSameCollectionID &&
|
||||
isImageOrVideo(firstFileIdentifier.fileType) &&
|
||||
isImageOrVideo(secondFileIdentifier.fileType) &&
|
||||
isImageOrVideo(f.fileType) &&
|
||||
isImageOrVideo(g.fileType) &&
|
||||
areNotSameFileType &&
|
||||
firstFileNameWithoutSuffix === secondFileNameWithoutSuffix
|
||||
) {
|
||||
|
@ -455,23 +440,20 @@ function areFilesLivePhotoAssets(
|
|||
// I did that based on the assumption that live photo assets ideally would not be larger than LIVE_PHOTO_ASSET_SIZE_LIMIT
|
||||
// also zipping library doesn't support stream as a input
|
||||
if (
|
||||
firstFileIdentifier.size <= LIVE_PHOTO_ASSET_SIZE_LIMIT &&
|
||||
secondFileIdentifier.size <= LIVE_PHOTO_ASSET_SIZE_LIMIT
|
||||
f.size <= LIVE_PHOTO_ASSET_SIZE_LIMIT &&
|
||||
g.size <= LIVE_PHOTO_ASSET_SIZE_LIMIT
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
log.error(
|
||||
`${CustomError.TOO_LARGE_LIVE_PHOTO_ASSETS} - ${JSON.stringify({
|
||||
fileSizes: [
|
||||
firstFileIdentifier.size,
|
||||
secondFileIdentifier.size,
|
||||
],
|
||||
fileSizes: [f.size, g.size],
|
||||
})}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
function removePotentialLivePhotoSuffix(
|
||||
filenameWithoutExtension: string,
|
||||
|
|
|
@ -367,19 +367,13 @@ class UploadManager {
|
|||
);
|
||||
await this.parseMetadataJSONFiles(metadataJSONFiles);
|
||||
}
|
||||
|
||||
if (mediaFiles.length) {
|
||||
log.info(`clusterLivePhotoFiles started`);
|
||||
const analysedMediaFiles =
|
||||
await clusterLivePhotoFiles(mediaFiles);
|
||||
log.info(`clusterLivePhotoFiles ended`);
|
||||
log.info(
|
||||
`got live photos: ${
|
||||
mediaFiles.length !== analysedMediaFiles.length
|
||||
}`,
|
||||
);
|
||||
const clusteredMediaFiles = await clusterLivePhotos(mediaFiles);
|
||||
|
||||
this.uiService.setFilenames(
|
||||
new Map<number, string>(
|
||||
analysedMediaFiles.map((mediaFile) => [
|
||||
clusteredMediaFiles.map((mediaFile) => [
|
||||
mediaFile.localID,
|
||||
assetName(mediaFile),
|
||||
]),
|
||||
|
@ -387,10 +381,10 @@ class UploadManager {
|
|||
);
|
||||
|
||||
this.uiService.setHasLivePhoto(
|
||||
mediaFiles.length !== analysedMediaFiles.length,
|
||||
mediaFiles.length !== clusteredMediaFiles.length,
|
||||
);
|
||||
|
||||
await this.uploadMediaFiles(analysedMediaFiles);
|
||||
await this.uploadMediaFiles(clusteredMediaFiles);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.message === CustomError.UPLOAD_CANCELLED) {
|
||||
|
|
Loading…
Add table
Reference in a new issue