refactor: dedicated queries for asset jobs (#17652)

This commit is contained in:
Daniel Dietzler
2025-04-16 20:08:49 +02:00
committed by GitHub
parent 8f8ff3adc0
commit f50e5d006c
12 changed files with 310 additions and 163 deletions
+26 -12
View File
@@ -9,9 +9,9 @@ import { constants } from 'node:fs/promises';
import path from 'node:path';
import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants';
import { StorageCore } from 'src/cores/storage.core';
import { Asset, AssetFace } from 'src/database';
import { AssetFaces, Exif, Person } from 'src/db';
import { OnEvent, OnJob } from 'src/decorators';
import { AssetEntity } from 'src/entities/asset.entity';
import {
AssetType,
DatabaseLock,
@@ -134,7 +134,10 @@ export class MetadataService extends BaseService {
}
}
private async linkLivePhotos(asset: AssetEntity, exifInfo: Insertable<Exif>): Promise<void> {
private async linkLivePhotos(
asset: { id: string; type: AssetType; ownerId: string; libraryId: string | null },
exifInfo: Insertable<Exif>,
): Promise<void> {
if (!exifInfo.livePhotoCID) {
return;
}
@@ -182,9 +185,9 @@ export class MetadataService extends BaseService {
@OnJob({ name: JobName.METADATA_EXTRACTION, queue: QueueName.METADATA_EXTRACTION })
async handleMetadataExtraction(data: JobOf<JobName.METADATA_EXTRACTION>): Promise<JobStatus> {
const [{ metadata, reverseGeocoding }, [asset]] = await Promise.all([
const [{ metadata, reverseGeocoding }, asset] = await Promise.all([
this.getConfig({ withCache: true }),
this.assetRepository.getByIds([data.id], { faces: { person: false } }),
this.assetJobRepository.getForMetadataExtraction(data.id),
]);
if (!asset) {
@@ -268,7 +271,7 @@ export class MetadataService extends BaseService {
];
if (this.isMotionPhoto(asset, exifTags)) {
promises.push(this.applyMotionPhotos(asset, exifTags, dates, stats));
promises.push(this.applyMotionPhotos(asset as unknown as Asset, exifTags, dates, stats));
}
if (isFaceImportEnabled(metadata) && this.hasTaggedFaces(exifTags)) {
@@ -376,7 +379,11 @@ export class MetadataService extends BaseService {
return { width, height };
}
private getExifTags(asset: AssetEntity): Promise<ImmichTags> {
private getExifTags(asset: {
originalPath: string;
sidecarPath: string | null;
type: AssetType;
}): Promise<ImmichTags> {
if (!asset.sidecarPath && asset.type === AssetType.IMAGE) {
return this.metadataRepository.readTags(asset.originalPath);
}
@@ -384,7 +391,11 @@ export class MetadataService extends BaseService {
return this.mergeExifTags(asset);
}
private async mergeExifTags(asset: AssetEntity): Promise<ImmichTags> {
private async mergeExifTags(asset: {
originalPath: string;
sidecarPath: string | null;
type: AssetType;
}): Promise<ImmichTags> {
const [mediaTags, sidecarTags, videoTags] = await Promise.all([
this.metadataRepository.readTags(asset.originalPath),
asset.sidecarPath ? this.metadataRepository.readTags(asset.sidecarPath) : null,
@@ -434,7 +445,7 @@ export class MetadataService extends BaseService {
return tags;
}
private async applyTagList(asset: AssetEntity, exifTags: ImmichTags) {
private async applyTagList(asset: { id: string; ownerId: string }, exifTags: ImmichTags) {
const tags = this.getTagList(exifTags);
const results = await upsertTags(this.tagRepository, { userId: asset.ownerId, tags });
await this.tagRepository.replaceAssetTags(
@@ -443,11 +454,11 @@ export class MetadataService extends BaseService {
);
}
private isMotionPhoto(asset: AssetEntity, tags: ImmichTags): boolean {
private isMotionPhoto(asset: { type: AssetType }, tags: ImmichTags): boolean {
return asset.type === AssetType.IMAGE && !!(tags.MotionPhoto || tags.MicroVideo);
}
private async applyMotionPhotos(asset: AssetEntity, tags: ImmichTags, dates: Dates, stats: Stats) {
private async applyMotionPhotos(asset: Asset, tags: ImmichTags, dates: Dates, stats: Stats) {
const isMotionPhoto = tags.MotionPhoto;
const isMicroVideo = tags.MicroVideo;
const videoOffset = tags.MicroVideoOffset;
@@ -582,7 +593,10 @@ export class MetadataService extends BaseService {
);
}
private async applyTaggedFaces(asset: AssetEntity, tags: ImmichTags) {
private async applyTaggedFaces(
asset: { id: string; ownerId: string; faces: AssetFace[]; originalPath: string },
tags: ImmichTags,
) {
if (!tags.RegionInfo?.AppliedToDimensions || tags.RegionInfo.RegionList.length === 0) {
return;
}
@@ -649,7 +663,7 @@ export class MetadataService extends BaseService {
}
}
private getDates(asset: AssetEntity, exifTags: ImmichTags, stats: Stats) {
private getDates(asset: { id: string; originalPath: string }, exifTags: ImmichTags, stats: Stats) {
const dateTime = firstDateTime(exifTags as Maybe<Tags>, EXIF_DATE_TAGS);
this.logger.verbose(`Date and time is ${dateTime} for asset ${asset.id}: ${asset.originalPath}`);