mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	fix(server): do not link live photos across users (#2162)
This commit is contained in:
		| @@ -229,7 +229,12 @@ export class MetadataExtractionProcessor { | ||||
|       newExif.livePhotoCID = exifData?.MediaGroupUUID || null; | ||||
|  | ||||
|       if (newExif.livePhotoCID && !asset.livePhotoVideoId) { | ||||
|         const motionAsset = await this.assetCore.findLivePhotoMatch(newExif.livePhotoCID, asset.id, AssetType.VIDEO); | ||||
|         const motionAsset = await this.assetCore.findLivePhotoMatch({ | ||||
|           livePhotoCID: newExif.livePhotoCID, | ||||
|           otherAssetId: asset.id, | ||||
|           ownerId: asset.ownerId, | ||||
|           type: AssetType.VIDEO, | ||||
|         }); | ||||
|         if (motionAsset) { | ||||
|           await this.assetCore.save({ id: asset.id, livePhotoVideoId: motionAsset.id }); | ||||
|           await this.assetCore.save({ id: motionAsset.id, isVisible: false }); | ||||
| @@ -331,7 +336,12 @@ export class MetadataExtractionProcessor { | ||||
|       newExif.livePhotoCID = exifData?.ContentIdentifier || null; | ||||
|  | ||||
|       if (newExif.livePhotoCID) { | ||||
|         const photoAsset = await this.assetCore.findLivePhotoMatch(newExif.livePhotoCID, asset.id, AssetType.IMAGE); | ||||
|         const photoAsset = await this.assetCore.findLivePhotoMatch({ | ||||
|           livePhotoCID: newExif.livePhotoCID, | ||||
|           ownerId: asset.ownerId, | ||||
|           otherAssetId: asset.id, | ||||
|           type: AssetType.IMAGE, | ||||
|         }); | ||||
|         if (photoAsset) { | ||||
|           await this.assetCore.save({ id: photoAsset.id, livePhotoVideoId: asset.id }); | ||||
|           await this.assetCore.save({ id: asset.id, isVisible: false }); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { AssetEntity, AssetType } from '@app/infra/entities'; | ||||
| import { AssetEntity } from '@app/infra/entities'; | ||||
| import { IJobRepository, JobName } from '../job'; | ||||
| import { AssetSearchOptions, IAssetRepository } from './asset.repository'; | ||||
| import { AssetSearchOptions, IAssetRepository, LivePhotoSearchOptions } from './asset.repository'; | ||||
|  | ||||
| export class AssetCore { | ||||
|   constructor(private assetRepository: IAssetRepository, private jobRepository: IJobRepository) {} | ||||
| @@ -18,7 +18,7 @@ export class AssetCore { | ||||
|     return _asset; | ||||
|   } | ||||
|  | ||||
|   findLivePhotoMatch(livePhotoCID: string, otherAssetId: string, type: AssetType): Promise<AssetEntity | null> { | ||||
|     return this.assetRepository.findLivePhotoMatch(livePhotoCID, otherAssetId, type); | ||||
|   findLivePhotoMatch(options: LivePhotoSearchOptions): Promise<AssetEntity | null> { | ||||
|     return this.assetRepository.findLivePhotoMatch(options); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,13 @@ export interface AssetSearchOptions { | ||||
|   type?: AssetType; | ||||
| } | ||||
|  | ||||
| export interface LivePhotoSearchOptions { | ||||
|   ownerId: string; | ||||
|   livePhotoCID: string; | ||||
|   otherAssetId: string; | ||||
|   type: AssetType; | ||||
| } | ||||
|  | ||||
| export enum WithoutProperty { | ||||
|   THUMBNAIL = 'thumbnail', | ||||
|   ENCODED_VIDEO = 'encoded-video', | ||||
| @@ -22,5 +29,5 @@ export interface IAssetRepository { | ||||
|   deleteAll(ownerId: string): Promise<void>; | ||||
|   getAll(options?: AssetSearchOptions): Promise<AssetEntity[]>; | ||||
|   save(asset: Partial<AssetEntity>): Promise<AssetEntity>; | ||||
|   findLivePhotoMatch(livePhotoCID: string, otherAssetId: string, type: AssetType): Promise<AssetEntity | null>; | ||||
|   findLivePhotoMatch(options: LivePhotoSearchOptions): Promise<AssetEntity | null>; | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { AssetSearchOptions, IAssetRepository, WithoutProperty } from '@app/domain'; | ||||
| import { AssetSearchOptions, IAssetRepository, LivePhotoSearchOptions, WithoutProperty } from '@app/domain'; | ||||
| import { Injectable } from '@nestjs/common'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
| import { FindOptionsRelations, FindOptionsWhere, In, IsNull, Not, Repository } from 'typeorm'; | ||||
| @@ -52,10 +52,13 @@ export class AssetRepository implements IAssetRepository { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   findLivePhotoMatch(livePhotoCID: string, otherAssetId: string, type: AssetType): Promise<AssetEntity | null> { | ||||
|   findLivePhotoMatch(options: LivePhotoSearchOptions): Promise<AssetEntity | null> { | ||||
|     const { ownerId, otherAssetId, livePhotoCID, type } = options; | ||||
|  | ||||
|     return this.repository.findOne({ | ||||
|       where: { | ||||
|         id: Not(otherAssetId), | ||||
|         ownerId, | ||||
|         type, | ||||
|         exifInfo: { | ||||
|           livePhotoCID, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user