From b768eef44de548b0159ddf10f1dbab29c8efc837 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 2 Feb 2024 14:58:13 -0600 Subject: [PATCH] fix(server): extract duration from video as ISO time (#6863) * fix(server): extract duration from video as ISO time * feedback and add test * fix test --- .../src/domain/metadata/metadata.service.spec.ts | 16 ++++++++++++++++ server/src/domain/metadata/metadata.service.ts | 7 +++++-- .../domain/repositories/metadata.repository.ts | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/server/src/domain/metadata/metadata.service.spec.ts b/server/src/domain/metadata/metadata.service.spec.ts index 9a3a4bfed..e27e5f2ee 100644 --- a/server/src/domain/metadata/metadata.service.spec.ts +++ b/server/src/domain/metadata/metadata.service.spec.ts @@ -547,6 +547,22 @@ describe(MetadataService.name, () => { ); }); + it('should handle duration in ISO time string', async () => { + assetMock.getByIds.mockResolvedValue([assetStub.image]); + metadataMock.readTags.mockResolvedValue({ Duration: '00:00:08.41' }); + + await sut.handleMetadataExtraction({ id: assetStub.image.id }); + + expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.image.id]); + expect(assetMock.upsertExif).toHaveBeenCalled(); + expect(assetMock.save).toHaveBeenCalledWith( + expect.objectContaining({ + id: assetStub.image.id, + duration: '00:00:08.410', + }), + ); + }); + it('should handle duration as an object without Scale', async () => { assetMock.getByIds.mockResolvedValue([assetStub.image]); metadataMock.readTags.mockResolvedValue({ Duration: { Value: 6.2 } }); diff --git a/server/src/domain/metadata/metadata.service.ts b/server/src/domain/metadata/metadata.service.ts index 12ad57006..bcec1ac68 100644 --- a/server/src/domain/metadata/metadata.service.ts +++ b/server/src/domain/metadata/metadata.service.ts @@ -12,7 +12,6 @@ import { IBaseJob, IEntityJob, ISidecarWriteJob, JOBS_ASSET_PAGINATION_SIZE, Job import { ClientEvent, DatabaseLock, - ExifDuration, IAlbumRepository, IAssetRepository, ICommunicationRepository, @@ -555,11 +554,15 @@ export class MetadataService { return bitsPerSample; } - private getDuration(seconds?: number | ExifDuration): string { + private getDuration(seconds?: ImmichTags['Duration']): string { let _seconds = seconds as number; + if (typeof seconds === 'object') { _seconds = seconds.Value * (seconds?.Scale || 1); + } else if (typeof seconds === 'string') { + _seconds = Duration.fromISOTime(seconds).as('seconds'); } + return Duration.fromObject({ seconds: _seconds }).toFormat('hh:mm:ss.SSS'); } } diff --git a/server/src/domain/repositories/metadata.repository.ts b/server/src/domain/repositories/metadata.repository.ts index 98df4517a..ca9cfe497 100644 --- a/server/src/domain/repositories/metadata.repository.ts +++ b/server/src/domain/repositories/metadata.repository.ts @@ -26,7 +26,7 @@ export interface ImmichTags extends Omit { MediaGroupUUID?: string; ImagePixelDepth?: string; FocalLength?: number; - Duration?: number | ExifDuration; + Duration?: number | string | ExifDuration; EmbeddedVideoType?: string; EmbeddedVideoFile?: BinaryField; MotionPhotoVideo?: BinaryField;