mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
Implemented EXIF store and display (#19)
* Added EXIF extracting in the backend * Added EXIF displaying on `image_viewer_page.dart` * Added Icon for backup option not enable
This commit is contained in:
24
server/src/modules/background-task/background-task.module.ts
Normal file
24
server/src/modules/background-task/background-task.module.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { BullModule } from '@nestjs/bull';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AssetEntity } from '../../api-v1/asset/entities/asset.entity';
|
||||
import { ExifEntity } from '../../api-v1/asset/entities/exif.entity';
|
||||
import { BackgroundTaskProcessor } from './background-task.processor';
|
||||
import { BackgroundTaskService } from './background-task.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
BullModule.registerQueue({
|
||||
name: 'background-task',
|
||||
defaultJobOptions: {
|
||||
attempts: 3,
|
||||
removeOnComplete: true,
|
||||
removeOnFail: false,
|
||||
},
|
||||
}),
|
||||
TypeOrmModule.forFeature([AssetEntity, ExifEntity]),
|
||||
],
|
||||
providers: [BackgroundTaskService, BackgroundTaskProcessor],
|
||||
exports: [BackgroundTaskService],
|
||||
})
|
||||
export class BackgroundTaskModule {}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { InjectQueue, Process, Processor } from '@nestjs/bull';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Job, Queue } from 'bull';
|
||||
import { Repository } from 'typeorm';
|
||||
import { AssetEntity } from '../../api-v1/asset/entities/asset.entity';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import exifr from 'exifr';
|
||||
import { readFile } from 'fs/promises';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { ExifEntity } from '../../api-v1/asset/entities/exif.entity';
|
||||
|
||||
@Processor('background-task')
|
||||
export class BackgroundTaskProcessor {
|
||||
constructor(
|
||||
@InjectRepository(AssetEntity)
|
||||
private assetRepository: Repository<AssetEntity>,
|
||||
|
||||
@InjectRepository(ExifEntity)
|
||||
private exifRepository: Repository<ExifEntity>,
|
||||
|
||||
private configService: ConfigService,
|
||||
) {}
|
||||
|
||||
@Process('extract-exif')
|
||||
async extractExif(job: Job) {
|
||||
const { savedAsset, fileName, fileSize }: { savedAsset: AssetEntity; fileName: string; fileSize: number } =
|
||||
job.data;
|
||||
|
||||
const fileBuffer = await readFile(savedAsset.originalPath);
|
||||
|
||||
const exifData = await exifr.parse(fileBuffer);
|
||||
|
||||
const newExif = new ExifEntity();
|
||||
newExif.assetId = savedAsset.id;
|
||||
newExif.make = exifData['Make'] || null;
|
||||
newExif.model = exifData['Model'] || null;
|
||||
newExif.imageName = fileName || null;
|
||||
newExif.exifImageHeight = exifData['ExifImageHeight'] || null;
|
||||
newExif.exifImageWidth = exifData['ExifImageWidth'] || null;
|
||||
newExif.fileSizeInByte = fileSize || null;
|
||||
newExif.orientation = exifData['Orientation'] || null;
|
||||
newExif.dateTimeOriginal = exifData['DateTimeOriginal'] || null;
|
||||
newExif.modifyDate = exifData['ModifyDate'] || null;
|
||||
newExif.lensModel = exifData['LensModel'] || null;
|
||||
newExif.fNumber = exifData['FNumber'] || null;
|
||||
newExif.focalLength = exifData['FocalLength'] || null;
|
||||
newExif.iso = exifData['ISO'] || null;
|
||||
newExif.exposureTime = exifData['ExposureTime'] || null;
|
||||
newExif.latitude = exifData['latitude'] || null;
|
||||
newExif.longitude = exifData['longitude'] || null;
|
||||
|
||||
await this.exifRepository.save(newExif);
|
||||
|
||||
try {
|
||||
} catch (e) {
|
||||
Logger.error(`Error extracting EXIF ${e.toString()}`, 'extractExif');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { InjectQueue } from '@nestjs/bull/dist/decorators';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Queue } from 'bull';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { AssetEntity } from '../../api-v1/asset/entities/asset.entity';
|
||||
|
||||
@Injectable()
|
||||
export class BackgroundTaskService {
|
||||
constructor(
|
||||
@InjectQueue('background-task')
|
||||
private backgroundTaskQueue: Queue,
|
||||
) {}
|
||||
|
||||
async extractExif(savedAsset: AssetEntity, fileName: string, fileSize: number) {
|
||||
const job = await this.backgroundTaskQueue.add(
|
||||
'extract-exif',
|
||||
{
|
||||
savedAsset,
|
||||
fileName,
|
||||
fileSize,
|
||||
},
|
||||
{ jobId: randomUUID() },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ export class AssetOptimizeService {
|
||||
};
|
||||
}
|
||||
|
||||
public async getVideoThumbnail(savedAsset: AssetEntity, filename: String) {
|
||||
public async getVideoThumbnail(savedAsset: AssetEntity, filename: string) {
|
||||
const job = await this.optimizeQueue.add(
|
||||
'get-video-thumbnail',
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user