refactor: enum casing (#19946)

This commit is contained in:
Jason Rasmussen
2025-07-15 14:50:13 -04:00
committed by GitHub
parent 920d7de349
commit e73abe0762
174 changed files with 2675 additions and 2459 deletions
+50 -50
View File
@@ -126,7 +126,7 @@ type Dates = {
@Injectable()
export class MetadataService extends BaseService {
@OnEvent({ name: 'AppBootstrap', workers: [ImmichWorker.MICROSERVICES] })
@OnEvent({ name: 'AppBootstrap', workers: [ImmichWorker.Microservices] })
async onBootstrap() {
this.logger.log('Bootstrapping metadata service');
await this.init();
@@ -137,12 +137,12 @@ export class MetadataService extends BaseService {
await this.metadataRepository.teardown();
}
@OnEvent({ name: 'ConfigInit', workers: [ImmichWorker.MICROSERVICES] })
@OnEvent({ name: 'ConfigInit', workers: [ImmichWorker.Microservices] })
onConfigInit({ newConfig }: ArgOf<'ConfigInit'>) {
this.metadataRepository.setMaxConcurrency(newConfig.job.metadataExtraction.concurrency);
}
@OnEvent({ name: 'ConfigUpdate', workers: [ImmichWorker.MICROSERVICES], server: true })
@OnEvent({ name: 'ConfigUpdate', workers: [ImmichWorker.Microservices], server: true })
onConfigUpdate({ newConfig }: ArgOf<'ConfigUpdate'>) {
this.metadataRepository.setMaxConcurrency(newConfig.job.metadataExtraction.concurrency);
}
@@ -151,9 +151,9 @@ export class MetadataService extends BaseService {
this.logger.log('Initializing metadata service');
try {
await this.jobRepository.pause(QueueName.METADATA_EXTRACTION);
await this.jobRepository.pause(QueueName.MetadataExtraction);
await this.databaseRepository.withLock(DatabaseLock.GeodataImport, () => this.mapRepository.init());
await this.jobRepository.resume(QueueName.METADATA_EXTRACTION);
await this.jobRepository.resume(QueueName.MetadataExtraction);
this.logger.log(`Initialized local reverse geocoder`);
} catch (error: Error | any) {
@@ -170,7 +170,7 @@ export class MetadataService extends BaseService {
return;
}
const otherType = asset.type === AssetType.VIDEO ? AssetType.IMAGE : AssetType.VIDEO;
const otherType = asset.type === AssetType.Video ? AssetType.Image : AssetType.Video;
const match = await this.assetRepository.findLivePhotoMatch({
livePhotoCID: exifInfo.livePhotoCID,
ownerId: asset.ownerId,
@@ -183,23 +183,23 @@ export class MetadataService extends BaseService {
return;
}
const [photoAsset, motionAsset] = asset.type === AssetType.IMAGE ? [asset, match] : [match, asset];
const [photoAsset, motionAsset] = asset.type === AssetType.Image ? [asset, match] : [match, asset];
await Promise.all([
this.assetRepository.update({ id: photoAsset.id, livePhotoVideoId: motionAsset.id }),
this.assetRepository.update({ id: motionAsset.id, visibility: AssetVisibility.HIDDEN }),
this.assetRepository.update({ id: motionAsset.id, visibility: AssetVisibility.Hidden }),
this.albumRepository.removeAssetsFromAll([motionAsset.id]),
]);
await this.eventRepository.emit('AssetHide', { assetId: motionAsset.id, userId: motionAsset.ownerId });
}
@OnJob({ name: JobName.QUEUE_METADATA_EXTRACTION, queue: QueueName.METADATA_EXTRACTION })
async handleQueueMetadataExtraction(job: JobOf<JobName.QUEUE_METADATA_EXTRACTION>): Promise<JobStatus> {
@OnJob({ name: JobName.QueueMetadataExtraction, queue: QueueName.MetadataExtraction })
async handleQueueMetadataExtraction(job: JobOf<JobName.QueueMetadataExtraction>): Promise<JobStatus> {
const { force } = job;
let queue: { name: JobName.METADATA_EXTRACTION; data: { id: string } }[] = [];
let queue: { name: JobName.MetadataExtraction; data: { id: string } }[] = [];
for await (const asset of this.assetJobRepository.streamForMetadataExtraction(force)) {
queue.push({ name: JobName.METADATA_EXTRACTION, data: { id: asset.id } });
queue.push({ name: JobName.MetadataExtraction, data: { id: asset.id } });
if (queue.length >= JOBS_ASSET_PAGINATION_SIZE) {
await this.jobRepository.queueAll(queue);
@@ -208,11 +208,11 @@ export class MetadataService extends BaseService {
}
await this.jobRepository.queueAll(queue);
return JobStatus.SUCCESS;
return JobStatus.Success;
}
@OnJob({ name: JobName.METADATA_EXTRACTION, queue: QueueName.METADATA_EXTRACTION })
async handleMetadataExtraction(data: JobOf<JobName.METADATA_EXTRACTION>) {
@OnJob({ name: JobName.MetadataExtraction, queue: QueueName.MetadataExtraction })
async handleMetadataExtraction(data: JobOf<JobName.MetadataExtraction>) {
const [{ metadata, reverseGeocoding }, asset] = await Promise.all([
this.getConfig({ withCache: true }),
this.assetJobRepository.getForMetadataExtraction(data.id),
@@ -320,8 +320,8 @@ export class MetadataService extends BaseService {
});
}
@OnJob({ name: JobName.QUEUE_SIDECAR, queue: QueueName.SIDECAR })
async handleQueueSidecar({ force }: JobOf<JobName.QUEUE_SIDECAR>): Promise<JobStatus> {
@OnJob({ name: JobName.QueueSidecar, queue: QueueName.Sidecar })
async handleQueueSidecar({ force }: JobOf<JobName.QueueSidecar>): Promise<JobStatus> {
let jobs: JobItem[] = [];
const queueAll = async () => {
await this.jobRepository.queueAll(jobs);
@@ -330,7 +330,7 @@ export class MetadataService extends BaseService {
const assets = this.assetJobRepository.streamForSidecar(force);
for await (const asset of assets) {
jobs.push({ name: force ? JobName.SIDECAR_SYNC : JobName.SIDECAR_DISCOVERY, data: { id: asset.id } });
jobs.push({ name: force ? JobName.SidecarSync : JobName.SidecarDiscovery, data: { id: asset.id } });
if (jobs.length >= JOBS_ASSET_PAGINATION_SIZE) {
await queueAll();
}
@@ -338,35 +338,35 @@ export class MetadataService extends BaseService {
await queueAll();
return JobStatus.SUCCESS;
return JobStatus.Success;
}
@OnJob({ name: JobName.SIDECAR_SYNC, queue: QueueName.SIDECAR })
handleSidecarSync({ id }: JobOf<JobName.SIDECAR_SYNC>): Promise<JobStatus> {
@OnJob({ name: JobName.SidecarSync, queue: QueueName.Sidecar })
handleSidecarSync({ id }: JobOf<JobName.SidecarSync>): Promise<JobStatus> {
return this.processSidecar(id, true);
}
@OnJob({ name: JobName.SIDECAR_DISCOVERY, queue: QueueName.SIDECAR })
handleSidecarDiscovery({ id }: JobOf<JobName.SIDECAR_DISCOVERY>): Promise<JobStatus> {
@OnJob({ name: JobName.SidecarDiscovery, queue: QueueName.Sidecar })
handleSidecarDiscovery({ id }: JobOf<JobName.SidecarDiscovery>): Promise<JobStatus> {
return this.processSidecar(id, false);
}
@OnEvent({ name: 'AssetTag' })
async handleTagAsset({ assetId }: ArgOf<'AssetTag'>) {
await this.jobRepository.queue({ name: JobName.SIDECAR_WRITE, data: { id: assetId, tags: true } });
await this.jobRepository.queue({ name: JobName.SidecarWrite, data: { id: assetId, tags: true } });
}
@OnEvent({ name: 'AssetUntag' })
async handleUntagAsset({ assetId }: ArgOf<'AssetUntag'>) {
await this.jobRepository.queue({ name: JobName.SIDECAR_WRITE, data: { id: assetId, tags: true } });
await this.jobRepository.queue({ name: JobName.SidecarWrite, data: { id: assetId, tags: true } });
}
@OnJob({ name: JobName.SIDECAR_WRITE, queue: QueueName.SIDECAR })
async handleSidecarWrite(job: JobOf<JobName.SIDECAR_WRITE>): Promise<JobStatus> {
@OnJob({ name: JobName.SidecarWrite, queue: QueueName.Sidecar })
async handleSidecarWrite(job: JobOf<JobName.SidecarWrite>): Promise<JobStatus> {
const { id, description, dateTimeOriginal, latitude, longitude, rating, tags } = job;
const asset = await this.assetJobRepository.getForSidecarWriteJob(id);
if (!asset) {
return JobStatus.FAILED;
return JobStatus.Failed;
}
const tagsList = (asset.tags || []).map((tag) => tag.value);
@@ -386,7 +386,7 @@ export class MetadataService extends BaseService {
);
if (Object.keys(exif).length === 0) {
return JobStatus.SKIPPED;
return JobStatus.Skipped;
}
await this.metadataRepository.writeTags(sidecarPath, exif);
@@ -395,7 +395,7 @@ export class MetadataService extends BaseService {
await this.assetRepository.update({ id, sidecarPath });
}
return JobStatus.SUCCESS;
return JobStatus.Success;
}
private getImageDimensions(exifTags: ImmichTags): { width?: number; height?: number } {
@@ -416,7 +416,7 @@ export class MetadataService extends BaseService {
sidecarPath: string | null;
type: AssetType;
}): Promise<ImmichTags> {
if (!asset.sidecarPath && asset.type === AssetType.IMAGE) {
if (!asset.sidecarPath && asset.type === AssetType.Image) {
return this.metadataRepository.readTags(asset.originalPath);
}
@@ -431,7 +431,7 @@ export class MetadataService extends BaseService {
const [mediaTags, sidecarTags, videoTags] = await Promise.all([
this.metadataRepository.readTags(asset.originalPath),
asset.sidecarPath ? this.metadataRepository.readTags(asset.sidecarPath) : null,
asset.type === AssetType.VIDEO ? this.getVideoTags(asset.originalPath) : null,
asset.type === AssetType.Video ? this.getVideoTags(asset.originalPath) : null,
]);
// prefer dates from sidecar tags
@@ -488,7 +488,7 @@ export class MetadataService extends BaseService {
}
private isMotionPhoto(asset: { type: AssetType }, tags: ImmichTags): boolean {
return asset.type === AssetType.IMAGE && !!(tags.MotionPhoto || tags.MicroVideo);
return asset.type === AssetType.Image && !!(tags.MotionPhoto || tags.MicroVideo);
}
private async applyMotionPhotos(asset: Asset, tags: ImmichTags, dates: Dates, stats: Stats) {
@@ -558,10 +558,10 @@ export class MetadataService extends BaseService {
});
// Hide the motion photo video asset if it's not already hidden to prepare for linking
if (motionAsset.visibility === AssetVisibility.TIMELINE) {
if (motionAsset.visibility === AssetVisibility.Timeline) {
await this.assetRepository.update({
id: motionAsset.id,
visibility: AssetVisibility.HIDDEN,
visibility: AssetVisibility.Hidden,
});
this.logger.log(`Hid unlinked motion photo video asset (${motionAsset.id})`);
}
@@ -570,7 +570,7 @@ export class MetadataService extends BaseService {
motionAsset = await this.assetRepository.create({
id: motionAssetId,
libraryId: asset.libraryId,
type: AssetType.VIDEO,
type: AssetType.Video,
fileCreatedAt: dates.dateTimeOriginal,
fileModifiedAt: stats.mtime,
localDateTime: dates.localDateTime,
@@ -578,7 +578,7 @@ export class MetadataService extends BaseService {
ownerId: asset.ownerId,
originalPath: StorageCore.getAndroidMotionPath(asset, motionAssetId),
originalFileName: `${path.parse(asset.originalFileName).name}.mp4`,
visibility: AssetVisibility.HIDDEN,
visibility: AssetVisibility.Hidden,
deviceAssetId: 'NONE',
deviceId: 'NONE',
});
@@ -597,7 +597,7 @@ export class MetadataService extends BaseService {
// note asset.livePhotoVideoId is not motionAsset.id yet
if (asset.livePhotoVideoId) {
await this.jobRepository.queue({
name: JobName.ASSET_DELETION,
name: JobName.AssetDeletion,
data: { id: asset.livePhotoVideoId, deleteOnDisk: true },
});
this.logger.log(`Removed old motion photo video asset (${asset.livePhotoVideoId})`);
@@ -612,7 +612,7 @@ export class MetadataService extends BaseService {
this.logger.log(`Wrote motion photo video to ${motionAsset.originalPath}`);
await this.handleMetadataExtraction({ id: motionAsset.id });
await this.jobRepository.queue({ name: JobName.VIDEO_CONVERSION, data: { id: motionAsset.id } });
await this.jobRepository.queue({ name: JobName.VideoConversation, data: { id: motionAsset.id } });
}
this.logger.debug(`Finished motion photo video extraction for asset ${asset.id}: ${asset.originalPath}`);
@@ -740,7 +740,7 @@ export class MetadataService extends BaseService {
boundingBoxY1: Math.floor((region.Area.Y - region.Area.H / 2) * imageHeight),
boundingBoxX2: Math.floor((region.Area.X + region.Area.W / 2) * imageWidth),
boundingBoxY2: Math.floor((region.Area.Y + region.Area.H / 2) * imageHeight),
sourceType: SourceType.EXIF,
sourceType: SourceType.Exif,
};
facesToAdd.push(face);
@@ -753,11 +753,11 @@ export class MetadataService extends BaseService {
if (missing.length > 0) {
this.logger.debugFn(() => `Creating missing persons: ${missing.map((p) => `${p.name}/${p.id}`)}`);
const newPersonIds = await this.personRepository.createAll(missing);
const jobs = newPersonIds.map((id) => ({ name: JobName.GENERATE_PERSON_THUMBNAIL, data: { id } }) as const);
const jobs = newPersonIds.map((id) => ({ name: JobName.GeneratePersonThumbnail, data: { id } }) as const);
await this.jobRepository.queueAll(jobs);
}
const facesToRemove = asset.faces.filter((face) => face.sourceType === SourceType.EXIF).map((face) => face.id);
const facesToRemove = asset.faces.filter((face) => face.sourceType === SourceType.Exif).map((face) => face.id);
if (facesToRemove.length > 0) {
this.logger.debug(`Removing ${facesToRemove.length} faces for asset ${asset.id}: ${asset.originalPath}`);
}
@@ -894,15 +894,15 @@ export class MetadataService extends BaseService {
const [asset] = await this.assetRepository.getByIds([id]);
if (!asset) {
return JobStatus.FAILED;
return JobStatus.Failed;
}
if (isSync && !asset.sidecarPath) {
return JobStatus.FAILED;
return JobStatus.Failed;
}
if (!isSync && (asset.visibility === AssetVisibility.HIDDEN || asset.sidecarPath) && !asset.isExternal) {
return JobStatus.FAILED;
if (!isSync && (asset.visibility === AssetVisibility.Hidden || asset.sidecarPath) && !asset.isExternal) {
return JobStatus.Failed;
}
// XMP sidecars can come in two filename formats. For a photo named photo.ext, the filenames are photo.ext.xmp and photo.xmp
@@ -927,22 +927,22 @@ export class MetadataService extends BaseService {
if (sidecarPath !== asset.sidecarPath) {
await this.assetRepository.update({ id: asset.id, sidecarPath });
}
return JobStatus.SUCCESS;
return JobStatus.Success;
}
if (sidecarPath) {
this.logger.debug(`Detected sidecar at '${sidecarPath}' for asset ${asset.id}: ${asset.originalPath}`);
await this.assetRepository.update({ id: asset.id, sidecarPath });
return JobStatus.SUCCESS;
return JobStatus.Success;
}
if (!isSync) {
return JobStatus.FAILED;
return JobStatus.Failed;
}
this.logger.debug(`No sidecar found for asset ${asset.id}: ${asset.originalPath}`);
await this.assetRepository.update({ id: asset.id, sidecarPath: null });
return JobStatus.SUCCESS;
return JobStatus.Success;
}
}