diff --git a/web/apps/photos/src/services/ffmpeg.ts b/web/apps/photos/src/services/ffmpeg.ts index 5731d37bf..a05a22a50 100644 --- a/web/apps/photos/src/services/ffmpeg.ts +++ b/web/apps/photos/src/services/ffmpeg.ts @@ -6,7 +6,10 @@ import { } from "constants/ffmpeg"; import { ElectronFile } from "types/upload"; import ComlinkFFmpegWorker from "utils/comlink/ComlinkFFmpegWorker"; -import { parseFFmpegExtractedMetadata } from "utils/ffmpeg"; + +import { validateAndGetCreationUnixTimeInMicroSeconds } from "@ente/shared/time"; +import { NULL_LOCATION } from "constants/upload"; +import { ParsedExtractedMetadata } from "types/upload"; /** Called during upload */ export async function generateVideoThumbnail( @@ -77,6 +80,70 @@ export async function extractVideoMetadata(file: File | ElectronFile) { } } +enum MetadataTags { + CREATION_TIME = "creation_time", + APPLE_CONTENT_IDENTIFIER = "com.apple.quicktime.content.identifier", + APPLE_LIVE_PHOTO_IDENTIFIER = "com.apple.quicktime.live-photo.auto", + APPLE_CREATION_DATE = "com.apple.quicktime.creationdate", + APPLE_LOCATION_ISO = "com.apple.quicktime.location.ISO6709", + LOCATION = "location", +} + +function parseFFmpegExtractedMetadata(encodedMetadata: Uint8Array) { + const metadataString = new TextDecoder().decode(encodedMetadata); + const metadataPropertyArray = metadataString.split("\n"); + const metadataKeyValueArray = metadataPropertyArray.map((property) => + property.split("="), + ); + const validKeyValuePairs = metadataKeyValueArray.filter( + (keyValueArray) => keyValueArray.length === 2, + ) as Array<[string, string]>; + + const metadataMap = Object.fromEntries(validKeyValuePairs); + + const location = parseAppleISOLocation( + metadataMap[MetadataTags.APPLE_LOCATION_ISO] ?? + metadataMap[MetadataTags.LOCATION], + ); + + const creationTime = parseCreationTime( + metadataMap[MetadataTags.APPLE_CREATION_DATE] ?? + metadataMap[MetadataTags.CREATION_TIME], + ); + const parsedMetadata: ParsedExtractedMetadata = { + creationTime, + location: { + latitude: location.latitude, + longitude: location.longitude, + }, + width: null, + height: null, + }; + return parsedMetadata; +} + +function parseAppleISOLocation(isoLocation: string) { + let location = NULL_LOCATION; + if (isoLocation) { + const [latitude, longitude] = isoLocation + .match(/(\+|-)\d+\.*\d+/g) + .map((x) => parseFloat(x)); + + location = { latitude, longitude }; + } + return location; +} + +function parseCreationTime(creationTime: string) { + let dateTime = null; + if (creationTime) { + dateTime = validateAndGetCreationUnixTimeInMicroSeconds( + new Date(creationTime), + ); + } + return dateTime; +} + /** Called when viewing a file */ export async function convertToMP4(file: File) { try { diff --git a/web/apps/photos/src/utils/ffmpeg/index.ts b/web/apps/photos/src/utils/ffmpeg/index.ts deleted file mode 100644 index 8a4332a7f..000000000 --- a/web/apps/photos/src/utils/ffmpeg/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { validateAndGetCreationUnixTimeInMicroSeconds } from "@ente/shared/time"; -import { NULL_LOCATION } from "constants/upload"; -import { ParsedExtractedMetadata } from "types/upload"; - -enum MetadataTags { - CREATION_TIME = "creation_time", - APPLE_CONTENT_IDENTIFIER = "com.apple.quicktime.content.identifier", - APPLE_LIVE_PHOTO_IDENTIFIER = "com.apple.quicktime.live-photo.auto", - APPLE_CREATION_DATE = "com.apple.quicktime.creationdate", - APPLE_LOCATION_ISO = "com.apple.quicktime.location.ISO6709", - LOCATION = "location", -} - -export function parseFFmpegExtractedMetadata(encodedMetadata: Uint8Array) { - const metadataString = new TextDecoder().decode(encodedMetadata); - const metadataPropertyArray = metadataString.split("\n"); - const metadataKeyValueArray = metadataPropertyArray.map((property) => - property.split("="), - ); - const validKeyValuePairs = metadataKeyValueArray.filter( - (keyValueArray) => keyValueArray.length === 2, - ) as Array<[string, string]>; - - const metadataMap = Object.fromEntries(validKeyValuePairs); - - const location = parseAppleISOLocation( - metadataMap[MetadataTags.APPLE_LOCATION_ISO] ?? - metadataMap[MetadataTags.LOCATION], - ); - - const creationTime = parseCreationTime( - metadataMap[MetadataTags.APPLE_CREATION_DATE] ?? - metadataMap[MetadataTags.CREATION_TIME], - ); - const parsedMetadata: ParsedExtractedMetadata = { - creationTime, - location: { - latitude: location.latitude, - longitude: location.longitude, - }, - width: null, - height: null, - }; - return parsedMetadata; -} - -function parseAppleISOLocation(isoLocation: string) { - let location = NULL_LOCATION; - if (isoLocation) { - const [latitude, longitude] = isoLocation - .match(/(\+|-)\d+\.*\d+/g) - .map((x) => parseFloat(x)); - - location = { latitude, longitude }; - } - return location; -} - -function parseCreationTime(creationTime: string) { - let dateTime = null; - if (creationTime) { - dateTime = validateAndGetCreationUnixTimeInMicroSeconds( - new Date(creationTime), - ); - } - return dateTime; -}