hunk.code_window:       newExif.longitude = exifData?.GPSLongitude || null;
         newExif.livePhotoCID = exifData?.MediaGroupUUID || null;
         if (newExif.livePhotoCID && !asset.livePhotoVideoId) {
           const motionAsset = await this.assetCore.findLivePhotoMatch(newExif.livePhotoCID, asset.id, AssetType.VIDEO);
           if (motionAsset) {
             await this.assetCore.save({ id: asset.id, livePhotoVideoId: motionAsset.id });
             await this.assetCore.save({ id: motionAsset.id, isVisible: false });
           }
         }
  
hunk.labels: keep keep keep keep replace keep keep keep keep keep
hunk.after_edit:         const motionAsset = await this.assetCore.findLivePhotoMatch({
             livePhotoCID: newExif.livePhotoCID,
             otherAssetId: asset.id,
             ownerId: asset.ownerId,
             type: AssetType.VIDEO,
           });
  
hunk.file_path: server/apps/microservices/src/processors/metadata-extraction.processor.ts
hunk.type: replace
file: import { AssetEntity, AssetType } from '@app/infra/entities';
  import { IJobRepository, JobName } from '../job';
  import { AssetSearchOptions, IAssetRepository } from './asset.repository';
  
  export class AssetCore {
    constructor(private assetRepository: IAssetRepository, private jobRepository: IJobRepository) {}
  
    getAll(options: AssetSearchOptions) {
      return this.assetRepository.getAll(options);
    }
  
    async save(asset: Partial<AssetEntity>) {
      const _asset = await this.assetRepository.save(asset);
      await this.jobRepository.queue({
        name: JobName.SEARCH_INDEX_ASSET,
        data: { ids: [_asset.id] },
      });
      return _asset;
    }
  
    findLivePhotoMatch(livePhotoCID: string, otherAssetId: string, type: AssetType): Promise<AssetEntity | null> {
      return this.assetRepository.findLivePhotoMatch(livePhotoCID, otherAssetId, type);
    }
  }
  