From 29d229c5baf9cc14cce420c10059cc1857b8bbb4 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Tue, 20 Aug 2024 21:23:50 -0400 Subject: [PATCH] fix(server): do not match live photos across libraries (#11952) --- server/src/interfaces/asset.interface.ts | 1 + server/src/repositories/asset.repository.ts | 3 ++- server/src/services/metadata.service.spec.ts | 23 ++++++++++++++++++++ server/src/services/metadata.service.ts | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/server/src/interfaces/asset.interface.ts b/server/src/interfaces/asset.interface.ts index 6dd81edaef..05ea84a5ae 100644 --- a/server/src/interfaces/asset.interface.ts +++ b/server/src/interfaces/asset.interface.ts @@ -16,6 +16,7 @@ export interface AssetStatsOptions { export interface LivePhotoSearchOptions { ownerId: string; + libraryId?: string | null; livePhotoCID: string; otherAssetId: string; type: AssetType; diff --git a/server/src/repositories/asset.repository.ts b/server/src/repositories/asset.repository.ts index a74451f9a5..8e97d54817 100644 --- a/server/src/repositories/asset.repository.ts +++ b/server/src/repositories/asset.repository.ts @@ -363,12 +363,13 @@ export class AssetRepository implements IAssetRepository { } findLivePhotoMatch(options: LivePhotoSearchOptions): Promise { - const { ownerId, otherAssetId, livePhotoCID, type } = options; + const { ownerId, libraryId, otherAssetId, livePhotoCID, type } = options; return this.repository.findOne({ where: { id: Not(otherAssetId), ownerId, + libraryId: libraryId || IsNull(), type, exifInfo: { livePhotoCID, diff --git a/server/src/services/metadata.service.spec.ts b/server/src/services/metadata.service.spec.ts index 05f6f9f658..6585b8c2ee 100644 --- a/server/src/services/metadata.service.spec.ts +++ b/server/src/services/metadata.service.spec.ts @@ -218,6 +218,29 @@ describe(MetadataService.name, () => { assetStub.livePhotoMotionAsset.id, ); }); + + it('should search by libraryId', async () => { + assetMock.getByIds.mockResolvedValue([ + { + ...assetStub.livePhotoStillAsset, + libraryId: 'library-id', + exifInfo: { livePhotoCID: 'CID' } as ExifEntity, + }, + ]); + assetMock.findLivePhotoMatch.mockResolvedValue(null); + + await expect(sut.handleLivePhotoLinking({ id: assetStub.livePhotoStillAsset.id })).resolves.toBe( + JobStatus.SKIPPED, + ); + + expect(assetMock.findLivePhotoMatch).toHaveBeenCalledWith({ + ownerId: 'user-id', + otherAssetId: 'live-photo-still-asset', + livePhotoCID: 'CID', + libraryId: 'library-id', + type: 'VIDEO', + }); + }); }); describe('handleQueueMetadataExtraction', () => { diff --git a/server/src/services/metadata.service.ts b/server/src/services/metadata.service.ts index f1d367fb7b..dcdf07b8c3 100644 --- a/server/src/services/metadata.service.ts +++ b/server/src/services/metadata.service.ts @@ -173,6 +173,7 @@ export class MetadataService { const match = await this.assetRepository.findLivePhotoMatch({ livePhotoCID: asset.exifInfo.livePhotoCID, ownerId: asset.ownerId, + libraryId: asset.libraryId, otherAssetId: asset.id, type: otherType, });