refactor(server): link live photos as part of metadata extraction instead of queueing job (#16390)

* link live photos helper instead of job

* update test

* queue storage template migration

* queue in onDone

* remove link live photos job
This commit is contained in:
Mert
2025-03-03 17:19:36 +03:00
committed by GitHub
parent eb74fafb00
commit 5698f446f7
6 changed files with 121 additions and 157 deletions
+17 -24
View File
@@ -113,21 +113,14 @@ export class MetadataService extends BaseService {
}
}
@OnJob({ name: JobName.LINK_LIVE_PHOTOS, queue: QueueName.METADATA_EXTRACTION })
async handleLivePhotoLinking(job: JobOf<JobName.LINK_LIVE_PHOTOS>): Promise<JobStatus> {
const { id } = job;
const [asset] = await this.assetRepository.getByIds([id], { exifInfo: true });
if (!asset?.exifInfo) {
return JobStatus.FAILED;
}
if (!asset.exifInfo.livePhotoCID) {
return JobStatus.SKIPPED;
private async linkLivePhotos(asset: AssetEntity, exifInfo: Insertable<Exif>): Promise<void> {
if (!exifInfo.livePhotoCID) {
return;
}
const otherType = asset.type === AssetType.VIDEO ? AssetType.IMAGE : AssetType.VIDEO;
const match = await this.assetRepository.findLivePhotoMatch({
livePhotoCID: asset.exifInfo.livePhotoCID,
livePhotoCID: exifInfo.livePhotoCID,
ownerId: asset.ownerId,
libraryId: asset.libraryId,
otherAssetId: asset.id,
@@ -135,18 +128,17 @@ export class MetadataService extends BaseService {
});
if (!match) {
return JobStatus.SKIPPED;
return;
}
const [photoAsset, motionAsset] = asset.type === AssetType.IMAGE ? [asset, match] : [match, asset];
await this.assetRepository.update({ id: photoAsset.id, livePhotoVideoId: motionAsset.id });
await this.assetRepository.update({ id: motionAsset.id, isVisible: false });
await this.albumRepository.removeAsset(motionAsset.id);
await Promise.all([
this.assetRepository.update({ id: photoAsset.id, livePhotoVideoId: motionAsset.id }),
this.assetRepository.update({ id: motionAsset.id, isVisible: false }),
this.albumRepository.removeAsset(motionAsset.id),
]);
await this.eventRepository.emit('asset.hide', { assetId: motionAsset.id, userId: motionAsset.ownerId });
return JobStatus.SUCCESS;
}
@OnJob({ name: JobName.QUEUE_METADATA_EXTRACTION, queue: QueueName.METADATA_EXTRACTION })
@@ -168,9 +160,9 @@ export class MetadataService extends BaseService {
}
@OnJob({ name: JobName.METADATA_EXTRACTION, queue: QueueName.METADATA_EXTRACTION })
async handleMetadataExtraction({ id }: JobOf<JobName.METADATA_EXTRACTION>): Promise<JobStatus> {
async handleMetadataExtraction(data: JobOf<JobName.METADATA_EXTRACTION>): Promise<JobStatus> {
const { metadata, reverseGeocoding } = await this.getConfig({ withCache: true });
const [asset] = await this.assetRepository.getByIds([id], { faces: { person: false } });
const [asset] = await this.assetRepository.getByIds([data.id], { faces: { person: false } });
if (!asset) {
return JobStatus.FAILED;
}
@@ -251,15 +243,16 @@ export class MetadataService extends BaseService {
fileModifiedAt: stats.mtime,
});
await this.assetRepository.upsertJobStatus({
assetId: asset.id,
metadataExtractedAt: new Date(),
});
if (exifData.livePhotoCID) {
await this.linkLivePhotos(asset, exifData);
}
if (isFaceImportEnabled(metadata)) {
await this.applyTaggedFaces(asset, exifTags);
}
await this.assetRepository.upsertJobStatus({ assetId: asset.id, metadataExtractedAt: new Date() });
return JobStatus.SUCCESS;
}