Cleanup
This commit is contained in:
@@ -18,7 +18,6 @@ import { downloadManager } from "ente-gallery/services/download";
|
||||
import { extractExifDates } from "ente-gallery/services/exif";
|
||||
import { fileLogID, type EnteFile } from "ente-media/file";
|
||||
import {
|
||||
decryptPublicMagicMetadata,
|
||||
fileCreationPhotoDate,
|
||||
fileFileName,
|
||||
type ParsedMetadataDate,
|
||||
@@ -343,10 +342,7 @@ const updateFileDate = async (
|
||||
|
||||
if (!newDate) return;
|
||||
|
||||
const existingDate = fileCreationPhotoDate(
|
||||
file,
|
||||
await decryptPublicMagicMetadata(file),
|
||||
);
|
||||
const existingDate = fileCreationPhotoDate(file);
|
||||
if (newDate.timestamp == existingDate.getTime()) return;
|
||||
|
||||
await updateFilePublicMagicMetadata(file, {
|
||||
|
||||
@@ -58,11 +58,9 @@ import { tagNumericValue, type RawExifTags } from "ente-gallery/services/exif";
|
||||
import { formattedByteSize } from "ente-gallery/utils/units";
|
||||
import { type EnteFile } from "ente-media/file";
|
||||
import {
|
||||
fileCaption,
|
||||
fileCreationPhotoDate,
|
||||
fileFileName,
|
||||
fileLocation,
|
||||
filePublicMagicMetadata,
|
||||
type ParsedMetadata,
|
||||
type ParsedMetadataDate,
|
||||
} from "ente-media/file-metadata";
|
||||
@@ -260,7 +258,7 @@ export const FileInfo: React.FC<FileInfoProps> = ({
|
||||
onSelectPerson?.(personID);
|
||||
};
|
||||
|
||||
const uploaderName = filePublicMagicMetadata(file)?.uploaderName;
|
||||
const uploaderName = file.pubMagicMetadata?.data.uploaderName;
|
||||
|
||||
return (
|
||||
<FileInfoSidebar {...{ open, onClose }}>
|
||||
@@ -582,7 +580,7 @@ const Caption: React.FC<CaptionProps> = ({
|
||||
}) => {
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const caption = fileCaption(file) ?? "";
|
||||
const caption = file.pubMagicMetadata?.data.caption ?? "";
|
||||
|
||||
const formik = useFormik<{ caption: string }>({
|
||||
initialValues: { caption },
|
||||
@@ -675,10 +673,7 @@ const CreationTime: React.FC<CreationTimeProps> = ({
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const originalDate = fileCreationPhotoDate(
|
||||
file,
|
||||
filePublicMagicMetadata(file),
|
||||
);
|
||||
const originalDate = fileCreationPhotoDate(file);
|
||||
|
||||
const saveEdits = async (pickedTime: ParsedMetadataDate) => {
|
||||
setIsEditing(false);
|
||||
|
||||
@@ -37,11 +37,7 @@ import {
|
||||
type FileInfoProps,
|
||||
} from "ente-gallery/components/FileInfo";
|
||||
import type { Collection } from "ente-media/collection";
|
||||
import {
|
||||
fileFileName,
|
||||
fileVisibility,
|
||||
ItemVisibility,
|
||||
} from "ente-media/file-metadata";
|
||||
import { fileFileName, ItemVisibility } from "ente-media/file-metadata";
|
||||
import { FileType } from "ente-media/file-type";
|
||||
import type { EnteFile } from "ente-media/file.js";
|
||||
import { isHEICExtension, needsJPEGConversion } from "ente-media/formats";
|
||||
@@ -670,7 +666,7 @@ export const FileViewer: React.FC<FileViewerProps> = ({
|
||||
file &&
|
||||
activeAnnotatedFile.annotation.showArchive
|
||||
) {
|
||||
switch (fileVisibility(file)) {
|
||||
switch (file.magicMetadata?.data.visibility) {
|
||||
case undefined:
|
||||
case ItemVisibility.visible:
|
||||
isArchived = false;
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
type HLSPlaylistDataForFile,
|
||||
} from "ente-gallery/services/video";
|
||||
import type { EnteFile } from "ente-media/file";
|
||||
import { fileCaption, filePublicMagicMetadata } from "ente-media/file-metadata";
|
||||
import { FileType } from "ente-media/file-type";
|
||||
import { ensureString } from "ente-utils/ensure";
|
||||
|
||||
@@ -439,7 +438,7 @@ const enqueueUpdates = async (
|
||||
const update = (itemData: Partial<ItemData>, validTill?: Date) => {
|
||||
// Use the file's caption as its alt text (in addition to using it as
|
||||
// the visible caption).
|
||||
const alt = fileCaption(file);
|
||||
const alt = file.pubMagicMetadata?.data.caption;
|
||||
|
||||
_state.itemDataByFileID.set(file.id, {
|
||||
...itemData,
|
||||
@@ -647,8 +646,7 @@ const thumbnailDimensions = (
|
||||
{ width: thumbnailWidth, height: thumbnailHeight }: Partial<ItemData>,
|
||||
file: EnteFile,
|
||||
) => {
|
||||
const { w: imageWidth, h: imageHeight } =
|
||||
filePublicMagicMetadata(file) ?? {};
|
||||
const { w: imageWidth, h: imageHeight } = file.pubMagicMetadata?.data ?? {};
|
||||
if (thumbnailWidth && thumbnailHeight && imageWidth && imageHeight) {
|
||||
const arThumb = thumbnailWidth / thumbnailHeight;
|
||||
const arImage = imageWidth / imageHeight;
|
||||
|
||||
@@ -33,14 +33,13 @@ import type {
|
||||
EncryptedMagicMetadata,
|
||||
EnteFile,
|
||||
FilePublicMagicMetadata,
|
||||
FilePublicMagicMetadataProps,
|
||||
} from "ente-media/file";
|
||||
import {
|
||||
fileFileName,
|
||||
metadataHash,
|
||||
type FileMetadata,
|
||||
type FilePublicMagicMetadataData,
|
||||
type ParsedMetadata,
|
||||
type PublicMagicMetadata,
|
||||
} from "ente-media/file-metadata";
|
||||
import { FileType, type FileTypeInfo } from "ente-media/file-type";
|
||||
import { encodeLivePhoto } from "ente-media/live-photo";
|
||||
@@ -1047,7 +1046,7 @@ const readEntireStream = async (stream: ReadableStream) =>
|
||||
|
||||
interface ExtractAssetMetadataResult {
|
||||
metadata: FileMetadata;
|
||||
publicMagicMetadata: FilePublicMagicMetadataProps;
|
||||
publicMagicMetadata: FilePublicMagicMetadataData;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1171,7 +1170,7 @@ const extractImageOrVideoMetadata = async (
|
||||
parsedMetadataJSONMap,
|
||||
);
|
||||
|
||||
const publicMagicMetadata: PublicMagicMetadata = {};
|
||||
const publicMagicMetadata: FilePublicMagicMetadataData = {};
|
||||
|
||||
const modificationTime =
|
||||
parsedMetadataJSON?.modificationTime ?? lastModifiedMs * 1000;
|
||||
@@ -1490,7 +1489,7 @@ const augmentWithThumbnail = async (
|
||||
};
|
||||
|
||||
const constructPublicMagicMetadata = async (
|
||||
publicMagicMetadataProps: FilePublicMagicMetadataProps,
|
||||
publicMagicMetadataProps: FilePublicMagicMetadataData,
|
||||
): Promise<FilePublicMagicMetadata> => {
|
||||
const nonEmptyPublicMagicMetadataProps = getNonEmptyMagicMetadataProps(
|
||||
publicMagicMetadataProps,
|
||||
|
||||
@@ -10,7 +10,6 @@ import log from "ente-base/log";
|
||||
import { apiURL } from "ente-base/origins";
|
||||
import { ensureAuthToken } from "ente-base/token";
|
||||
import { fileLogID, type EnteFile } from "ente-media/file";
|
||||
import { filePublicMagicMetadata } from "ente-media/file-metadata";
|
||||
import { FileType } from "ente-media/file-type";
|
||||
import { updateFilePublicMagicMetadata } from "ente-new/photos/services/file";
|
||||
import {
|
||||
@@ -336,7 +335,7 @@ export const hlsPlaylistDataForFile = async (
|
||||
): Promise<HLSPlaylistDataForFile> => {
|
||||
ensurePrecondition(file.metadata.fileType == FileType.video);
|
||||
|
||||
if (filePublicMagicMetadata(file)?.sv == 1) {
|
||||
if (file.pubMagicMetadata?.data.sv == 1) {
|
||||
return "skip";
|
||||
}
|
||||
|
||||
@@ -901,7 +900,7 @@ const backfillQueue = async (
|
||||
// Not in trash.
|
||||
!localTrashFileIDs.has(f.id) &&
|
||||
// See: [Note: Marking files which do not need video processing]
|
||||
filePublicMagicMetadata(f)?.sv != 1,
|
||||
f.pubMagicMetadata?.data.sv != 1,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import { decryptMetadataJSON, encryptMetadataJSON } from "ente-base/crypto";
|
||||
import { encryptMetadataJSON } from "ente-base/crypto";
|
||||
import { authenticatedRequestHeaders, ensureOk } from "ente-base/http";
|
||||
import { apiURL } from "ente-base/origins";
|
||||
import { type Location } from "ente-base/types";
|
||||
import {
|
||||
fileLogID,
|
||||
type EnteFile,
|
||||
type EnteFile2,
|
||||
type FileMagicMetadata,
|
||||
type FilePrivateMagicMetadata,
|
||||
type FilePublicMagicMetadata,
|
||||
} from "ente-media/file";
|
||||
import { nullToUndefined } from "ente-utils/transform";
|
||||
import { z } from "zod/v4";
|
||||
import { mergeMetadata1 } from "./file";
|
||||
import { FileType } from "./file-type";
|
||||
import type { RemoteMagicMetadata } from "./magic-metadata";
|
||||
|
||||
@@ -293,7 +290,7 @@ export type ItemVisibility =
|
||||
*
|
||||
* Also see: [Note: Zod doesn't work with `exactOptionalPropertyTypes` yet].
|
||||
*/
|
||||
export interface PublicMagicMetadata {
|
||||
export interface FilePublicMagicMetadataData {
|
||||
/**
|
||||
* A ISO 8601 date time string without a timezone, indicating the local time
|
||||
* where the photo (or video) was taken.
|
||||
@@ -358,6 +355,20 @@ export interface PublicMagicMetadata {
|
||||
* (The owner of such files will be the owner of the collection)
|
||||
*/
|
||||
uploaderName?: string;
|
||||
/**
|
||||
* Edited latitude of the file
|
||||
*
|
||||
* If the user edits the location (latitude and longitude) of a file within
|
||||
* Ente, then the edits will be stored as the {@link lat} and {@link long}
|
||||
* properties in the file's public magic metadata.
|
||||
*/
|
||||
lat?: number;
|
||||
/**
|
||||
* Edited longitude of the file.
|
||||
*
|
||||
* See {@link long}.
|
||||
*/
|
||||
long?: number;
|
||||
/**
|
||||
* An arbitrary integer set to indicate that this file should be skipped for
|
||||
* the purpose of HLS generation.
|
||||
@@ -402,7 +413,8 @@ export interface PublicMagicMetadata {
|
||||
* might be other, newer, clients out there adding fields that the current
|
||||
* client might not we aware of, and we don't want to overwrite them.
|
||||
*/
|
||||
const PublicMagicMetadata = z.looseObject({
|
||||
// TODO(RE): Use me
|
||||
export const PublicMagicMetadata = z.looseObject({
|
||||
// [Note: Zod doesn't work with `exactOptionalPropertyTypes` yet]
|
||||
//
|
||||
// Using `optional` is not accurate here. The key is optional, but the
|
||||
@@ -416,46 +428,6 @@ const PublicMagicMetadata = z.looseObject({
|
||||
editedTime: z.number().optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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) => {
|
||||
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`,
|
||||
);
|
||||
}
|
||||
return file.magicMetadata.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the public 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 public 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 filePublicMagicMetadata = (file: EnteFile) => {
|
||||
if (!file.pubMagicMetadata) return undefined;
|
||||
if (typeof file.pubMagicMetadata.data == "string") {
|
||||
throw new Error(
|
||||
`Public 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.pubMagicMetadata.data as PublicMagicMetadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the hash of the file by reading it from its metadata.
|
||||
*
|
||||
@@ -483,59 +455,11 @@ export const metadataHash = (metadata: FileMetadata) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the public magic metadata for the given {@link file}.
|
||||
*
|
||||
* The file we persist in our local db has the metadata in the encrypted form
|
||||
* that we get it from remote. We decrypt when we read it, and also hang the
|
||||
* decrypted version to the in-memory {@link EnteFile} as a cache.
|
||||
*
|
||||
* If the file doesn't have any public magic metadata attached to it, return
|
||||
* `undefined`.
|
||||
* Return `true` if the {@link ItemVisibility} of the given {@link file} is
|
||||
* archived.
|
||||
*/
|
||||
export const decryptPublicMagicMetadata = async (
|
||||
file: EnteFile,
|
||||
): Promise<PublicMagicMetadata | undefined> => {
|
||||
const envelope = file.pubMagicMetadata;
|
||||
if (!envelope) return undefined;
|
||||
|
||||
// TODO: This function can be optimized to directly return the cached value
|
||||
// instead of reparsing it using Zod. But that requires us (a) first fix the
|
||||
// types, and (b) guarantee that we're the only ones putting that parsed
|
||||
// data there, so that it is in a known good state (currently we exist in
|
||||
// parallel with other functions that do the similar things).
|
||||
|
||||
const jsonValue =
|
||||
typeof envelope.data == "string"
|
||||
? await decryptMetadataJSON(
|
||||
{
|
||||
encryptedData: envelope.data,
|
||||
decryptionHeader: envelope.header,
|
||||
},
|
||||
file.key,
|
||||
)
|
||||
: envelope.data;
|
||||
const result = PublicMagicMetadata.parse(
|
||||
// TODO: Can we avoid this cast?
|
||||
withoutNullAndUndefinedValues(jsonValue as object),
|
||||
);
|
||||
|
||||
// -@ts-expect-error [Note: Zod doesn't work with `exactOptionalPropertyTypes` yet]
|
||||
// We can't use -@ts-expect-error since this code is also included in the
|
||||
// packages which don't have strict mode enabled (and thus don't error).
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
envelope.data = result;
|
||||
|
||||
// -@ts-expect-error [Note: Zod doesn't work with `exactOptionalPropertyTypes` yet]
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return result;
|
||||
};
|
||||
|
||||
const withoutNullAndUndefinedValues = (o: object) =>
|
||||
Object.fromEntries(
|
||||
Object.entries(o).filter(([, v]) => v !== null && v !== undefined),
|
||||
);
|
||||
export const isArchivedFile = (file: EnteFile) =>
|
||||
file.magicMetadata?.data.visibility == ItemVisibility.archived;
|
||||
|
||||
/**
|
||||
* Return the file name of the file (including both the name and the extension).
|
||||
@@ -555,15 +479,13 @@ export const fileFileName = (file: EnteFile | EnteFile2) =>
|
||||
* Return the file's creation date as a Date in the hypothetical "timezone of
|
||||
* the photo".
|
||||
*
|
||||
* For all the details and nuance, see {@link createPhotoDate}.
|
||||
* This function handles files with edited dates. For all the details and
|
||||
* nuance, see {@link createPhotoDate}.
|
||||
*/
|
||||
export const fileCreationPhotoDate = (
|
||||
file: EnteFile,
|
||||
publicMagicMetadata: PublicMagicMetadata | undefined,
|
||||
) =>
|
||||
export const fileCreationPhotoDate = (file: EnteFile) =>
|
||||
createPhotoDate(
|
||||
publicMagicMetadata?.dateTime ??
|
||||
publicMagicMetadata?.editedTime ??
|
||||
file.pubMagicMetadata?.data.dateTime ??
|
||||
file.pubMagicMetadata?.data.editedTime ??
|
||||
file.metadata.creationTime,
|
||||
);
|
||||
|
||||
@@ -617,7 +539,7 @@ export const updateRemotePrivateMagicMetadata = async (
|
||||
file: EnteFile,
|
||||
metadataUpdates: Partial<FilePrivateMagicMetadataData>,
|
||||
): Promise<FilePrivateMagicMetadata> => {
|
||||
const existingMetadata = filePrivateMagicMetadata(file);
|
||||
const existingMetadata = file.magicMetadata?.data;
|
||||
|
||||
const updatedMetadata = { ...(existingMetadata ?? {}), ...metadataUpdates };
|
||||
|
||||
@@ -647,50 +569,6 @@ export const updateRemotePrivateMagicMetadata = async (
|
||||
return updatedMagicMetadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the public magic metadata associated with a file on remote.
|
||||
*
|
||||
* See: [Note: Interactive updates to file metadata]
|
||||
*
|
||||
* @param file The {@link EnteFile} whose public magic metadata we want to
|
||||
* update.
|
||||
*
|
||||
* @param metadataUpdates A subset of {@link PublicMagicMetadata} containing the
|
||||
* fields that we want to add or update.
|
||||
*/
|
||||
export const updateRemotePublicMagicMetadata = async (
|
||||
file: EnteFile,
|
||||
metadataUpdates: Partial<PublicMagicMetadata>,
|
||||
) => {
|
||||
const existingMetadata = await decryptPublicMagicMetadata(file);
|
||||
|
||||
const updatedMetadata = { ...(existingMetadata ?? {}), ...metadataUpdates };
|
||||
|
||||
const metadataVersion = file.pubMagicMetadata?.version ?? 1;
|
||||
|
||||
const updateRequest = await updateMagicMetadataRequest(
|
||||
file,
|
||||
updatedMetadata,
|
||||
metadataVersion,
|
||||
);
|
||||
|
||||
const updatedEnvelope = updateRequest.metadataList[0]!.magicMetadata;
|
||||
|
||||
await putFilesPublicMagicMetadata(updateRequest);
|
||||
|
||||
// Modify the in-memory object to use the updated envelope. This steps are
|
||||
// quite ad-hoc, as is the concept of updating the object in place.
|
||||
file.pubMagicMetadata = updatedEnvelope as FilePublicMagicMetadata;
|
||||
// The correct version will come in the updated EnteFile we get in the
|
||||
// response of the /diff. Temporarily bump it for the in place edits.
|
||||
file.pubMagicMetadata.version = file.pubMagicMetadata.version + 1;
|
||||
// Re-read the data.
|
||||
await decryptPublicMagicMetadata(file);
|
||||
// Re-jig the other bits of EnteFile that depend on its public magic
|
||||
// metadata.
|
||||
mergeMetadata1(file);
|
||||
};
|
||||
|
||||
/**
|
||||
* The shape of the JSON body payload expected by the APIs that update the
|
||||
* public and private magic metadata fields associated with a file.
|
||||
@@ -712,7 +590,7 @@ interface UpdateMagicMetadataRequest {
|
||||
*/
|
||||
const updateMagicMetadataRequest = async (
|
||||
file: EnteFile,
|
||||
metadata: FilePrivateMagicMetadataData | PublicMagicMetadata,
|
||||
metadata: FilePrivateMagicMetadataData | FilePublicMagicMetadataData,
|
||||
metadataVersion: number,
|
||||
): Promise<UpdateMagicMetadataRequest> => {
|
||||
// Drop all null or undefined values to obtain the syncable entries.
|
||||
@@ -760,36 +638,6 @@ const putFilesPrivateMagicMetadata = async (
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
* Update the public magic metadata for a list of files.
|
||||
*
|
||||
* @param request The list of file ids and the updated encrypted magic metadata
|
||||
* associated with each of them.
|
||||
*/
|
||||
const putFilesPublicMagicMetadata = async (
|
||||
request: UpdateMagicMetadataRequest,
|
||||
) =>
|
||||
ensureOk(
|
||||
await fetch(await apiURL("/files/public-magic-metadata"), {
|
||||
method: "PUT",
|
||||
headers: await authenticatedRequestHeaders(),
|
||||
body: JSON.stringify(request),
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
@@ -848,13 +696,6 @@ export const fileDurationString = (file: EnteFile): string | undefined => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
fileFileName,
|
||||
FileMetadata,
|
||||
type FilePrivateMagicMetadataData,
|
||||
type FilePublicMagicMetadataData,
|
||||
} from "./file-metadata";
|
||||
import { FileType } from "./file-type";
|
||||
import { decryptMagicMetadata, RemoteMagicMetadata } from "./magic-metadata";
|
||||
@@ -306,7 +307,7 @@ export interface EnteFile
|
||||
*
|
||||
* See: [Note: Metadatum]
|
||||
*/
|
||||
pubMagicMetadata?: FilePublicMagicMetadata;
|
||||
pubMagicMetadata?: MagicMetadataCore<FilePublicMagicMetadataData>;
|
||||
/**
|
||||
* `true` if this file is in trash (i.e. it has been deleted by the user,
|
||||
* and will be permanently deleted after 30 days of being moved to trash).
|
||||
@@ -492,56 +493,8 @@ export type FileMagicMetadata = MagicMetadataCore<FilePrivateMagicMetadataData>;
|
||||
export type FilePrivateMagicMetadata =
|
||||
MagicMetadataCore<FilePrivateMagicMetadataData>;
|
||||
|
||||
export interface FilePublicMagicMetadataProps {
|
||||
/**
|
||||
* Modified value of the date time associated with an {@link EnteFile}.
|
||||
*
|
||||
* Epoch microseconds.
|
||||
*/
|
||||
editedTime?: number;
|
||||
/** See {@link PublicMagicMetadata} in file-metadata.ts */
|
||||
dateTime?: string;
|
||||
/** See {@link PublicMagicMetadata} in file-metadata.ts */
|
||||
offsetTime?: string;
|
||||
/**
|
||||
* Edited name of the {@link EnteFile}.
|
||||
*
|
||||
* If the user edits the name of the file within Ente, then the edits are
|
||||
* saved in this field.
|
||||
*/
|
||||
editedName?: string;
|
||||
/**
|
||||
* A arbitrary textual caption / description that the user has attached to
|
||||
* the {@link EnteFile}.
|
||||
*/
|
||||
caption?: string;
|
||||
uploaderName?: string;
|
||||
/**
|
||||
* Width of the image / video, in pixels.
|
||||
*/
|
||||
w?: number;
|
||||
/**
|
||||
* Height of the image / video, in pixels.
|
||||
*/
|
||||
h?: number;
|
||||
/**
|
||||
* Edited latitude for the {@link EnteFile}.
|
||||
*
|
||||
* If the user edits the location (latitude and longitude) of a file within
|
||||
* Ente, then the edits will be stored as the {@link lat} and {@link long}
|
||||
* properties in the file's public magic metadata.
|
||||
*/
|
||||
lat?: number;
|
||||
/**
|
||||
* Edited longitude for the {@link EnteFile}.
|
||||
*
|
||||
* See {@link long}.
|
||||
*/
|
||||
long?: number;
|
||||
}
|
||||
|
||||
export type FilePublicMagicMetadata =
|
||||
MagicMetadataCore<FilePublicMagicMetadataProps>;
|
||||
MagicMetadataCore<FilePublicMagicMetadataData>;
|
||||
|
||||
export interface TrashItem extends Omit<EncryptedTrashItem, "file"> {
|
||||
file: EnteFile;
|
||||
@@ -741,7 +694,7 @@ export const decryptRemoteFile = async (
|
||||
key,
|
||||
);
|
||||
// TODO(RE):
|
||||
const data = genericMM.data as FilePublicMagicMetadataProps;
|
||||
const data = genericMM.data as FilePublicMagicMetadataData;
|
||||
// TODO(RE):
|
||||
pubMagicMetadata = { ...genericMM, header: "", data };
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@ import { ensureLocalUser } from "ente-accounts/services/user";
|
||||
import { assertionFailed } from "ente-base/assert";
|
||||
import { newID } from "ente-base/id";
|
||||
import type { EnteFile } from "ente-media/file";
|
||||
import {
|
||||
filePublicMagicMetadata,
|
||||
metadataHash,
|
||||
} from "ente-media/file-metadata";
|
||||
import { metadataHash } from "ente-media/file-metadata";
|
||||
import {
|
||||
addToCollection,
|
||||
createCollectionNameByID,
|
||||
@@ -312,7 +309,7 @@ const duplicateGroupItemToRetain = (duplicateGroup: DuplicateGroup) => {
|
||||
const itemsWithCaption: DuplicateGroup["items"] = [];
|
||||
const itemsWithOtherEdits: DuplicateGroup["items"] = [];
|
||||
for (const item of duplicateGroup.items) {
|
||||
const pubMM = filePublicMagicMetadata(item.file);
|
||||
const pubMM = item.file.pubMagicMetadata?.data;
|
||||
if (!pubMM) continue;
|
||||
if (pubMM.caption) itemsWithCaption.push(item);
|
||||
if (pubMM.editedName ?? pubMM.editedTime)
|
||||
|
||||
@@ -3,8 +3,8 @@ import { apiURL } from "ente-base/origins";
|
||||
import type { EnteFile, EnteFile2 } from "ente-media/file";
|
||||
import type {
|
||||
FilePrivateMagicMetadataData,
|
||||
FilePublicMagicMetadataData,
|
||||
ItemVisibility,
|
||||
PublicMagicMetadata,
|
||||
} from "ente-media/file-metadata";
|
||||
import {
|
||||
createMagicMetadata,
|
||||
@@ -201,7 +201,7 @@ export const updateFileCaption = (file: EnteFile2, caption: string) =>
|
||||
*/
|
||||
export const updateFilePublicMagicMetadata = async (
|
||||
file: EnteFile2,
|
||||
updates: PublicMagicMetadata,
|
||||
updates: FilePublicMagicMetadataData,
|
||||
) => updateFilesPublicMagicMetadata([file], updates);
|
||||
|
||||
/**
|
||||
@@ -214,7 +214,7 @@ export const updateFilePublicMagicMetadata = async (
|
||||
*/
|
||||
const updateFilesPublicMagicMetadata = async (
|
||||
files: EnteFile2[],
|
||||
updates: PublicMagicMetadata,
|
||||
updates: FilePublicMagicMetadataData,
|
||||
) =>
|
||||
putFilesPublicMagicMetadata({
|
||||
metadataList: await Promise.all(
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
fileCreationPhotoDate,
|
||||
fileFileName,
|
||||
fileLocation,
|
||||
filePublicMagicMetadata,
|
||||
} from "ente-media/file-metadata";
|
||||
import { nullToUndefined } from "ente-utils/transform";
|
||||
import { z } from "zod/v4";
|
||||
@@ -385,7 +384,7 @@ const isMatchingFile = (file: EnteFile, suggestion: SearchSuggestion) => {
|
||||
case "date":
|
||||
return isDateComponentsMatch(
|
||||
suggestion.dateComponents,
|
||||
fileCreationPhotoDate(file, filePublicMagicMetadata(file)),
|
||||
fileCreationPhotoDate(file),
|
||||
);
|
||||
|
||||
case "location": {
|
||||
|
||||
Reference in New Issue
Block a user