This commit is contained in:
Manav Rathi 2024-09-06 12:44:25 +05:30
parent 9e48010ee6
commit cfea740511
No known key found for this signature in database
7 changed files with 90 additions and 81 deletions

View File

@ -1,4 +1,5 @@
import { haveWindow } from "@/base/env";
import { type Location } from "@/base/location";
import { styled } from "@mui/material";
import { useEffect, useRef } from "react";
import { MapButton } from "./MapButton";
@ -29,7 +30,7 @@ const MapBoxEnableContainer = styled(MapBoxContainer)`
`;
interface MapBoxProps {
location: { latitude: number; longitude: number };
location: Location;
mapEnabled: boolean;
openUpdateMapConfirmationDialog: () => void;
}

View File

@ -2,9 +2,11 @@ import { EnteDrawer } from "@/base/components/EnteDrawer";
import { Titlebar } from "@/base/components/Titlebar";
import { EllipsizedTypography } from "@/base/components/Typography";
import { nameAndExtension } from "@/base/file";
import type { Location } from "@/base/location";
import log from "@/base/log";
import type { ParsedMetadata } from "@/media/file-metadata";
import {
fileLocation,
getUICreationDate,
updateRemotePublicMagicMetadata,
type ParsedMetadataDate,
@ -97,16 +99,9 @@ export const FileInfo: React.FC<FileInfoProps> = ({
const [openRawExif, setOpenRawExif] = useState(false);
const location = useMemo(() => {
if (file && file.metadata) {
if (
(file.metadata.latitude || file.metadata.latitude === 0) &&
!(file.metadata.longitude === 0 && file.metadata.latitude === 0)
) {
return {
latitude: file.metadata.latitude,
longitude: file.metadata.longitude,
};
}
if (file) {
const location = fileLocation(file);
if (location) return location;
}
return exif?.parsed?.location;
}, [file, exif]);
@ -181,7 +176,7 @@ export const FileInfo: React.FC<FileInfoProps> = ({
!mapEnabled ||
publicCollectionGalleryContext.accessedThroughSharedURL ? (
<Link
href={getOpenStreetMapLink(location)}
href={openStreetMapLink(location)}
target="_blank"
rel="noopener"
sx={{ fontWeight: "bold" }}
@ -205,7 +200,7 @@ export const FileInfo: React.FC<FileInfoProps> = ({
}
customEndButton={
<CopyButton
code={getOpenStreetMapLink(location)}
code={openStreetMapLink(location)}
color="secondary"
size="medium"
/>
@ -531,11 +526,8 @@ const BasicDeviceCamera: React.FC<{ parsedExif: ExifInfo }> = ({
);
};
const getOpenStreetMapLink = (location: {
latitude: number;
longitude: number;
}) =>
`https://www.openstreetmap.org/?mlat=${location.latitude}&mlon=${location.longitude}#map=15/${location.latitude}/${location.longitude}`;
const openStreetMapLink = ({ latitude, longitude }: Location) =>
`https://www.openstreetmap.org/?mlat=${latitude}&mlon=${longitude}#map=15/${latitude}/${longitude}`;
interface RawExifProps {
open: boolean;

View File

@ -1,6 +1,6 @@
import { ensureElectron } from "@/base/electron";
import log from "@/base/log";
import type { Metadata } from "@/media/file-metadata";
import { fileLocation, type Metadata } from "@/media/file-metadata";
import { FileType } from "@/media/file-type";
import { decodeLivePhoto } from "@/media/live-photo";
import downloadManager from "@/new/photos/services/download";
@ -1383,6 +1383,7 @@ const getGoogleLikeMetadataFile = (fileExportName: string, file: EnteFile) => {
(metadata.modificationTime ?? metadata.creationTime) / 1000000,
);
const captionValue: string = file?.pubMagicMetadata?.data?.caption;
const geoData = fileLocation(file);
return JSON.stringify(
{
title: fileExportName,
@ -1395,10 +1396,7 @@ const getGoogleLikeMetadataFile = (fileExportName: string, file: EnteFile) => {
timestamp: modificationTime,
formatted: formatDateTimeShort(modificationTime * 1000),
},
geoData: {
latitude: metadata.latitude,
longitude: metadata.longitude,
},
geoData,
},
null,
2,

View File

@ -2,6 +2,7 @@
import { ensureElectron } from "@/base/electron";
import { nameAndExtension } from "@/base/file";
import { type Location } from "@/base/location";
import log from "@/base/log";
import type { UploadItem } from "@/new/photos/services/upload/types";
import { readStream } from "@/new/photos/utils/native-stream";
@ -16,7 +17,7 @@ import { readStream } from "@/new/photos/utils/native-stream";
export interface ParsedMetadataJSON {
creationTime?: number;
modificationTime?: number;
location?: { latitude: number; longitude: number };
location?: Location;
}
export const MAX_FILE_NAME_LENGTH_GOOGLE_EXPORT = 46;
@ -112,53 +113,60 @@ const parseMetadataJSONText = (text: string) => {
const parsedMetadataJSON: ParsedMetadataJSON = {};
// The metadata provided by Google does not include the time zone where the
// photo was taken, it only has an epoch seconds value.
if (
metadataJSON["photoTakenTime"] &&
metadataJSON["photoTakenTime"]["timestamp"]
) {
parsedMetadataJSON.creationTime =
metadataJSON["photoTakenTime"]["timestamp"] * 1e6;
} else if (
metadataJSON["creationTime"] &&
metadataJSON["creationTime"]["timestamp"]
) {
parsedMetadataJSON.creationTime =
metadataJSON["creationTime"]["timestamp"] * 1e6;
}
parsedMetadataJSON.creationTime =
parseGTTimestamp(metadataJSON["photoTakenTime"]) ??
parseGTTimestamp(metadataJSON["creationTime"]);
if (
metadataJSON["modificationTime"] &&
metadataJSON["modificationTime"]["timestamp"]
) {
parsedMetadataJSON.modificationTime =
metadataJSON["modificationTime"]["timestamp"] * 1e6;
}
parsedMetadataJSON.modificationTime = parseGTTimestamp(
metadataJSON["modificationTime"],
);
if (
metadataJSON["geoData"] &&
(metadataJSON["geoData"]["latitude"] !== 0.0 ||
metadataJSON["geoData"]["longitude"] !== 0.0)
) {
parsedMetadataJSON.location = {
latitude: metadataJSON["geoData"]["latitude"],
longitude: metadataJSON["geoData"]["longitude"],
};
} else if (
metadataJSON["geoDataExif"] &&
(metadataJSON["geoDataExif"]["latitude"] !== 0.0 ||
metadataJSON["geoDataExif"]["longitude"] !== 0.0)
) {
parsedMetadataJSON.location = {
latitude: metadataJSON["geoDataExif"]["latitude"],
longitude: metadataJSON["geoDataExif"]["longitude"],
};
}
parsedMetadataJSON.location =
parseGTLocation(metadataJSON["geoData"]) ??
parseGTLocation(metadataJSON["geoDataExif"]);
return parsedMetadataJSON;
};
/**
* Parse a nullish epoch seconds timestamp from a field in a Google Takeout
* JSON, converting it into epoch microseconds if it is found.
*
* Note that the metadata provided by Google does not include the time zone
* where the photo was taken, it only has an epoch seconds value.
*/
const parseGTTimestamp = (o: unknown) => {
if (
o &&
typeof o == "object" &&
"timestamp" in o &&
typeof o.timestamp == "number"
) {
const { timestamp } = o;
if (timestamp) return timestamp * 1e6;
}
return undefined;
};
/**
* A custom parser (instead of parseLatLng) that retains the existing behaviour
* of ignoring (0, 0) lat lng pairs when reading Google Takeout JSONs.
*/
const parseGTLocation = (o: unknown) => {
if (
o &&
typeof o == "object" &&
"latitude" in o &&
typeof o.latitude == "number" &&
"longitude" in o &&
typeof o.longitude == "number"
) {
const { latitude, longitude } = o;
if (latitude !== 0 || longitude !== 0) return { latitude, longitude };
}
return undefined;
};
/**
* Return the matching entry (if any) from {@link parsedMetadataJSONMap} for the
* {@link fileName} and {@link collectionID} combination.

View File

@ -0,0 +1,25 @@
import { nullToUndefined } from "@/utils/transform";
/**
* A location, represented as a (latitude, longitude) pair.
*/
export interface Location {
latitude: number;
longitude: number;
}
/**
* Convert a pair of nullish latitude and longitude values into a
* {@link Location} if both of them are present.
*/
export const parseLatLng = (
latitudeN: number | undefined | null,
longitudeN: number | undefined | null,
): Location | undefined => {
const latitude = nullToUndefined(latitudeN);
const longitude = nullToUndefined(longitudeN);
if (latitude === undefined || longitude === undefined) return undefined;
return { latitude, longitude };
};

View File

@ -1,7 +0,0 @@
/**
* A location, represented as a (latitude, longitude) pair.
*/
export interface Location {
latitude: number;
longitude: number;
}

View File

@ -1,14 +1,13 @@
import { decryptMetadataJSON, encryptMetadataJSON } from "@/base/crypto";
import { authenticatedRequestHeaders, ensureOk } from "@/base/http";
import type { Location } from "@/base/location";
import { apiURL } from "@/base/origins";
import type { Location } from "@/base/types";
import {
type EnteFile,
type FilePublicMagicMetadata,
} from "@/new/photos/types/file";
import { mergeMetadata1 } from "@/new/photos/utils/file";
import { ensure } from "@/utils/ensure";
import { nullToUndefined } from "@/utils/transform";
import { z } from "zod";
import { FileType } from "./file-type";
@ -773,11 +772,4 @@ export const fileLocation = (enteFile: EnteFile): Location | undefined => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!enteFile.metadata) return undefined;
const latitude = nullToUndefined(enteFile.metadata.latitude);
const longitude = nullToUndefined(enteFile.metadata.longitude);
if (latitude === undefined || longitude === undefined) return undefined;
return { latitude, longitude };
};