mirror of
https://github.com/immich-app/immich.git
synced 2024-11-16 02:18:50 -07:00
fix(server): override date via xmp (#5199)
* Fix * open api * Change to list and delete * Bug fix * Change name * refactor: clean up code and add test --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
parent
55fa3234fd
commit
0f657da5a4
@ -14,6 +14,7 @@ import {
|
||||
import { randomBytes } from 'crypto';
|
||||
import { Stats } from 'fs';
|
||||
import { constants } from 'fs/promises';
|
||||
import { when } from 'jest-when';
|
||||
import { JobName, QueueName } from '../job';
|
||||
import {
|
||||
IAlbumRepository,
|
||||
@ -248,6 +249,30 @@ describe(MetadataService.name, () => {
|
||||
expect(assetMock.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle a date in a sidecar file', async () => {
|
||||
const originalDate = new Date('2023-11-21T16:13:17.517Z');
|
||||
const sidecarDate = new Date('2022-01-01T00:00:00.000Z');
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.sidecar]);
|
||||
when(metadataMock.getExifTags)
|
||||
.calledWith(assetStub.sidecar.originalPath)
|
||||
// higher priority tag
|
||||
.mockResolvedValue({ CreationDate: originalDate.toISOString() });
|
||||
when(metadataMock.getExifTags)
|
||||
.calledWith(assetStub.sidecar.sidecarPath as string)
|
||||
// lower priority tag, but in sidecar
|
||||
.mockResolvedValue({ CreateDate: sidecarDate.toISOString() });
|
||||
|
||||
await sut.handleMetadataExtraction({ id: assetStub.image.id });
|
||||
expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.sidecar.id]);
|
||||
expect(assetMock.upsertExif).toHaveBeenCalledWith(expect.objectContaining({ dateTimeOriginal: sidecarDate }));
|
||||
expect(assetMock.save).toHaveBeenCalledWith({
|
||||
id: assetStub.image.id,
|
||||
duration: null,
|
||||
fileCreatedAt: sidecarDate,
|
||||
localDateTime: sidecarDate,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle lists of numbers', async () => {
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||
metadataMock.getExifTags.mockResolvedValue({ ISO: [160] as any });
|
||||
|
@ -25,6 +25,18 @@ import {
|
||||
import { StorageCore } from '../storage';
|
||||
import { FeatureFlag, SystemConfigCore } from '../system-config';
|
||||
|
||||
/** look for a date from these tags (in order) */
|
||||
const EXIF_DATE_TAGS: Array<keyof Tags> = [
|
||||
'SubSecDateTimeOriginal',
|
||||
'DateTimeOriginal',
|
||||
'SubSecCreateDate',
|
||||
'CreationDate',
|
||||
'CreateDate',
|
||||
'SubSecMediaCreateDate',
|
||||
'MediaCreateDate',
|
||||
'DateTimeCreated',
|
||||
];
|
||||
|
||||
interface DirectoryItem {
|
||||
Length?: number;
|
||||
Mime: string;
|
||||
@ -340,6 +352,15 @@ export class MetadataService {
|
||||
const stats = await this.storageRepository.stat(asset.originalPath);
|
||||
const mediaTags = await this.repository.getExifTags(asset.originalPath);
|
||||
const sidecarTags = asset.sidecarPath ? await this.repository.getExifTags(asset.sidecarPath) : null;
|
||||
|
||||
// ensure date from sidecar is used if present
|
||||
const hasDateOverride = !!this.getDateTimeOriginal(sidecarTags);
|
||||
if (mediaTags && hasDateOverride) {
|
||||
for (const tag of EXIF_DATE_TAGS) {
|
||||
delete mediaTags[tag];
|
||||
}
|
||||
}
|
||||
|
||||
const tags = { ...mediaTags, ...sidecarTags };
|
||||
|
||||
this.logger.verbose('Exif Tags', tags);
|
||||
@ -350,19 +371,7 @@ export class MetadataService {
|
||||
assetId: asset.id,
|
||||
bitsPerSample: this.getBitsPerSample(tags),
|
||||
colorspace: tags.ColorSpace ?? null,
|
||||
dateTimeOriginal:
|
||||
exifDate(
|
||||
firstDateTime(tags as Tags, [
|
||||
'SubSecDateTimeOriginal',
|
||||
'DateTimeOriginal',
|
||||
'SubSecCreateDate',
|
||||
'CreationDate',
|
||||
'CreateDate',
|
||||
'SubSecMediaCreateDate',
|
||||
'MediaCreateDate',
|
||||
'DateTimeCreated',
|
||||
]),
|
||||
) ?? asset.fileCreatedAt,
|
||||
dateTimeOriginal: this.getDateTimeOriginal(tags) ?? asset.fileCreatedAt,
|
||||
exifImageHeight: validate(tags.ImageHeight),
|
||||
exifImageWidth: validate(tags.ImageWidth),
|
||||
exposureTime: tags.ExposureTime ?? null,
|
||||
@ -387,6 +396,13 @@ export class MetadataService {
|
||||
};
|
||||
}
|
||||
|
||||
private getDateTimeOriginal(tags: ImmichTags | Tags | null) {
|
||||
if (!tags) {
|
||||
return null;
|
||||
}
|
||||
return exifDate(firstDateTime(tags as Tags, EXIF_DATE_TAGS));
|
||||
}
|
||||
|
||||
private getBitsPerSample(tags: ImmichTags): number | null {
|
||||
const bitDepthTags = [
|
||||
tags.BitsPerSample,
|
||||
|
Loading…
Reference in New Issue
Block a user