mirror of
https://github.com/immich-app/immich.git
synced 2025-02-11 01:18:24 -05:00
Merge branch 'feat/nullable-dates' of https://github.com/immich-app/immich into feat/inline-offline-check
This commit is contained in:
commit
92177576c1
5 changed files with 21 additions and 62 deletions
|
@ -542,7 +542,6 @@ describe(AssetMediaService.name, () => {
|
||||||
|
|
||||||
it('should throw an error if the requested preview file does not exist', async () => {
|
it('should throw an error if the requested preview file does not exist', async () => {
|
||||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set([assetStub.image.id]));
|
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set([assetStub.image.id]));
|
||||||
|
|
||||||
assetMock.getById.mockResolvedValue({
|
assetMock.getById.mockResolvedValue({
|
||||||
...assetStub.image,
|
...assetStub.image,
|
||||||
files: [
|
files: [
|
||||||
|
@ -563,7 +562,6 @@ describe(AssetMediaService.name, () => {
|
||||||
|
|
||||||
it('should fall back to preview if the requested thumbnail file does not exist', async () => {
|
it('should fall back to preview if the requested thumbnail file does not exist', async () => {
|
||||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set([assetStub.image.id]));
|
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set([assetStub.image.id]));
|
||||||
|
|
||||||
assetMock.getById.mockResolvedValue({
|
assetMock.getById.mockResolvedValue({
|
||||||
...assetStub.image,
|
...assetStub.image,
|
||||||
files: [
|
files: [
|
||||||
|
|
|
@ -574,8 +574,7 @@ export class LibraryService extends BaseService {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mtime = stat.mtime;
|
const mtime = stat.mtime;
|
||||||
|
const isTimeUpdated = !asset.fileModifiedAt || mtime.toISOString() !== asset.fileModifiedAt.toISOString();
|
||||||
const isTimeUpdated = asset.fileModifiedAt === null || mtime.toISOString() !== asset.fileModifiedAt.toISOString();
|
|
||||||
|
|
||||||
if (isTimeUpdated) {
|
if (isTimeUpdated) {
|
||||||
this.logger.verbose(
|
this.logger.verbose(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { ContainerDirectoryItem, ExifDateTime, Maybe, Tags } from 'exiftool-vendored';
|
import { ContainerDirectoryItem, ExifDateTime, Maybe, Tags } from 'exiftool-vendored';
|
||||||
import { firstDateTime } from 'exiftool-vendored/dist/FirstDateTime';
|
import { firstDateTime } from 'exiftool-vendored/dist/FirstDateTime';
|
||||||
import { Insertable } from 'kysely';
|
import { Insertable } from 'kysely';
|
||||||
|
@ -588,17 +588,7 @@ export class MetadataService extends BaseService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDates(asset: AssetEntity, exifTags: ImmichTags): AssetDatesDto {
|
private getDates(asset: AssetEntity, exifTags: ImmichTags) {
|
||||||
// We first assert that fileCreatedAt and fileModifiedAt are not null since that should be set to a non-null value before calling this function
|
|
||||||
if (asset.fileCreatedAt === null) {
|
|
||||||
this.logger.warn(`Asset ${asset.id} has no file creation date`);
|
|
||||||
throw new BadRequestException(`Asset ${asset.id} has no file creation date`);
|
|
||||||
}
|
|
||||||
if (asset.fileModifiedAt === null) {
|
|
||||||
this.logger.warn(`Asset ${asset.id} has no file modification date`);
|
|
||||||
throw new BadRequestException(`Asset ${asset.id} has no file modification date`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const dateTime = firstDateTime(exifTags as Maybe<Tags>, EXIF_DATE_TAGS);
|
const dateTime = firstDateTime(exifTags as Maybe<Tags>, EXIF_DATE_TAGS);
|
||||||
this.logger.verbose(`Asset ${asset.id} date time is ${dateTime}`);
|
this.logger.verbose(`Asset ${asset.id} date time is ${dateTime}`);
|
||||||
|
|
||||||
|
@ -630,11 +620,7 @@ export class MetadataService extends BaseService {
|
||||||
localDateTime = earliestDate;
|
localDateTime = earliestDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localDateTime) {
|
this.logger.verbose(`Asset ${asset.id} has a local time of ${localDateTime.toISOString()}`);
|
||||||
this.logger.verbose(`Asset ${asset.id} has a local time of ${localDateTime.toISOString()}`);
|
|
||||||
} else {
|
|
||||||
this.logger.verbose(`Asset ${asset.id} has no time set`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let modifyDate = asset.fileModifiedAt;
|
let modifyDate = asset.fileModifiedAt;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -310,12 +310,6 @@ export class StorageTemplateService extends BaseService {
|
||||||
|
|
||||||
const systemTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
const systemTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
const zone = asset.exifInfo?.timeZone || systemTimeZone;
|
const zone = asset.exifInfo?.timeZone || systemTimeZone;
|
||||||
|
|
||||||
if (!asset.fileCreatedAt) {
|
|
||||||
this.logger.log(`Asset ${asset.id} is missing fileCreatedAt, skipping storage template migration`);
|
|
||||||
throw new Error(`Missing fileCreatedAt for asset ${asset.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const dt = DateTime.fromJSDate(asset.fileCreatedAt, { zone });
|
const dt = DateTime.fromJSDate(asset.fileCreatedAt, { zone });
|
||||||
|
|
||||||
for (const token of Object.values(storageTokens).flat()) {
|
for (const token of Object.values(storageTokens).flat()) {
|
||||||
|
|
|
@ -29,8 +29,6 @@ type TimeZoneTest = {
|
||||||
description: string;
|
description: string;
|
||||||
serverTimeZone?: string;
|
serverTimeZone?: string;
|
||||||
exifData: Record<string, any>;
|
exifData: Record<string, any>;
|
||||||
fileCreatedAt: Date;
|
|
||||||
fileModifiedAt: Date;
|
|
||||||
expected: {
|
expected: {
|
||||||
localDateTime: string;
|
localDateTime: string;
|
||||||
dateTimeOriginal: string;
|
dateTimeOriginal: string;
|
||||||
|
@ -60,8 +58,6 @@ describe(MetadataService.name, () => {
|
||||||
const timeZoneTests: TimeZoneTest[] = [
|
const timeZoneTests: TimeZoneTest[] = [
|
||||||
{
|
{
|
||||||
description: 'should handle no time zone information',
|
description: 'should handle no time zone information',
|
||||||
fileCreatedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
fileModifiedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
exifData: {
|
exifData: {
|
||||||
DateTimeOriginal: '2022:01:01 00:00:00',
|
DateTimeOriginal: '2022:01:01 00:00:00',
|
||||||
},
|
},
|
||||||
|
@ -73,8 +69,6 @@ describe(MetadataService.name, () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'should handle no time zone information and server behind UTC',
|
description: 'should handle no time zone information and server behind UTC',
|
||||||
fileCreatedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
fileModifiedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
serverTimeZone: 'America/Los_Angeles',
|
serverTimeZone: 'America/Los_Angeles',
|
||||||
exifData: {
|
exifData: {
|
||||||
DateTimeOriginal: '2022:01:01 00:00:00',
|
DateTimeOriginal: '2022:01:01 00:00:00',
|
||||||
|
@ -87,8 +81,6 @@ describe(MetadataService.name, () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'should handle no time zone information and server ahead of UTC',
|
description: 'should handle no time zone information and server ahead of UTC',
|
||||||
fileCreatedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
fileModifiedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
serverTimeZone: 'Europe/Brussels',
|
serverTimeZone: 'Europe/Brussels',
|
||||||
exifData: {
|
exifData: {
|
||||||
DateTimeOriginal: '2022:01:01 00:00:00',
|
DateTimeOriginal: '2022:01:01 00:00:00',
|
||||||
|
@ -101,8 +93,6 @@ describe(MetadataService.name, () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'should handle no time zone information and server ahead of UTC in the summer',
|
description: 'should handle no time zone information and server ahead of UTC in the summer',
|
||||||
fileCreatedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
fileModifiedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
serverTimeZone: 'Europe/Brussels',
|
serverTimeZone: 'Europe/Brussels',
|
||||||
exifData: {
|
exifData: {
|
||||||
DateTimeOriginal: '2022:06:01 00:00:00',
|
DateTimeOriginal: '2022:06:01 00:00:00',
|
||||||
|
@ -115,8 +105,6 @@ describe(MetadataService.name, () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'should handle a +13:00 time zone',
|
description: 'should handle a +13:00 time zone',
|
||||||
fileCreatedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
fileModifiedAt: new Date('2022-01-01T00:00:00.000Z'),
|
|
||||||
exifData: {
|
exifData: {
|
||||||
DateTimeOriginal: '2022:01:01 00:00:00+13:00',
|
DateTimeOriginal: '2022:01:01 00:00:00+13:00',
|
||||||
},
|
},
|
||||||
|
@ -128,32 +116,26 @@ describe(MetadataService.name, () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
it.each(timeZoneTests)(
|
it.each(timeZoneTests)('$description', async ({ exifData, serverTimeZone, expected }) => {
|
||||||
'$description',
|
process.env.TZ = serverTimeZone ?? undefined;
|
||||||
async ({ exifData, serverTimeZone, expected, fileCreatedAt, fileModifiedAt }) => {
|
|
||||||
// TODO: the TZ environment variable is no longer used, remove it
|
|
||||||
process.env.TZ = serverTimeZone ?? undefined;
|
|
||||||
|
|
||||||
const { filePath } = await createTestFile(exifData);
|
const { filePath } = await createTestFile(exifData);
|
||||||
assetMock.getByIds.mockResolvedValue([
|
assetMock.getByIds.mockResolvedValue([{ id: 'asset-1', originalPath: filePath } as AssetEntity]);
|
||||||
{ id: 'asset-1', originalPath: filePath, fileCreatedAt, fileModifiedAt } as AssetEntity,
|
|
||||||
]);
|
|
||||||
|
|
||||||
await sut.handleMetadataExtraction({ id: 'asset-1' });
|
await sut.handleMetadataExtraction({ id: 'asset-1' });
|
||||||
|
|
||||||
expect(assetMock.upsertExif).toHaveBeenCalledWith(
|
expect(assetMock.upsertExif).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
dateTimeOriginal: new Date(expected.dateTimeOriginal),
|
dateTimeOriginal: new Date(expected.dateTimeOriginal),
|
||||||
timeZone: expected.timeZone,
|
timeZone: expected.timeZone,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(assetMock.update).toHaveBeenCalledWith(
|
expect(assetMock.update).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
localDateTime: new Date(expected.localDateTime),
|
localDateTime: new Date(expected.localDateTime),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue