This commit is contained in:
Manav Rathi 2024-04-29 20:35:00 +05:30
parent 61de0c9c9c
commit 2c62f983a8
No known key found for this signature in database
3 changed files with 197 additions and 237 deletions

View file

@ -21,12 +21,12 @@ import {
savePublicCollectionUploaderName, savePublicCollectionUploaderName,
} from "services/publicCollectionService"; } from "services/publicCollectionService";
import type { import type {
FileWithCollection,
InProgressUpload, InProgressUpload,
SegregatedFinishedUploads, SegregatedFinishedUploads,
UploadCounter, UploadCounter,
UploadFileNames, UploadFileNames,
UploadItem, UploadItem,
UploadItemWithCollection,
} from "services/upload/uploadManager"; } from "services/upload/uploadManager";
import uploadManager from "services/upload/uploadManager"; import uploadManager from "services/upload/uploadManager";
import watcher from "services/watch"; import watcher from "services/watch";
@ -86,6 +86,7 @@ interface Props {
} }
export default function Uploader({ export default function Uploader({
isFirstUpload,
dragAndDropFiles, dragAndDropFiles,
openFileSelector, openFileSelector,
fileSelectorFiles, fileSelectorFiles,
@ -162,12 +163,14 @@ export default function Uploader({
* {@link desktopFiles}, {@link desktopFilePaths} and * {@link desktopFiles}, {@link desktopFilePaths} and
* {@link desktopZipEntries}. * {@link desktopZipEntries}.
* *
* Augment each {@link UploadItem} with its "path" (relative path or name in
* the case of {@link webFiles}, absolute path in the case of
* {@link desktopFiles}, {@link desktopFilePaths}, and the path within the
* zip file for {@link desktopZipEntries}).
*
* See the documentation of {@link UploadItem} for more details. * See the documentation of {@link UploadItem} for more details.
*/ */
const uploadItems = useRef<UploadItem[]>([]); const uploadItemsAndPaths = useRef<[UploadItem, string][]>([]);
// TODO(MR): temp, doesn't have zips
const fileOrPathsToUpload = useRef<(File | string)[]>([]);
/** /**
* If true, then the next upload we'll be processing was initiated by our * If true, then the next upload we'll be processing was initiated by our
@ -301,15 +304,15 @@ export default function Uploader({
// Trigger an upload when any of the dependencies change. // Trigger an upload when any of the dependencies change.
useEffect(() => { useEffect(() => {
const itemAndPaths = [ const allItemAndPaths = [
/* TODO(MR): ElectronFile | use webkitRelativePath || name here */ /* TODO(MR): ElectronFile | use webkitRelativePath || name here */
webFiles.map((f) => [f, f["path"]]), webFiles.map((f) => [f, f["path"] ?? f.name]),
desktopFiles.map((fp) => [fp, fp.path]), desktopFiles.map((fp) => [fp, fp.path]),
desktopFilePaths.map((p) => [p, p]), desktopFilePaths.map((p) => [p, p]),
desktopZipEntries.map((ze) => [ze, ze[1]]), desktopZipEntries.map((ze) => [ze, ze[1]]),
].flat(); ].flat() as [UploadItem, string][];
if (itemAndPaths.length == 0) return; if (allItemAndPaths.length == 0) return;
if (uploadManager.isUploadRunning()) { if (uploadManager.isUploadRunning()) {
if (watcher.isUploadRunning()) { if (watcher.isUploadRunning()) {
@ -333,42 +336,93 @@ export default function Uploader({
setDesktopZipEntries([]); setDesktopZipEntries([]);
// Remove hidden files (files whose names begins with a "."). // Remove hidden files (files whose names begins with a ".").
const prunedItemAndPaths = itemAndPaths.filter( const prunedItemAndPaths = allItemAndPaths.filter(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
([_, p]) => !basename(p).startsWith("."), ([_, p]) => !basename(p).startsWith("."),
); );
uploadItems.current = prunedItemAndPaths.map(([i]) => i); uploadItemsAndPaths.current = prunedItemAndPaths;
fileOrPathsToUpload.current = uploadItems.current if (uploadItemsAndPaths.current.length === 0) {
.map((i) => {
if (typeof i == "string" || i instanceof File) return i;
if (Array.isArray(i)) return undefined;
return i.file;
})
.filter((x) => x);
uploadItems.current = [];
if (fileOrPathsToUpload.current.length === 0) {
props.setLoading(false); props.setLoading(false);
return; return;
} }
const importSuggestion = getImportSuggestion( const importSuggestion = getImportSuggestion(
pickedUploadType.current, pickedUploadType.current,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
prunedItemAndPaths.map(([_, p]) => p), prunedItemAndPaths.map(([_, p]) => p),
); );
setImportSuggestion(importSuggestion); setImportSuggestion(importSuggestion);
log.debug(() => "Uploader invoked:"); log.debug(() => "Uploader invoked:");
log.debug(() => fileOrPathsToUpload.current); log.debug(() => uploadItemsAndPaths.current);
log.debug(() => importSuggestion); log.debug(() => importSuggestion);
handleCollectionCreationAndUpload( const _pickedUploadType = pickedUploadType.current;
importSuggestion,
props.isFirstUpload,
pickedUploadType.current,
publicCollectionGalleryContext.accessedThroughSharedURL,
);
pickedUploadType.current = null; pickedUploadType.current = null;
props.setLoading(false); props.setLoading(false);
(async () => {
if (publicCollectionGalleryContext.accessedThroughSharedURL) {
const uploaderName = await getPublicCollectionUploaderName(
getPublicCollectionUID(
publicCollectionGalleryContext.token,
),
);
uploaderNameRef.current = uploaderName;
showUserNameInputDialog();
return;
}
if (isPendingDesktopUpload.current) {
isPendingDesktopUpload.current = false;
if (pendingDesktopUploadCollectionName.current) {
uploadFilesToNewCollections(
"root",
pendingDesktopUploadCollectionName.current,
);
pendingDesktopUploadCollectionName.current = null;
} else {
uploadFilesToNewCollections("parent");
}
return;
}
if (electron && _pickedUploadType === PICKED_UPLOAD_TYPE.ZIPS) {
uploadFilesToNewCollections("parent");
return;
}
if (isFirstUpload && !importSuggestion.rootFolderName) {
importSuggestion.rootFolderName = FIRST_ALBUM_NAME;
}
if (isDragAndDrop.current) {
isDragAndDrop.current = false;
if (
props.activeCollection &&
props.activeCollection.owner.id === galleryContext.user?.id
) {
uploadFilesToExistingCollection(props.activeCollection);
return;
}
}
let showNextModal = () => {};
if (importSuggestion.hasNestedFolders) {
showNextModal = () => setChoiceModalView(true);
} else {
showNextModal = () =>
showCollectionCreateModal(importSuggestion.rootFolderName);
}
props.setCollectionSelectorAttributes({
callback: uploadFilesToExistingCollection,
onCancel: handleCollectionSelectorCancel,
showNextModal,
intent: CollectionSelectorIntent.upload,
});
})();
}, [webFiles, desktopFiles, desktopFilePaths, desktopZipEntries]); }, [webFiles, desktopFiles, desktopFilePaths, desktopZipEntries]);
const preCollectionCreationAction = async () => { const preCollectionCreationAction = async () => {
@ -382,100 +436,78 @@ export default function Uploader({
collection: Collection, collection: Collection,
uploaderName?: string, uploaderName?: string,
) => { ) => {
try { await preCollectionCreationAction();
log.info( const uploadItemsWithCollection = uploadItemsAndPaths.current.map(
`Uploading files existing collection id ${collection.id} (${collection.name})`, ([uploadItem], index) => ({
); uploadItem,
await preCollectionCreationAction(); localID: index,
const filesWithCollectionToUpload = fileOrPathsToUpload.current.map( collectionID: collection.id,
(fileOrPath, index) => ({ }),
fileOrPath, );
localID: index, await waitInQueueAndUploadFiles(
collectionID: collection.id, uploadItemsWithCollection,
}), [collection],
); uploaderName,
await waitInQueueAndUploadFiles( );
filesWithCollectionToUpload, uploadItemsAndPaths.current = null;
[collection],
uploaderName,
);
} catch (e) {
log.error("Failed to upload files to existing collection", e);
}
}; };
const uploadFilesToNewCollections = async ( const uploadFilesToNewCollections = async (
mapping: CollectionMapping, mapping: CollectionMapping,
collectionName?: string, collectionName?: string,
) => { ) => {
try { await preCollectionCreationAction();
log.info( let uploadItemsWithCollection: UploadItemWithCollection[] = [];
`Uploading files to collection using ${mapping} mapping (${collectionName ?? "<NA>"})`, const collections: Collection[] = [];
let collectionNameToUploadItems = new Map<string, UploadItem[]>();
if (mapping == "root") {
collectionNameToUploadItems.set(
collectionName,
uploadItemsAndPaths.current.map(([i]) => i),
); );
await preCollectionCreationAction(); } else {
let filesWithCollectionToUpload: FileWithCollection[] = []; collectionNameToUploadItems = groupFilesBasedOnParentFolder(
const collections: Collection[] = []; uploadItemsAndPaths.current,
let collectionNameToFileOrPaths = new Map<
string,
(File | string)[]
>();
if (mapping == "root") {
collectionNameToFileOrPaths.set(
collectionName,
fileOrPathsToUpload.current,
);
} else {
collectionNameToFileOrPaths = groupFilesBasedOnParentFolder(
fileOrPathsToUpload.current,
);
}
try {
const existingCollections = await getLatestCollections();
let index = 0;
for (const [
collectionName,
fileOrPaths,
] of collectionNameToFileOrPaths) {
const collection = await getOrCreateAlbum(
collectionName,
existingCollections,
);
collections.push(collection);
props.setCollections([
...existingCollections,
...collections,
]);
filesWithCollectionToUpload = [
...filesWithCollectionToUpload,
...fileOrPaths.map((fileOrPath) => ({
localID: index++,
collectionID: collection.id,
fileOrPath,
})),
];
}
} catch (e) {
closeUploadProgress();
log.error("Failed to create album", e);
appContext.setDialogMessage({
title: t("ERROR"),
close: { variant: "critical" },
content: t("CREATE_ALBUM_FAILED"),
});
throw e;
}
await waitInQueueAndUploadFiles(
filesWithCollectionToUpload,
collections,
); );
fileOrPathsToUpload.current = null;
} catch (e) {
log.error("Failed to upload files to new collections", e);
} }
try {
const existingCollections = await getLatestCollections();
let index = 0;
for (const [
collectionName,
fileOrPaths,
] of collectionNameToUploadItems) {
const collection = await getOrCreateAlbum(
collectionName,
existingCollections,
);
collections.push(collection);
props.setCollections([...existingCollections, ...collections]);
uploadItemsWithCollection = [
...uploadItemsWithCollection,
...fileOrPaths.map((fileOrPath) => ({
localID: index++,
collectionID: collection.id,
fileOrPath,
})),
];
}
} catch (e) {
closeUploadProgress();
log.error("Failed to create album", e);
appContext.setDialogMessage({
title: t("ERROR"),
close: { variant: "critical" },
content: t("CREATE_ALBUM_FAILED"),
});
throw e;
}
await waitInQueueAndUploadFiles(uploadItemsWithCollection, collections);
uploadItemsAndPaths.current = null;
}; };
const waitInQueueAndUploadFiles = async ( const waitInQueueAndUploadFiles = async (
filesWithCollectionToUploadIn: FileWithCollection[], uploadItemsWithCollection: UploadItemWithCollection[],
collections: Collection[], collections: Collection[],
uploaderName?: string, uploaderName?: string,
) => { ) => {
@ -484,7 +516,7 @@ export default function Uploader({
currentPromise, currentPromise,
async () => async () =>
await uploadFiles( await uploadFiles(
filesWithCollectionToUploadIn, uploadItemsWithCollection,
collections, collections,
uploaderName, uploaderName,
), ),
@ -505,7 +537,7 @@ export default function Uploader({
} }
const uploadFiles = async ( const uploadFiles = async (
filesWithCollectionToUploadIn: FileWithCollection[], uploadItemsWithCollection: UploadItemWithCollection[],
collections: Collection[], collections: Collection[],
uploaderName?: string, uploaderName?: string,
) => { ) => {
@ -519,11 +551,13 @@ export default function Uploader({
setPendingUploads( setPendingUploads(
electron, electron,
collections, collections,
filesWithCollectionToUploadIn, uploadItemsWithCollection
.map(({ uploadItem }) => uploadItem)
.filter((x) => x),
); );
} }
const wereFilesProcessed = await uploadManager.uploadFiles( const wereFilesProcessed = await uploadManager.uploadFiles(
filesWithCollectionToUploadIn, uploadItemsWithCollection,
collections, collections,
uploaderName, uploaderName,
); );
@ -531,11 +565,12 @@ export default function Uploader({
if (isElectron()) { if (isElectron()) {
if (watcher.isUploadRunning()) { if (watcher.isUploadRunning()) {
await watcher.allFileUploadsDone( await watcher.allFileUploadsDone(
filesWithCollectionToUploadIn, uploadItemsWithCollection,
collections, collections,
); );
} else if (watcher.isSyncPaused()) { } else if (watcher.isSyncPaused()) {
// resume the service after user upload is done // Resume folder watch after the user upload that
// interrupted it is done.
watcher.resumePausedSync(); watcher.resumePausedSync();
} }
} }
@ -610,78 +645,6 @@ export default function Uploader({
}); });
}; };
const handleCollectionCreationAndUpload = async (
importSuggestion: ImportSuggestion,
isFirstUpload: boolean,
pickedUploadType: PICKED_UPLOAD_TYPE,
accessedThroughSharedURL?: boolean,
) => {
try {
if (accessedThroughSharedURL) {
const uploaderName = await getPublicCollectionUploaderName(
getPublicCollectionUID(
publicCollectionGalleryContext.token,
),
);
uploaderNameRef.current = uploaderName;
showUserNameInputDialog();
return;
}
if (isPendingDesktopUpload.current) {
isPendingDesktopUpload.current = false;
if (pendingDesktopUploadCollectionName.current) {
uploadFilesToNewCollections(
"root",
pendingDesktopUploadCollectionName.current,
);
pendingDesktopUploadCollectionName.current = null;
} else {
uploadFilesToNewCollections("parent");
}
return;
}
if (isElectron() && pickedUploadType === PICKED_UPLOAD_TYPE.ZIPS) {
uploadFilesToNewCollections("parent");
return;
}
if (isFirstUpload && !importSuggestion.rootFolderName) {
importSuggestion.rootFolderName = FIRST_ALBUM_NAME;
}
if (isDragAndDrop.current) {
isDragAndDrop.current = false;
if (
props.activeCollection &&
props.activeCollection.owner.id === galleryContext.user?.id
) {
uploadFilesToExistingCollection(props.activeCollection);
return;
}
}
let showNextModal = () => {};
if (importSuggestion.hasNestedFolders) {
showNextModal = () => setChoiceModalView(true);
} else {
showNextModal = () =>
showCollectionCreateModal(importSuggestion.rootFolderName);
}
props.setCollectionSelectorAttributes({
callback: uploadFilesToExistingCollection,
onCancel: handleCollectionSelectorCancel,
showNextModal,
intent: CollectionSelectorIntent.upload,
});
} catch (e) {
// TODO(MR): Why?
log.warn("Ignoring error in handleCollectionCreationAndUpload", e);
}
};
const cancelUploads = () => { const cancelUploads = () => {
uploadManager.cancelRunningUpload(); uploadManager.cancelRunningUpload();
}; };
@ -784,7 +747,7 @@ export default function Uploader({
open={userNameInputDialogView} open={userNameInputDialogView}
onClose={handleUserNameInputDialogClose} onClose={handleUserNameInputDialogClose}
onNameSubmit={handlePublicUpload} onNameSubmit={handlePublicUpload}
toUploadFilesCount={fileOrPathsToUpload.current?.length} toUploadFilesCount={uploadItemsAndPaths.current?.length}
uploaderName={uploaderNameRef.current} uploaderName={uploaderNameRef.current}
/> />
</> </>
@ -884,16 +847,12 @@ function getImportSuggestion(
// [a => [j], // [a => [j],
// b => [e,f,g], // b => [e,f,g],
// c => [h, i]] // c => [h, i]]
const groupFilesBasedOnParentFolder = (fileOrPaths: (File | string)[]) => { const groupFilesBasedOnParentFolder = (
const result = new Map<string, (File | string)[]>(); uploadItemsAndPaths: [UploadItem, string][],
for (const fileOrPath of fileOrPaths) { ) => {
const filePath = const result = new Map<string, UploadItem[]>();
/* TODO(MR): ElectronFile */ for (const [uploadItem, pathOrName] of uploadItemsAndPaths) {
typeof fileOrPath == "string" let folderPath = pathOrName.substring(0, pathOrName.lastIndexOf("/"));
? fileOrPath
: (fileOrPath["path"] as string);
let folderPath = filePath.substring(0, filePath.lastIndexOf("/"));
// If the parent folder of a file is "metadata" // If the parent folder of a file is "metadata"
// we consider it to be part of the parent folder // we consider it to be part of the parent folder
// For Eg,For FileList -> [a/x.png, a/metadata/x.png.json] // For Eg,For FileList -> [a/x.png, a/metadata/x.png.json]
@ -907,7 +866,7 @@ const groupFilesBasedOnParentFolder = (fileOrPaths: (File | string)[]) => {
); );
if (!folderName) throw Error("Unexpected empty folder name"); if (!folderName) throw Error("Unexpected empty folder name");
if (!result.has(folderName)) result.set(folderName, []); if (!result.has(folderName)) result.set(folderName, []);
result.get(folderName).push(fileOrPath); result.get(folderName).push(uploadItem);
} }
return result; return result;
}; };

View file

@ -109,17 +109,17 @@ const maxConcurrentUploads = 4;
*/ */
export type UploadItem = File | FileAndPath | string | ZipEntry; export type UploadItem = File | FileAndPath | string | ZipEntry;
export interface FileWithCollection { export interface UploadItemWithCollection {
localID: number; localID: number;
collectionID: number; collectionID: number;
isLivePhoto?: boolean; isLivePhoto?: boolean;
fileOrPath?: File | string; uploadItem?: UploadItem;
livePhotoAssets?: LivePhotoAssets; livePhotoAssets?: LivePhotoAssets;
} }
export interface LivePhotoAssets { export interface LivePhotoAssets {
image: File | string; image: UploadItem;
video: File | string; video: UploadItem;
} }
export interface PublicUploadProps { export interface PublicUploadProps {
@ -419,7 +419,7 @@ class UploadManager {
* @returns `true` if at least one file was processed * @returns `true` if at least one file was processed
*/ */
public async uploadFiles( public async uploadFiles(
filesWithCollectionToUploadIn: FileWithCollection[], filesWithCollectionToUploadIn: UploadItemWithCollection[],
collections: Collection[], collections: Collection[],
uploaderName?: string, uploaderName?: string,
) { ) {
@ -735,8 +735,8 @@ export default new UploadManager();
* As files progress through stages, they get more and more bits tacked on to * As files progress through stages, they get more and more bits tacked on to
* them. These types document the journey. * them. These types document the journey.
* *
* - The input is {@link FileWithCollection}. This can either be a new * - The input is {@link UploadItemWithCollection}. This can either be a new
* {@link FileWithCollection}, in which case it'll only have a * {@link UploadItemWithCollection}, in which case it'll only have a
* {@link localID}, {@link collectionID} and a {@link fileOrPath}. Or it could * {@link localID}, {@link collectionID} and a {@link fileOrPath}. Or it could
* be a retry, in which case it'll not have a {@link fileOrPath} but instead * be a retry, in which case it'll not have a {@link fileOrPath} but instead
* will have data from a previous stage (concretely, it'll just be a * will have data from a previous stage (concretely, it'll just be a
@ -772,9 +772,9 @@ type FileWithCollectionIDAndName = {
}; };
const makeFileWithCollectionIDAndName = ( const makeFileWithCollectionIDAndName = (
f: FileWithCollection, f: UploadItemWithCollection,
): FileWithCollectionIDAndName => { ): FileWithCollectionIDAndName => {
const fileOrPath = f.fileOrPath; const fileOrPath = f.uploadItem;
/* TODO(MR): ElectronFile */ /* TODO(MR): ElectronFile */
if (!(fileOrPath instanceof File || typeof fileOrPath == "string")) if (!(fileOrPath instanceof File || typeof fileOrPath == "string"))
throw new Error(`Unexpected file ${f}`); throw new Error(`Unexpected file ${f}`);

View file

@ -15,7 +15,7 @@ import { ensureString } from "@/utils/ensure";
import { UPLOAD_RESULT } from "constants/upload"; import { UPLOAD_RESULT } from "constants/upload";
import debounce from "debounce"; import debounce from "debounce";
import uploadManager, { import uploadManager, {
type FileWithCollection, type UploadItemWithCollection,
} from "services/upload/uploadManager"; } from "services/upload/uploadManager";
import { Collection } from "types/collection"; import { Collection } from "types/collection";
import { EncryptedEnteFile } from "types/file"; import { EncryptedEnteFile } from "types/file";
@ -317,16 +317,17 @@ class FolderWatcher {
} }
/** /**
* Callback invoked by the uploader whenever a file we requested to * Callback invoked by the uploader whenever a item we requested to
* {@link upload} gets uploaded. * {@link upload} gets uploaded.
*/ */
async onFileUpload( async onFileUpload(
fileUploadResult: UPLOAD_RESULT, fileUploadResult: UPLOAD_RESULT,
fileWithCollection: FileWithCollection, item: UploadItemWithCollection,
file: EncryptedEnteFile, file: EncryptedEnteFile,
) { ) {
// The files we get here will have fileWithCollection.file as a string, // Re the usage of ensureString: For desktop watch, the only possibility
// not as a File or a ElectronFile // for a UploadItem is for it to be a string (the absolute path to a
// file on disk).
if ( if (
[ [
UPLOAD_RESULT.ADDED_SYMLINK, UPLOAD_RESULT.ADDED_SYMLINK,
@ -335,18 +336,18 @@ class FolderWatcher {
UPLOAD_RESULT.ALREADY_UPLOADED, UPLOAD_RESULT.ALREADY_UPLOADED,
].includes(fileUploadResult) ].includes(fileUploadResult)
) { ) {
if (fileWithCollection.isLivePhoto) { if (item.isLivePhoto) {
this.uploadedFileForPath.set( this.uploadedFileForPath.set(
ensureString(fileWithCollection.livePhotoAssets.image), ensureString(item.livePhotoAssets.image),
file, file,
); );
this.uploadedFileForPath.set( this.uploadedFileForPath.set(
ensureString(fileWithCollection.livePhotoAssets.video), ensureString(item.livePhotoAssets.video),
file, file,
); );
} else { } else {
this.uploadedFileForPath.set( this.uploadedFileForPath.set(
ensureString(fileWithCollection.fileOrPath), ensureString(item.uploadItem),
file, file,
); );
} }
@ -355,17 +356,15 @@ class FolderWatcher {
fileUploadResult, fileUploadResult,
) )
) { ) {
if (fileWithCollection.isLivePhoto) { if (item.isLivePhoto) {
this.unUploadableFilePaths.add( this.unUploadableFilePaths.add(
ensureString(fileWithCollection.livePhotoAssets.image), ensureString(item.livePhotoAssets.image),
); );
this.unUploadableFilePaths.add( this.unUploadableFilePaths.add(
ensureString(fileWithCollection.livePhotoAssets.video), ensureString(item.livePhotoAssets.video),
); );
} else { } else {
this.unUploadableFilePaths.add( this.unUploadableFilePaths.add(ensureString(item.uploadItem));
ensureString(fileWithCollection.fileOrPath),
);
} }
} }
} }
@ -375,7 +374,7 @@ class FolderWatcher {
* {@link upload} get uploaded. * {@link upload} get uploaded.
*/ */
async allFileUploadsDone( async allFileUploadsDone(
filesWithCollection: FileWithCollection[], uploadItemsWithCollection: UploadItemWithCollection[],
collections: Collection[], collections: Collection[],
) { ) {
const electron = ensureElectron(); const electron = ensureElectron();
@ -384,14 +383,15 @@ class FolderWatcher {
log.debug(() => log.debug(() =>
JSON.stringify({ JSON.stringify({
f: "watch/allFileUploadsDone", f: "watch/allFileUploadsDone",
filesWithCollection, uploadItemsWithCollection,
collections, collections,
watch, watch,
}), }),
); );
const { syncedFiles, ignoredFiles } = const { syncedFiles, ignoredFiles } = this.deduceSyncedAndIgnored(
this.deduceSyncedAndIgnored(filesWithCollection); uploadItemsWithCollection,
);
if (syncedFiles.length > 0) if (syncedFiles.length > 0)
await electron.watch.updateSyncedFiles( await electron.watch.updateSyncedFiles(
@ -411,7 +411,9 @@ class FolderWatcher {
this.debouncedRunNextEvent(); this.debouncedRunNextEvent();
} }
private deduceSyncedAndIgnored(filesWithCollection: FileWithCollection[]) { private deduceSyncedAndIgnored(
uploadItemsWithCollection: UploadItemWithCollection[],
) {
const syncedFiles: FolderWatch["syncedFiles"] = []; const syncedFiles: FolderWatch["syncedFiles"] = [];
const ignoredFiles: FolderWatch["ignoredFiles"] = []; const ignoredFiles: FolderWatch["ignoredFiles"] = [];
@ -430,14 +432,13 @@ class FolderWatcher {
this.unUploadableFilePaths.delete(path); this.unUploadableFilePaths.delete(path);
}; };
for (const fileWithCollection of filesWithCollection) { for (const item of uploadItemsWithCollection) {
if (fileWithCollection.isLivePhoto) { // Re the usage of ensureString: For desktop watch, the only
const imagePath = ensureString( // possibility for a UploadItem is for it to be a string (the
fileWithCollection.livePhotoAssets.image, // absolute path to a file on disk).
); if (item.isLivePhoto) {
const videoPath = ensureString( const imagePath = ensureString(item.livePhotoAssets.image);
fileWithCollection.livePhotoAssets.video, const videoPath = ensureString(item.livePhotoAssets.video);
);
const imageFile = this.uploadedFileForPath.get(imagePath); const imageFile = this.uploadedFileForPath.get(imagePath);
const videoFile = this.uploadedFileForPath.get(videoPath); const videoFile = this.uploadedFileForPath.get(videoPath);
@ -453,7 +454,7 @@ class FolderWatcher {
markIgnored(videoPath); markIgnored(videoPath);
} }
} else { } else {
const path = ensureString(fileWithCollection.fileOrPath); const path = ensureString(item.uploadItem);
const file = this.uploadedFileForPath.get(path); const file = this.uploadedFileForPath.get(path);
if (file) { if (file) {
markSynced(file, path); markSynced(file, path);