Compare commits

...

3 Commits

Author SHA1 Message Date
Carsten Otto
615eb671f8
Merge 7abe36f82007dc0128bc758c3f5a5c401c0e6205 into b0bcc6c03ecedff0d756a0e54352586672cea761 2024-10-02 06:30:20 +07:00
renovate[bot]
b0bcc6c03e
chore(deps): update typescript-projects (#13099)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-01 19:29:48 -04:00
Carsten Otto
7abe36f820 fix(server): prefer explicit timezone over GPS based guess
exiftool-vendored sadly treats the offset +00:00 (used in several countries) as unknown
and may return a timezone which is based on GPS coordinates. Because of this, when
one manually fixes the timezone offset to +00:00, this fix is overwritten. With this fix,
we explicitly prefer +00:00 (if set).
2024-09-15 23:08:00 +02:00
5 changed files with 39 additions and 19 deletions

7
cli/package-lock.json generated
View File

@ -3148,10 +3148,11 @@
} }
}, },
"node_modules/mock-fs": { "node_modules/mock-fs": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.2.0.tgz", "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.3.0.tgz",
"integrity": "sha512-2dF2R6YMSZbpip1V1WHKGLNjr/k48uQClqMVb5H3MOvwc9qhYis3/IWbj02qIg/Y8MDXKFF4c5v0rxx2o6xTZw==", "integrity": "sha512-IMvz1X+RF7vf+ur7qUenXMR7/FSKSIqS3HqFHXcyNI7G0FbpFO8L5lfsUJhl+bhK1AiulVHWKUSxebWauPA+xQ==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=12.0.0" "node": ">=12.0.0"
} }

View File

@ -10478,9 +10478,9 @@
"dev": true "dev": true
}, },
"node_modules/mock-fs": { "node_modules/mock-fs": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.2.0.tgz", "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.3.0.tgz",
"integrity": "sha512-2dF2R6YMSZbpip1V1WHKGLNjr/k48uQClqMVb5H3MOvwc9qhYis3/IWbj02qIg/Y8MDXKFF4c5v0rxx2o6xTZw==", "integrity": "sha512-IMvz1X+RF7vf+ur7qUenXMR7/FSKSIqS3HqFHXcyNI7G0FbpFO8L5lfsUJhl+bhK1AiulVHWKUSxebWauPA+xQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=12.0.0" "node": ">=12.0.0"
@ -22506,9 +22506,9 @@
"dev": true "dev": true
}, },
"mock-fs": { "mock-fs": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.2.0.tgz", "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.3.0.tgz",
"integrity": "sha512-2dF2R6YMSZbpip1V1WHKGLNjr/k48uQClqMVb5H3MOvwc9qhYis3/IWbj02qIg/Y8MDXKFF4c5v0rxx2o6xTZw==", "integrity": "sha512-IMvz1X+RF7vf+ur7qUenXMR7/FSKSIqS3HqFHXcyNI7G0FbpFO8L5lfsUJhl+bhK1AiulVHWKUSxebWauPA+xQ==",
"dev": true "dev": true
}, },
"module-details-from-path": { "module-details-from-path": {

View File

@ -1,4 +1,5 @@
import { BinaryField, ExifDateTime } from 'exiftool-vendored'; import { BinaryField, ExifDateTime } from 'exiftool-vendored';
import { DateTime } from 'luxon';
import { randomBytes } from 'node:crypto'; import { randomBytes } from 'node:crypto';
import { Stats } from 'node:fs'; import { Stats } from 'node:fs';
import { constants } from 'node:fs/promises'; import { constants } from 'node:fs/promises';
@ -871,10 +872,30 @@ describe(MetadataService.name, () => {
metadataMock.readTags.mockResolvedValue(tags); metadataMock.readTags.mockResolvedValue(tags);
await sut.handleMetadataExtraction({ id: assetStub.image.id }); await sut.handleMetadataExtraction({ id: assetStub.image.id });
expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.image.id]);
expect(assetMock.upsertExif).toHaveBeenCalledWith( expect(assetMock.upsertExif).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
timeZone: 'UTC+0', timeZone: 'UTC+0',
dateTimeOriginal: DateTime.fromISO('2024-09-01T00:00:00.000Z').toJSDate(),
}),
);
});
it('should extract +00:00 timezone from raw value despite conflicting GPS location/timezone', async () => {
// exiftool-vendored returns a timezone derived from GPS coordinates even though "+00:00" might be set explicitly
// https://github.com/photostructure/exiftool-vendored.js/issues/203
const tags: ImmichTags = {
DateTimeOriginal: ExifDateTime.fromISO('2024-09-15T00:00:00.000+00:00'),
tz: 'America/Santiago',
};
assetMock.getByIds.mockResolvedValue([assetStub.image]);
metadataMock.readTags.mockResolvedValue(tags);
await sut.handleMetadataExtraction({ id: assetStub.image.id });
expect(assetMock.upsertExif).toHaveBeenCalledWith(
expect.objectContaining({
timeZone: 'UTC+0',
dateTimeOriginal: DateTime.fromISO('2024-09-15T00:00:00.000Z').toJSDate(),
}), }),
); );
}); });

View File

@ -623,12 +623,10 @@ export class MetadataService extends BaseService {
} }
// timezone // timezone
let timeZone = exifTags.tz ?? null; // exiftool-vendored returns "no timezone" information or one derived from GPS coordinates even though "+00:00"
if (timeZone == null && dateTime?.rawValue?.endsWith('+00:00')) { // might be set explicitly
// exiftool-vendored returns "no timezone" information even though "+00:00" might be set explicitly
// https://github.com/photostructure/exiftool-vendored.js/issues/203 // https://github.com/photostructure/exiftool-vendored.js/issues/203
timeZone = 'UTC+0'; const timeZone = dateTime?.rawValue?.endsWith('+00:00') ? 'UTC+0' : (exifTags.tz ?? null);
}
if (timeZone) { if (timeZone) {
this.logger.debug(`Asset ${asset.id} timezone is ${timeZone} (via ${exifTags.tzSource})`); this.logger.debug(`Asset ${asset.id} timezone is ${timeZone} (via ${exifTags.tzSource})`);

6
web/package-lock.json generated
View File

@ -769,9 +769,9 @@
} }
}, },
"node_modules/@faker-js/faker": { "node_modules/@faker-js/faker": {
"version": "9.0.2", "version": "9.0.3",
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.0.2.tgz", "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.0.3.tgz",
"integrity": "sha512-nI/FP30ZGXb+UaR7yXawVTH40NVKXPIx0tA3GKjkKLjorqBoMAeq4iSEacl8mJmpVhOCDa0vYHwYDmOOcFMrYw==", "integrity": "sha512-lWrrK4QNlFSU+13PL9jMbMKLJYXDFu3tQfayBsMXX7KL/GiQeqfB1CzHkqD5UHBUtPAuPo6XwGbMFNdVMZObRA==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {