mirror of
https://github.com/immich-app/immich.git
synced 2026-02-28 09:38:43 +03:00
@@ -919,7 +919,7 @@ describe(MetadataService.name, () => {
|
|||||||
Orientation: 0,
|
Orientation: 0,
|
||||||
ProfileDescription: 'extensive description',
|
ProfileDescription: 'extensive description',
|
||||||
ProjectionType: 'equirectangular',
|
ProjectionType: 'equirectangular',
|
||||||
tz: 'UTC-11:30',
|
zone: 'UTC-11:30',
|
||||||
TagsList: ['parent/child'],
|
TagsList: ['parent/child'],
|
||||||
Rating: 3,
|
Rating: 3,
|
||||||
};
|
};
|
||||||
@@ -955,7 +955,7 @@ describe(MetadataService.name, () => {
|
|||||||
orientation: tags.Orientation?.toString(),
|
orientation: tags.Orientation?.toString(),
|
||||||
profileDescription: tags.ProfileDescription,
|
profileDescription: tags.ProfileDescription,
|
||||||
projectionType: 'EQUIRECTANGULAR',
|
projectionType: 'EQUIRECTANGULAR',
|
||||||
timeZone: tags.tz,
|
timeZone: tags.zone,
|
||||||
rating: tags.Rating,
|
rating: tags.Rating,
|
||||||
country: null,
|
country: null,
|
||||||
state: null,
|
state: null,
|
||||||
@@ -987,7 +987,7 @@ describe(MetadataService.name, () => {
|
|||||||
|
|
||||||
const tags: ImmichTags = {
|
const tags: ImmichTags = {
|
||||||
DateTimeOriginal: ExifDateTime.fromISO(someDate + '+00:00'),
|
DateTimeOriginal: ExifDateTime.fromISO(someDate + '+00:00'),
|
||||||
tz: undefined,
|
zone: undefined,
|
||||||
};
|
};
|
||||||
mocks.assetJob.getForMetadataExtraction.mockResolvedValue(asset);
|
mocks.assetJob.getForMetadataExtraction.mockResolvedValue(asset);
|
||||||
mockReadTags(tags);
|
mockReadTags(tags);
|
||||||
|
|||||||
@@ -527,6 +527,15 @@ export class MetadataService extends BaseService {
|
|||||||
for (const tag of EXIF_DATE_TAGS) {
|
for (const tag of EXIF_DATE_TAGS) {
|
||||||
delete mediaTags[tag];
|
delete mediaTags[tag];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exiftool-vendored derives tz information from the date.
|
||||||
|
// if the sidecar file has date information, we also assume the tz information come from there.
|
||||||
|
//
|
||||||
|
// this is especially important in the case of UTC+0 where exiftool-vendored does not return tz/zone fields
|
||||||
|
// and as such the tags aren't overwritten when returning all tags.
|
||||||
|
for (const tag of ['zone', 'tz', 'tzSource'] as const) {
|
||||||
|
delete mediaTags[tag];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,8 +906,8 @@ export class MetadataService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// timezone
|
// timezone
|
||||||
let timeZone = exifTags.tz ?? null;
|
let timeZone = exifTags.zone ?? null;
|
||||||
if (timeZone == null && dateTime?.rawValue?.endsWith('+00:00')) {
|
if (timeZone == null && (dateTime?.rawValue?.endsWith('Z') || dateTime?.rawValue?.endsWith('+00:00'))) {
|
||||||
// exiftool-vendored returns "no timezone" information even though "+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';
|
timeZone = 'UTC+0';
|
||||||
@@ -906,7 +915,7 @@ export class MetadataService extends BaseService {
|
|||||||
|
|
||||||
if (timeZone) {
|
if (timeZone) {
|
||||||
this.logger.verbose(
|
this.logger.verbose(
|
||||||
`Found timezone ${timeZone} via ${exifTags.tzSource} for asset ${asset.id}: ${asset.originalPath}`,
|
`Found timezone ${timeZone} via ${exifTags.zoneSource} for asset ${asset.id}: ${asset.originalPath}`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.logger.debug(`No timezone information found for asset ${asset.id}: ${asset.originalPath}`);
|
this.logger.debug(`No timezone information found for asset ${asset.id}: ${asset.originalPath}`);
|
||||||
|
|||||||
@@ -398,6 +398,23 @@ describe(AssetService.name, () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should update dateTimeOriginal with time zone UTC+0', async () => {
|
||||||
|
const { sut, ctx } = setup();
|
||||||
|
ctx.getMock(JobRepository).queue.mockResolvedValue();
|
||||||
|
const { user } = await ctx.newUser();
|
||||||
|
const auth = factory.auth({ user });
|
||||||
|
const { asset } = await ctx.newAsset({ ownerId: user.id });
|
||||||
|
await ctx.newExif({ assetId: asset.id, description: 'test', timeZone: 'UTC-7' });
|
||||||
|
|
||||||
|
await sut.update(auth, asset.id, { dateTimeOriginal: '2023-11-19T18:11:00.000Z' });
|
||||||
|
|
||||||
|
await expect(ctx.get(AssetRepository).getById(asset.id, { exifInfo: true })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
exifInfo: expect.objectContaining({ dateTimeOriginal: '2023-11-19T18:11:00+00:00', timeZone: 'UTC' }),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('updateAll', () => {
|
describe('updateAll', () => {
|
||||||
@@ -456,7 +473,7 @@ describe(AssetService.name, () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should relatively update an assets with timezone', async () => {
|
it('should relatively update assets with timezone', async () => {
|
||||||
const { sut, ctx } = setup();
|
const { sut, ctx } = setup();
|
||||||
ctx.getMock(JobRepository).queueAll.mockResolvedValue();
|
ctx.getMock(JobRepository).queueAll.mockResolvedValue();
|
||||||
const { user } = await ctx.newUser();
|
const { user } = await ctx.newUser();
|
||||||
@@ -477,7 +494,7 @@ describe(AssetService.name, () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should relatively update an assets and set a timezone', async () => {
|
it('should relatively update assets and set a timezone', async () => {
|
||||||
const { sut, ctx } = setup();
|
const { sut, ctx } = setup();
|
||||||
ctx.getMock(JobRepository).queueAll.mockResolvedValue();
|
ctx.getMock(JobRepository).queueAll.mockResolvedValue();
|
||||||
const { user } = await ctx.newUser();
|
const { user } = await ctx.newUser();
|
||||||
@@ -497,6 +514,26 @@ describe(AssetService.name, () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should set asset time zones to UTC', async () => {
|
||||||
|
const { sut, ctx } = setup();
|
||||||
|
ctx.getMock(JobRepository).queueAll.mockResolvedValue();
|
||||||
|
const { user } = await ctx.newUser();
|
||||||
|
const auth = factory.auth({ user });
|
||||||
|
const { asset } = await ctx.newAsset({ ownerId: user.id });
|
||||||
|
await ctx.newExif({ assetId: asset.id, dateTimeOriginal: '2023-11-19T18:11:00', timeZone: 'UTC-7' });
|
||||||
|
|
||||||
|
await sut.updateAll(auth, { ids: [asset.id], timeZone: 'UTC' });
|
||||||
|
|
||||||
|
await expect(ctx.get(AssetRepository).getById(asset.id, { exifInfo: true })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
exifInfo: expect.objectContaining({
|
||||||
|
dateTimeOriginal: '2023-11-19T18:11:00+00:00',
|
||||||
|
timeZone: 'UTC',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('should update dateTimeOriginal', async () => {
|
it('should update dateTimeOriginal', async () => {
|
||||||
const { sut, ctx } = setup();
|
const { sut, ctx } = setup();
|
||||||
ctx.getMock(JobRepository).queueAll.mockResolvedValue();
|
ctx.getMock(JobRepository).queueAll.mockResolvedValue();
|
||||||
@@ -530,6 +567,23 @@ describe(AssetService.name, () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should update dateTimeOriginal with UTC time zone', async () => {
|
||||||
|
const { sut, ctx } = setup();
|
||||||
|
ctx.getMock(JobRepository).queueAll.mockResolvedValue();
|
||||||
|
const { user } = await ctx.newUser();
|
||||||
|
const auth = factory.auth({ user });
|
||||||
|
const { asset } = await ctx.newAsset({ ownerId: user.id });
|
||||||
|
await ctx.newExif({ assetId: asset.id, description: 'test', timeZone: 'UTC-7' });
|
||||||
|
|
||||||
|
await sut.updateAll(auth, { ids: [asset.id], dateTimeOriginal: '2023-11-19T18:11:00.000Z' });
|
||||||
|
|
||||||
|
await expect(ctx.get(AssetRepository).getById(asset.id, { exifInfo: true })).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
exifInfo: expect.objectContaining({ dateTimeOriginal: '2023-11-19T18:11:00+00:00', timeZone: 'UTC' }),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('upsertBulkMetadata', () => {
|
describe('upsertBulkMetadata', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user