diff --git a/server/apps/immich/src/config/asset-upload.config.ts b/server/apps/immich/src/config/asset-upload.config.ts index 364edb69f2..fd5185ed2d 100644 --- a/server/apps/immich/src/config/asset-upload.config.ts +++ b/server/apps/immich/src/config/asset-upload.config.ts @@ -9,7 +9,7 @@ import { randomUUID } from 'crypto'; export const assetUploadOption: MulterOptions = { fileFilter: (req: Request, file: any, cb: any) => { - if (file.mimetype.match(/\/(jpg|jpeg|png|gif|mp4|x-msvideo|quicktime|heic|heif|dng|x-adobe-dng|webp)$/)) { + if (file.mimetype.match(/\/(jpg|jpeg|png|gif|mp4|x-msvideo|quicktime|heic|heif|dng|x-adobe-dng|webp|tiff)$/)) { cb(null, true); } else { cb(new HttpException(`Unsupported file type ${extname(file.originalname)}`, HttpStatus.BAD_REQUEST), false); diff --git a/server/apps/microservices/src/processors/metadata-extraction.processor.ts b/server/apps/microservices/src/processors/metadata-extraction.processor.ts index be667b9c6c..e3f9161797 100644 --- a/server/apps/microservices/src/processors/metadata-extraction.processor.ts +++ b/server/apps/microservices/src/processors/metadata-extraction.processor.ts @@ -60,8 +60,8 @@ export class MetadataExtractionProcessor { newExif.make = exifData['Make'] || null; newExif.model = exifData['Model'] || null; newExif.imageName = path.parse(fileName).name || null; - newExif.exifImageHeight = exifData['ExifImageHeight'] || null; - newExif.exifImageWidth = exifData['ExifImageWidth'] || null; + newExif.exifImageHeight = exifData['ExifImageHeight'] || exifData['ImageHeight'] || null; + newExif.exifImageWidth = exifData['ExifImageWidth'] || exifData['ImageWidth'] || null; newExif.fileSizeInByte = fileSize || null; newExif.orientation = exifData['Orientation'] || null; newExif.dateTimeOriginal = exifData['DateTimeOriginal'] || null; diff --git a/server/apps/microservices/src/processors/thumbnail.processor.ts b/server/apps/microservices/src/processors/thumbnail.processor.ts index 8f53a726f4..086542353a 100644 --- a/server/apps/microservices/src/processors/thumbnail.processor.ts +++ b/server/apps/microservices/src/processors/thumbnail.processor.ts @@ -51,62 +51,47 @@ export class ThumbnailGeneratorProcessor { const jpegThumbnailPath = resizePath + originalFilename + '.jpeg'; if (asset.type == AssetType.IMAGE) { - sharp(asset.originalPath) - .resize(1440, 2560, { fit: 'inside' }) - .jpeg() - .rotate() - .toFile(jpegThumbnailPath, async (err) => { - if (!err) { - await this.assetRepository.update({ id: asset.id }, { resizePath: jpegThumbnailPath }); + await sharp(asset.originalPath).resize(1440, 2560, { fit: 'inside' }).jpeg().rotate().toFile(jpegThumbnailPath); + await this.assetRepository.update({ id: asset.id }, { resizePath: jpegThumbnailPath }); - // Update resize path to send to generate webp queue - asset.resizePath = jpegThumbnailPath; + // Update resize path to send to generate webp queue + asset.resizePath = jpegThumbnailPath; - await this.thumbnailGeneratorQueue.add( - generateWEBPThumbnailProcessorName, - { asset }, - { jobId: randomUUID() }, - ); - await this.metadataExtractionQueue.add(imageTaggingProcessorName, { asset }, { jobId: randomUUID() }); - await this.metadataExtractionQueue.add(objectDetectionProcessorName, { asset }, { jobId: randomUUID() }); - this.wsCommunicationGateway.server - .to(asset.userId) - .emit('on_upload_success', JSON.stringify(mapAsset(asset))); - } - }); + await this.thumbnailGeneratorQueue.add(generateWEBPThumbnailProcessorName, { asset }, { jobId: randomUUID() }); + await this.metadataExtractionQueue.add(imageTaggingProcessorName, { asset }, { jobId: randomUUID() }); + await this.metadataExtractionQueue.add(objectDetectionProcessorName, { asset }, { jobId: randomUUID() }); + this.wsCommunicationGateway.server.to(asset.userId).emit('on_upload_success', JSON.stringify(mapAsset(asset))); } if (asset.type == AssetType.VIDEO) { - ffmpeg(asset.originalPath) - .outputOptions(['-ss 00:00:00.000', '-frames:v 1']) - .output(jpegThumbnailPath) - .on('start', () => { - Logger.log('Start Generating Video Thumbnail', 'generateJPEGThumbnail'); - }) - .on('error', (error) => { - Logger.error(`Cannot Generate Video Thumbnail ${error}`, 'generateJPEGThumbnail'); - // reject(); - }) - .on('end', async () => { - Logger.log(`Generating Video Thumbnail Success ${asset.id}`, 'generateJPEGThumbnail'); - await this.assetRepository.update({ id: asset.id }, { resizePath: jpegThumbnailPath }); + await new Promise((resolve, reject) => { + ffmpeg(asset.originalPath) + .outputOptions(['-ss 00:00:00.000', '-frames:v 1']) + .output(jpegThumbnailPath) + .on('start', () => { + Logger.log('Start Generating Video Thumbnail', 'generateJPEGThumbnail'); + }) + .on('error', (error) => { + Logger.error(`Cannot Generate Video Thumbnail ${error}`, 'generateJPEGThumbnail'); + reject(error); + }) + .on('end', async () => { + Logger.log(`Generating Video Thumbnail Success ${asset.id}`, 'generateJPEGThumbnail'); + resolve(asset); + }) + .run(); + }); - // Update resize path to send to generate webp queue - asset.resizePath = jpegThumbnailPath; + await this.assetRepository.update({ id: asset.id }, { resizePath: jpegThumbnailPath }); - await this.thumbnailGeneratorQueue.add( - generateWEBPThumbnailProcessorName, - { asset }, - { jobId: randomUUID() }, - ); - await this.metadataExtractionQueue.add(imageTaggingProcessorName, { asset }, { jobId: randomUUID() }); - await this.metadataExtractionQueue.add(objectDetectionProcessorName, { asset }, { jobId: randomUUID() }); + // Update resize path to send to generate webp queue + asset.resizePath = jpegThumbnailPath; - this.wsCommunicationGateway.server - .to(asset.userId) - .emit('on_upload_success', JSON.stringify(mapAsset(asset))); - }) - .run(); + await this.thumbnailGeneratorQueue.add(generateWEBPThumbnailProcessorName, { asset }, { jobId: randomUUID() }); + await this.metadataExtractionQueue.add(imageTaggingProcessorName, { asset }, { jobId: randomUUID() }); + await this.metadataExtractionQueue.add(objectDetectionProcessorName, { asset }, { jobId: randomUUID() }); + + this.wsCommunicationGateway.server.to(asset.userId).emit('on_upload_success', JSON.stringify(mapAsset(asset))); } } @@ -117,16 +102,10 @@ export class ThumbnailGeneratorProcessor { if (!asset.resizePath) { return; } + const webpPath = asset.resizePath.replace('jpeg', 'webp'); - sharp(asset.resizePath) - .resize(250) - .webp() - .rotate() - .toFile(webpPath, (err) => { - if (!err) { - this.assetRepository.update({ id: asset.id }, { webpPath: webpPath }); - } - }); + await sharp(asset.resizePath).resize(250).webp().rotate().toFile(webpPath); + await this.assetRepository.update({ id: asset.id }, { webpPath: webpPath }); } }