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; |       newExif.livePhotoCID = exifData?.MediaGroupUUID || null; | ||||||
|  |  | ||||||
|       if (newExif.livePhotoCID && !asset.livePhotoVideoId) { |       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) { |         if (motionAsset) { | ||||||
|           await this.assetCore.save({ id: asset.id, livePhotoVideoId: motionAsset.id }); |           await this.assetCore.save({ id: asset.id, livePhotoVideoId: motionAsset.id }); | ||||||
|           await this.assetCore.save({ id: motionAsset.id, isVisible: false }); |           await this.assetCore.save({ id: motionAsset.id, isVisible: false }); | ||||||
| @@ -331,7 +336,12 @@ export class MetadataExtractionProcessor { | |||||||
|       newExif.livePhotoCID = exifData?.ContentIdentifier || null; |       newExif.livePhotoCID = exifData?.ContentIdentifier || null; | ||||||
|  |  | ||||||
|       if (newExif.livePhotoCID) { |       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) { |         if (photoAsset) { | ||||||
|           await this.assetCore.save({ id: photoAsset.id, livePhotoVideoId: asset.id }); |           await this.assetCore.save({ id: photoAsset.id, livePhotoVideoId: asset.id }); | ||||||
|           await this.assetCore.save({ id: asset.id, isVisible: false }); |           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 { IJobRepository, JobName } from '../job'; | ||||||
| import { AssetSearchOptions, IAssetRepository } from './asset.repository'; | import { AssetSearchOptions, IAssetRepository, LivePhotoSearchOptions } from './asset.repository'; | ||||||
|  |  | ||||||
| export class AssetCore { | export class AssetCore { | ||||||
|   constructor(private assetRepository: IAssetRepository, private jobRepository: IJobRepository) {} |   constructor(private assetRepository: IAssetRepository, private jobRepository: IJobRepository) {} | ||||||
| @@ -18,7 +18,7 @@ export class AssetCore { | |||||||
|     return _asset; |     return _asset; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   findLivePhotoMatch(livePhotoCID: string, otherAssetId: string, type: AssetType): Promise<AssetEntity | null> { |   findLivePhotoMatch(options: LivePhotoSearchOptions): Promise<AssetEntity | null> { | ||||||
|     return this.assetRepository.findLivePhotoMatch(livePhotoCID, otherAssetId, type); |     return this.assetRepository.findLivePhotoMatch(options); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,6 +5,13 @@ export interface AssetSearchOptions { | |||||||
|   type?: AssetType; |   type?: AssetType; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface LivePhotoSearchOptions { | ||||||
|  |   ownerId: string; | ||||||
|  |   livePhotoCID: string; | ||||||
|  |   otherAssetId: string; | ||||||
|  |   type: AssetType; | ||||||
|  | } | ||||||
|  |  | ||||||
| export enum WithoutProperty { | export enum WithoutProperty { | ||||||
|   THUMBNAIL = 'thumbnail', |   THUMBNAIL = 'thumbnail', | ||||||
|   ENCODED_VIDEO = 'encoded-video', |   ENCODED_VIDEO = 'encoded-video', | ||||||
| @@ -22,5 +29,5 @@ export interface IAssetRepository { | |||||||
|   deleteAll(ownerId: string): Promise<void>; |   deleteAll(ownerId: string): Promise<void>; | ||||||
|   getAll(options?: AssetSearchOptions): Promise<AssetEntity[]>; |   getAll(options?: AssetSearchOptions): Promise<AssetEntity[]>; | ||||||
|   save(asset: Partial<AssetEntity>): 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 { Injectable } from '@nestjs/common'; | ||||||
| import { InjectRepository } from '@nestjs/typeorm'; | import { InjectRepository } from '@nestjs/typeorm'; | ||||||
| import { FindOptionsRelations, FindOptionsWhere, In, IsNull, Not, Repository } from '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({ |     return this.repository.findOne({ | ||||||
|       where: { |       where: { | ||||||
|         id: Not(otherAssetId), |         id: Not(otherAssetId), | ||||||
|  |         ownerId, | ||||||
|         type, |         type, | ||||||
|         exifInfo: { |         exifInfo: { | ||||||
|           livePhotoCID, |           livePhotoCID, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user