|
@@ -1,4 +1,5 @@
|
|
|
import {
|
|
|
+ IAlbumRepository,
|
|
|
IAssetRepository,
|
|
|
IBaseJob,
|
|
|
ICryptoRepository,
|
|
@@ -59,6 +60,7 @@ export class MetadataExtractionProcessor {
|
|
|
|
|
|
constructor(
|
|
|
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
|
|
|
+ @Inject(IAlbumRepository) private albumRepository: IAlbumRepository,
|
|
|
@Inject(IJobRepository) private jobRepository: IJobRepository,
|
|
|
@Inject(IGeocodingRepository) private geocodingRepository: IGeocodingRepository,
|
|
|
@Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository,
|
|
@@ -92,6 +94,38 @@ export class MetadataExtractionProcessor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ async handleLivePhotoLinking(job: IEntityJob) {
|
|
|
+ const { id } = job;
|
|
|
+ const [asset] = await this.assetRepository.getByIds([id]);
|
|
|
+ if (!asset?.exifInfo) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!asset.exifInfo.livePhotoCID) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ const otherType = asset.type === AssetType.VIDEO ? AssetType.IMAGE : AssetType.VIDEO;
|
|
|
+ const match = await this.assetRepository.findLivePhotoMatch({
|
|
|
+ livePhotoCID: asset.exifInfo.livePhotoCID,
|
|
|
+ ownerId: asset.ownerId,
|
|
|
+ otherAssetId: asset.id,
|
|
|
+ type: otherType,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!match) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ const [photoAsset, motionAsset] = asset.type === AssetType.IMAGE ? [asset, match] : [match, asset];
|
|
|
+
|
|
|
+ await this.assetRepository.save({ id: photoAsset.id, livePhotoVideoId: motionAsset.id });
|
|
|
+ await this.assetRepository.save({ id: motionAsset.id, isVisible: false });
|
|
|
+ await this.albumRepository.removeAsset(motionAsset.id);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
async handleQueueMetadataExtraction(job: IBaseJob) {
|
|
|
const { force } = job;
|
|
|
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => {
|
|
@@ -351,19 +385,6 @@ export class MetadataExtractionProcessor {
|
|
|
}
|
|
|
|
|
|
newExif.livePhotoCID = getExifProperty('MediaGroupUUID');
|
|
|
- if (newExif.livePhotoCID && !asset.livePhotoVideoId) {
|
|
|
- const motionAsset = await this.assetRepository.findLivePhotoMatch({
|
|
|
- livePhotoCID: newExif.livePhotoCID,
|
|
|
- otherAssetId: asset.id,
|
|
|
- ownerId: asset.ownerId,
|
|
|
- type: AssetType.VIDEO,
|
|
|
- });
|
|
|
- if (motionAsset) {
|
|
|
- await this.assetRepository.save({ id: asset.id, livePhotoVideoId: motionAsset.id });
|
|
|
- await this.assetRepository.save({ id: motionAsset.id, isVisible: false });
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
await this.applyReverseGeocoding(asset, newExif);
|
|
|
|
|
|
/**
|
|
@@ -428,19 +449,6 @@ export class MetadataExtractionProcessor {
|
|
|
newExif.fps = null;
|
|
|
newExif.livePhotoCID = exifData?.ContentIdentifier || null;
|
|
|
|
|
|
- if (newExif.livePhotoCID) {
|
|
|
- const photoAsset = await this.assetRepository.findLivePhotoMatch({
|
|
|
- livePhotoCID: newExif.livePhotoCID,
|
|
|
- ownerId: asset.ownerId,
|
|
|
- otherAssetId: asset.id,
|
|
|
- type: AssetType.IMAGE,
|
|
|
- });
|
|
|
- if (photoAsset) {
|
|
|
- await this.assetRepository.save({ id: photoAsset.id, livePhotoVideoId: asset.id });
|
|
|
- await this.assetRepository.save({ id: asset.id, isVisible: false });
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
if (videoTags && videoTags['location']) {
|
|
|
const location = videoTags['location'] as string;
|
|
|
const locationRegex = /([+-][0-9]+\.[0-9]+)([+-][0-9]+\.[0-9]+)\/$/;
|