mirror of
https://github.com/ente-io/ente.git
synced 2025-08-14 10:16:10 +00:00
Towards new layering
This commit is contained in:
@@ -4,10 +4,7 @@ import { type Electron } from "@/base/types/ipc";
|
||||
import { downloadAndRevokeObjectURL } from "@/base/utils/web";
|
||||
import { downloadManager } from "@/gallery/services/download";
|
||||
import { updateFileMagicMetadata } from "@/gallery/services/file";
|
||||
import {
|
||||
isArchivedFile,
|
||||
updateMagicMetadata,
|
||||
} from "@/gallery/services/magic-metadata";
|
||||
import { updateMagicMetadata } from "@/gallery/services/magic-metadata";
|
||||
import { detectFileTypeInfo } from "@/gallery/utils/detect-type";
|
||||
import { writeStream } from "@/gallery/utils/native-stream";
|
||||
import {
|
||||
@@ -15,7 +12,7 @@ import {
|
||||
FileMagicMetadataProps,
|
||||
FileWithUpdatedMagicMetadata,
|
||||
} from "@/media/file";
|
||||
import { ItemVisibility } from "@/media/file-metadata";
|
||||
import { ItemVisibility, isArchivedFile } from "@/media/file-metadata";
|
||||
import { FileType } from "@/media/file-type";
|
||||
import { decodeLivePhoto } from "@/media/live-photo";
|
||||
import { deleteFromTrash, moveToTrash } from "@/new/photos/services/collection";
|
||||
|
@@ -18,7 +18,7 @@ import {
|
||||
type FileInfoProps,
|
||||
} from "@/gallery/components/FileInfo";
|
||||
import type { Collection } from "@/media/collection";
|
||||
import { ItemVisibility } from "@/media/file-metadata";
|
||||
import { fileVisibility, ItemVisibility } from "@/media/file-metadata";
|
||||
import { FileType } from "@/media/file-type";
|
||||
import type { EnteFile } from "@/media/file.js";
|
||||
import { isHEICExtension, needsJPEGConversion } from "@/media/formats";
|
||||
@@ -53,7 +53,6 @@ import React, {
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { fileVisibility } from "../../services/magic-metadata";
|
||||
import {
|
||||
fileInfoExifForFile,
|
||||
updateItemDataAlt,
|
||||
|
@@ -3,41 +3,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||
import { sharedCryptoWorker } from "@/base/crypto";
|
||||
import type { Collection } from "@/media/collection";
|
||||
import { fileLogID, type EnteFile, type MagicMetadataCore } from "@/media/file";
|
||||
import {
|
||||
ItemVisibility,
|
||||
type PrivateMagicMetadata,
|
||||
} from "@/media/file-metadata";
|
||||
|
||||
/**
|
||||
* Return the magic metadata for an {@link EnteFile}.
|
||||
*
|
||||
* We are not expected to be in a scenario where the file gets to the UI without
|
||||
* having its magic metadata decrypted, so this function is a sanity
|
||||
* check and should be a no-op in usually. It'll throw if it finds its
|
||||
* assumptions broken. Once the types have been refactored this entire
|
||||
* check/cast shouldn't be needed, and this should become a trivial accessor.
|
||||
*/
|
||||
export const fileMagicMetadata = (file: EnteFile) => {
|
||||
if (!file.magicMetadata) return undefined;
|
||||
if (typeof file.magicMetadata.data == "string") {
|
||||
throw new Error(
|
||||
`Magic metadata for ${fileLogID(file)} had not been decrypted even when the file reached the UI layer`,
|
||||
);
|
||||
}
|
||||
// This cast is unavoidable in the current setup. We need to refactor the
|
||||
// types so that this cast in not needed.
|
||||
return file.magicMetadata.data as PrivateMagicMetadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the {@link ItemVisibility} for the given {@link file}.
|
||||
*/
|
||||
export const fileVisibility = (file: EnteFile) =>
|
||||
fileMagicMetadata(file)?.visibility;
|
||||
|
||||
export const isArchivedFile = (item: EnteFile) =>
|
||||
fileVisibility(item) === ItemVisibility.archived;
|
||||
import { type MagicMetadataCore } from "@/media/file";
|
||||
import { ItemVisibility } from "@/media/file-metadata";
|
||||
|
||||
export const isArchivedCollection = (item: Collection) => {
|
||||
if (!item) {
|
||||
|
@@ -152,6 +152,8 @@ export interface Metadata {
|
||||
* - Unlike {@link PublicMagicMetadata}, this is only available to the owner of
|
||||
* the file.
|
||||
*
|
||||
* [Note: Private magic metadata is called magic metadata on remote]
|
||||
*
|
||||
* For historical reasons, the unqualified phrase "magic metadata" in various
|
||||
* APIs refers to the (this) private metadata, even though the mutable public
|
||||
* metadata is the much more frequently used of the two. See: [Note: Metadatum].
|
||||
@@ -294,6 +296,29 @@ const PublicMagicMetadata = z
|
||||
})
|
||||
.passthrough();
|
||||
|
||||
/**
|
||||
* Return the private magic metadata for an {@link EnteFile}.
|
||||
*
|
||||
* We are not expected to be in a scenario where the file gets to the UI without
|
||||
* having its private magic metadata decrypted, so this function is a sanity
|
||||
* check and should be a no-op in usually. It'll throw if it finds its
|
||||
* assumptions broken. Once the types have been refactored this entire
|
||||
* check/cast shouldn't be needed, and this should become a trivial accessor.
|
||||
*/
|
||||
export const filePrivateMagicMetadata = (file: EnteFile) => {
|
||||
// TODO: Audit the types.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!file.magicMetadata) return undefined;
|
||||
if (typeof file.magicMetadata.data == "string") {
|
||||
throw new Error(
|
||||
`Private magic metadata for ${fileLogID(file)} had not been decrypted even when the file reached the UI layer`,
|
||||
);
|
||||
}
|
||||
// This cast is unavoidable in the current setup. We need to refactor the
|
||||
// types so that this cast in not needed.
|
||||
return file.magicMetadata.data as PrivateMagicMetadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the public magic metadata for an {@link EnteFile}.
|
||||
*
|
||||
@@ -410,6 +435,35 @@ export const fileCreationPhotoDate = (
|
||||
file.metadata.creationTime,
|
||||
);
|
||||
|
||||
/**
|
||||
* Update the private magic metadata associated with a file on remote.
|
||||
*
|
||||
* @param file The {@link EnteFile} whose public magic metadata we want to
|
||||
* update.
|
||||
*
|
||||
* @param metadataUpdates A subset of {@link PrivateMagicMetadata} containing the
|
||||
* fields that we want to add or update.
|
||||
*/
|
||||
export const updateRemotePrivateMagicMetadata = async (
|
||||
file: EnteFile,
|
||||
metadataUpdates: Partial<PrivateMagicMetadata>,
|
||||
) => {
|
||||
const existingMetadata = filePrivateMagicMetadata(file);
|
||||
|
||||
const updatedMetadata = { ...(existingMetadata ?? {}), ...metadataUpdates };
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const metadataVersion = file.magicMetadata?.version ?? 1;
|
||||
|
||||
const updateRequest = await updateMagicMetadataRequest(
|
||||
file,
|
||||
updatedMetadata,
|
||||
metadataVersion,
|
||||
);
|
||||
|
||||
return putFilesPrivateMagicMetadata(updateRequest);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the public magic metadata associated with a file on remote.
|
||||
*
|
||||
@@ -553,13 +607,14 @@ const updateMagicMetadataRequest = async (
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the magic metadata for a list of files.
|
||||
* Update the (private) magic metadata for a list of files.
|
||||
*
|
||||
* See: [Note: Private magic metadata is called magic metadata on remote]
|
||||
*
|
||||
* @param request The list of file ids and the updated encrypted magic metadata
|
||||
* associated with each of them.
|
||||
*/
|
||||
// TODO: Remove export once this is used.
|
||||
export const putFilesMagicMetadata = async (
|
||||
const putFilesPrivateMagicMetadata = async (
|
||||
request: UpdateMagicMetadataRequest,
|
||||
) =>
|
||||
ensureOk(
|
||||
@@ -587,6 +642,46 @@ const putFilesPublicMagicMetadata = async (
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the {@link ItemVisibility} for the given {@link file}.
|
||||
*/
|
||||
export const fileVisibility = (file: EnteFile) =>
|
||||
filePrivateMagicMetadata(file)?.visibility;
|
||||
|
||||
/**
|
||||
* Return `true` if the {@link ItemVisibility} of the given {@link file} is
|
||||
* archived.
|
||||
*/
|
||||
export const isArchivedFile = (item: EnteFile) =>
|
||||
fileVisibility(item) === ItemVisibility.archived;
|
||||
|
||||
/**
|
||||
* Return the GPS coordinates (if any) present in the given {@link EnteFile}.
|
||||
*/
|
||||
export const fileLocation = (file: EnteFile): Location | undefined => {
|
||||
// TODO: EnteFile types. Need to verify that metadata itself, and
|
||||
// metadata.lat/lng can not be null (I think they likely can, if so need to
|
||||
// update the types). Need to supress the linter meanwhile.
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!file.metadata) return undefined;
|
||||
|
||||
const latitude = nullToUndefined(file.metadata.latitude);
|
||||
const longitude = nullToUndefined(file.metadata.longitude);
|
||||
|
||||
if (latitude === undefined || longitude === undefined) return undefined;
|
||||
if (Number.isNaN(latitude) || Number.isNaN(longitude)) return undefined;
|
||||
|
||||
return { latitude, longitude };
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the caption, aka "description", (if any) attached to the given
|
||||
* {@link EnteFile}.
|
||||
*/
|
||||
export const fileCaption = (file: EnteFile): string | undefined =>
|
||||
filePublicMagicMetadata(file)?.caption;
|
||||
|
||||
/**
|
||||
* Metadata about a file extracted from various sources (like Exif) when
|
||||
* uploading it into Ente.
|
||||
@@ -835,30 +930,3 @@ export const createPhotoDate = (
|
||||
return new Date(dateLike / 1000);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the GPS coordinates (if any) present in the given {@link EnteFile}.
|
||||
*/
|
||||
export const fileLocation = (file: EnteFile): Location | undefined => {
|
||||
// TODO: EnteFile types. Need to verify that metadata itself, and
|
||||
// metadata.lat/lng can not be null (I think they likely can, if so need to
|
||||
// update the types). Need to supress the linter meanwhile.
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!file.metadata) return undefined;
|
||||
|
||||
const latitude = nullToUndefined(file.metadata.latitude);
|
||||
const longitude = nullToUndefined(file.metadata.longitude);
|
||||
|
||||
if (latitude === undefined || longitude === undefined) return undefined;
|
||||
if (Number.isNaN(latitude) || Number.isNaN(longitude)) return undefined;
|
||||
|
||||
return { latitude, longitude };
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the caption, aka "description", (if any) attached to the given
|
||||
* {@link EnteFile}.
|
||||
*/
|
||||
export const fileCaption = (file: EnteFile): string | undefined =>
|
||||
filePublicMagicMetadata(file)?.caption;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
isArchivedCollection,
|
||||
isArchivedFile,
|
||||
isPinnedCollection,
|
||||
} from "@/gallery/services/magic-metadata";
|
||||
import {
|
||||
@@ -10,7 +9,7 @@ import {
|
||||
} from "@/media/collection";
|
||||
import type { EnteFile } from "@/media/file";
|
||||
import { mergeMetadata } from "@/media/file";
|
||||
import { ItemVisibility } from "@/media/file-metadata";
|
||||
import { isArchivedFile, ItemVisibility } from "@/media/file-metadata";
|
||||
import {
|
||||
createCollectionNameByID,
|
||||
isHiddenCollection,
|
||||
|
Reference in New Issue
Block a user