Skip to content

Commit 9d7e01b

Browse files
committed
Weee exif
1 parent 44e2640 commit 9d7e01b

5 files changed

Lines changed: 68 additions & 22 deletions

File tree

app/actions/media.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ export async function uploadMedia(formData: FormData) {
422422
filename: file.name,
423423
mimeType,
424424
fileSize: buffer.length,
425-
exifData: exifData ? JSON.stringify(exifData) : null,
425+
exifData,
426426
width,
427427
height,
428428
takenAt,

app/actions/upload.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ export async function finalizeUpload(
564564
filename: data.filename,
565565
mimeType: data.mimeType,
566566
fileSize: realFileSize,
567-
exifData: finalExifData ? JSON.stringify(finalExifData) : null,
567+
exifData: finalExifData,
568568
width: (finalExifData?.width as number | undefined) || data.width,
569569
height:
570570
(finalExifData?.height as number | undefined) || data.height,

app/api/cron/repair-exif/route.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,6 @@ function getExifObject(item: MediaRow) {
4545
: null;
4646
}
4747

48-
function alreadyHasReliableExif(item: MediaRow) {
49-
const exif = getExifObject(item);
50-
if (hasValue(item.latitude) && hasValue(item.longitude)) return true;
51-
if (!exif) return false;
52-
return Boolean(
53-
hasValue(exif.gpsLatitude) ||
54-
hasValue(exif.gpsLongitude) ||
55-
hasValue(exif.make) ||
56-
hasValue(exif.model) ||
57-
hasValue(exif.lensModel) ||
58-
hasValue(exif.focalLength) ||
59-
hasValue(exif.fNumber) ||
60-
hasValue(exif.iso) ||
61-
hasValue(exif.exposureTime),
62-
);
63-
}
64-
6548
function mergeExifData(
6649
primary: Record<string, unknown> | null | undefined,
6750
fallback: Record<string, unknown> | null | undefined,
@@ -106,9 +89,6 @@ async function repairExifForMedia(item: MediaRow) {
10689
if (!item.mimeType.startsWith("image/")) {
10790
return { scanned: 0, skipped: 1, repaired: 0, failed: 0 };
10891
}
109-
if (alreadyHasReliableExif(item)) {
110-
return { scanned: 1, skipped: 1, repaired: 0, failed: 0 };
111-
}
11292
try {
11393
const sourceKeys = [
11494
item.s3Key,

lib/media/browser-utils.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,37 @@ async function drawThumbnail(
362362
canvas.toBlob(resolve, "image/jpeg", 0.76);
363363
});
364364
}
365+
366+
function toJsonSafeExifValue(value: unknown): unknown {
367+
if (value instanceof Date) {
368+
return Number.isNaN(value.getTime()) ? undefined : value.toISOString();
369+
}
370+
if (typeof value === "bigint") return value.toString();
371+
if (Array.isArray(value)) {
372+
return value
373+
.map((item) => toJsonSafeExifValue(item))
374+
.filter((item) => item !== undefined);
375+
}
376+
if (value && typeof value === "object") {
377+
const safeObject: Record<string, unknown> = {};
378+
for (const [key, nestedValue] of Object.entries(value)) {
379+
const safeValue = toJsonSafeExifValue(nestedValue);
380+
if (safeValue !== undefined) safeObject[key] = safeValue;
381+
}
382+
return Object.keys(safeObject).length > 0 ? safeObject : undefined;
383+
}
384+
return value;
385+
}
386+
387+
function toJsonSafeExif(exif: Record<string, unknown>) {
388+
const safeExif: Record<string, unknown> = {};
389+
for (const [key, value] of Object.entries(exif)) {
390+
const safeValue = toJsonSafeExifValue(value);
391+
if (safeValue !== undefined) safeExif[key] = safeValue;
392+
}
393+
return safeExif;
394+
}
395+
365396
export async function extractMetadata(file: File): Promise<{
366397
exifData: ExifData | null;
367398
width: number | null;
@@ -387,6 +418,7 @@ export async function extractMetadata(file: File): Promise<{
387418
? exif.ModifyDate
388419
: null;
389420
const exifData: ExifData = {
421+
...toJsonSafeExif(exif as Record<string, unknown>),
390422
make: exif.Make,
391423
model: exif.Model,
392424
lensModel: exif.LensModel,

lib/media/exif.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import exifr from "exifr";
22
import { logger } from "@/lib/logger";
33
export interface ExifData {
4+
[key: string]: unknown;
45
make?: string;
56
model?: string;
67
lensModel?: string;
@@ -29,6 +30,38 @@ function toIsoDate(value: unknown) {
2930
return undefined;
3031
}
3132

33+
function toJsonSafeExifValue(value: unknown): unknown {
34+
if (value instanceof Date) {
35+
return Number.isNaN(value.getTime()) ? undefined : value.toISOString();
36+
}
37+
if (typeof value === "bigint") {
38+
return value.toString();
39+
}
40+
if (Array.isArray(value)) {
41+
return value
42+
.map((item) => toJsonSafeExifValue(item))
43+
.filter((item) => item !== undefined);
44+
}
45+
if (value && typeof value === "object") {
46+
const safeObject: Record<string, unknown> = {};
47+
for (const [key, nestedValue] of Object.entries(value)) {
48+
const safeValue = toJsonSafeExifValue(nestedValue);
49+
if (safeValue !== undefined) safeObject[key] = safeValue;
50+
}
51+
return Object.keys(safeObject).length > 0 ? safeObject : undefined;
52+
}
53+
return value;
54+
}
55+
56+
function toJsonSafeExif(exif: Record<string, unknown>) {
57+
const safeExif: Record<string, unknown> = {};
58+
for (const [key, value] of Object.entries(exif)) {
59+
const safeValue = toJsonSafeExifValue(value);
60+
if (safeValue !== undefined) safeExif[key] = safeValue;
61+
}
62+
return safeExif;
63+
}
64+
3265
export async function extractExifData(
3366
buffer: Buffer,
3467
contextInfo?: string,
@@ -96,6 +129,7 @@ export async function extractExifData(
96129
gpsLongitude = lonValue;
97130
}
98131
return {
132+
...toJsonSafeExif(exif as Record<string, unknown>),
99133
make: exif.Make,
100134
model: exif.Model,
101135
lensModel: exif.LensModel,

0 commit comments

Comments
 (0)