diff --git a/web/apps/photos/src/components/PhotoFrame.tsx b/web/apps/photos/src/components/PhotoFrame.tsx
index 3603e43535..e814b19623 100644
--- a/web/apps/photos/src/components/PhotoFrame.tsx
+++ b/web/apps/photos/src/components/PhotoFrame.tsx
@@ -2,6 +2,7 @@ import log from "@/base/log";
import {
downloadManager,
type LivePhotoSourceURL,
+ type LoadedLivePhotoSourceURL,
type RenderableSourceURLs,
} from "@/gallery/services/download";
import { EnteFile } from "@/media/file";
@@ -45,6 +46,16 @@ const PHOTOSWIPE_HASH_SUFFIX = "&opened";
export type DisplayFile = EnteFile & {
src?: string;
srcURLs?: RenderableSourceURLs;
+ /**
+ * An object URL corresponding to the image portion, if any, associated with
+ * the {@link DisplayFile}.
+ *
+ * - For images, this will be the object URL of the renderable image itself.
+ * - For live photos, this will be the object URL of the image portion of
+ * the live photo.
+ * - For videos, this will not be defined.
+ */
+ associatedImageURL?: string | undefined;
msrc?: string;
html?: string;
w?: number;
@@ -550,7 +561,16 @@ const updateDisplayFileSource = (
: true;
file.canForceConvert = srcURLs.canForceConvert;
file.conversionFailed = !isRenderable;
- file.srcURLs = srcURLs;
+ file.associatedImageURL = (() => {
+ switch (file.metadata.fileType) {
+ case FileType.image:
+ return srcURLs.url as string;
+ case FileType.livePhoto:
+ return (srcURLs.url as LoadedLivePhotoSourceURL).image;
+ default:
+ return undefined;
+ }
+ })();
if (!isRenderable) {
file.isSourceLoaded = true;
return;
@@ -574,7 +594,7 @@ const updateDisplayFileSource = (
`;
} else {
const { image: imageURL, video: videoURL } =
- url as LivePhotoSourceURL;
+ url as LoadedLivePhotoSourceURL;
file.html = `
diff --git a/web/apps/photos/src/components/PhotoViewer/index.tsx b/web/apps/photos/src/components/PhotoViewer/index.tsx
index 6dfdfd825a..5fe68294ef 100644
--- a/web/apps/photos/src/components/PhotoViewer/index.tsx
+++ b/web/apps/photos/src/components/PhotoViewer/index.tsx
@@ -6,10 +6,7 @@ import { Overlay } from "@/base/components/mui/Container";
import { type ModalVisibilityProps } from "@/base/components/utils/modal";
import { lowercaseExtension } from "@/base/file-name";
import log from "@/base/log";
-import {
- downloadManager,
- type LoadedLivePhotoSourceURL,
-} from "@/gallery/services/download";
+import { downloadManager } from "@/gallery/services/download";
import { fileLogID, type EnteFile } from "@/media/file";
import { FileType } from "@/media/file-type";
import { isHEICExtension, needsJPEGConversion } from "@/media/formats";
@@ -365,11 +362,7 @@ function PhotoViewer(props: PhotoViewerProps) {
return;
}
- const key =
- file.metadata.fileType === FileType.image
- ? file.src
- : (file.srcURLs.url as LoadedLivePhotoSourceURL).image;
-
+ const key = file.associatedImageURL;
if (exifCopy?.current?.key === key) return;
setExif({ key, value: undefined });
@@ -638,12 +631,16 @@ function PhotoViewer(props: PhotoViewerProps) {
const checkExifAvailable = async (enteFile: DisplayFile) => {
if (exifExtractionInProgress.current === enteFile.src) return;
+ const associatedImageURL = enteFile.associatedImageURL;
+ if (!associatedImageURL) {
+ assertionFailed();
+ return;
+ }
+
try {
exifExtractionInProgress.current = enteFile.src;
const file = await getFileFromURL(
- enteFile.metadata.fileType === FileType.image
- ? (enteFile.src as string)
- : (enteFile.srcURLs.url as LoadedLivePhotoSourceURL).image,
+ associatedImageURL,
enteFile.metadata.title,
);
const tags = await extractRawExif(file);