mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	hotfix(server): skip exif extraction on duplicate file (#590)
* fix(server): skip exif extraction on duplicate file * fix(server): typo * chore(server): remvoe un-use code
This commit is contained in:
		
							parent
							
								
									a467936e73
								
							
						
					
					
						commit
						7f6837c751
					
				@ -47,6 +47,7 @@ import { GetAssetThumbnailDto } from './dto/get-asset-thumbnail.dto';
 | 
				
			|||||||
import { AssetCountByTimeBucketResponseDto } from './response-dto/asset-count-by-time-group-response.dto';
 | 
					import { AssetCountByTimeBucketResponseDto } from './response-dto/asset-count-by-time-group-response.dto';
 | 
				
			||||||
import { GetAssetCountByTimeBucketDto } from './dto/get-asset-count-by-time-bucket.dto';
 | 
					import { GetAssetCountByTimeBucketDto } from './dto/get-asset-count-by-time-bucket.dto';
 | 
				
			||||||
import { GetAssetByTimeBucketDto } from './dto/get-asset-by-time-bucket.dto';
 | 
					import { GetAssetByTimeBucketDto } from './dto/get-asset-by-time-bucket.dto';
 | 
				
			||||||
 | 
					import { QueryFailedError } from 'typeorm';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@UseGuards(JwtAuthGuard)
 | 
					@UseGuards(JwtAuthGuard)
 | 
				
			||||||
@ApiBearerAuth()
 | 
					@ApiBearerAuth()
 | 
				
			||||||
@ -74,8 +75,11 @@ export class AssetController {
 | 
				
			|||||||
    @UploadedFile() file: Express.Multer.File,
 | 
					    @UploadedFile() file: Express.Multer.File,
 | 
				
			||||||
    @Body(ValidationPipe) assetInfo: CreateAssetDto,
 | 
					    @Body(ValidationPipe) assetInfo: CreateAssetDto,
 | 
				
			||||||
  ): Promise<AssetFileUploadResponseDto> {
 | 
					  ): Promise<AssetFileUploadResponseDto> {
 | 
				
			||||||
 | 
					    const checksum = await this.assetService.calculateChecksum(file.path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const savedAsset = await this.assetService.createUserAsset(authUser, assetInfo, file.path, file.mimetype);
 | 
					      const savedAsset = await this.assetService.createUserAsset(authUser, assetInfo, file.path, file.mimetype, checksum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!savedAsset) {
 | 
					      if (!savedAsset) {
 | 
				
			||||||
        await this.backgroundTaskService.deleteFileOnDisk([
 | 
					        await this.backgroundTaskService.deleteFileOnDisk([
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
@ -92,14 +96,20 @@ export class AssetController {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return new AssetFileUploadResponseDto(savedAsset.id);
 | 
					      return new AssetFileUploadResponseDto(savedAsset.id);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (err) {
 | 
				
			||||||
      Logger.error(`Error uploading file ${e}`);
 | 
					 | 
				
			||||||
      await this.backgroundTaskService.deleteFileOnDisk([
 | 
					      await this.backgroundTaskService.deleteFileOnDisk([
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          originalPath: file.path,
 | 
					          originalPath: file.path,
 | 
				
			||||||
        } as any,
 | 
					        } as any,
 | 
				
			||||||
      ]); // simulate asset to make use of delete queue (or use fs.unlink instead)
 | 
					      ]); // simulate asset to make use of delete queue (or use fs.unlink instead)
 | 
				
			||||||
      throw new BadRequestException(`Error uploading file`, `${e}`);
 | 
					
 | 
				
			||||||
 | 
					      if (err instanceof QueryFailedError && (err as any).constraint === 'UQ_userid_checksum') {
 | 
				
			||||||
 | 
					        const existedAsset = await this.assetService.getAssetByChecksum(authUser.id, checksum)
 | 
				
			||||||
 | 
					        return new AssetFileUploadResponseDto(existedAsset.id);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Logger.error(`Error uploading file ${err}`);
 | 
				
			||||||
 | 
					      throw new BadRequestException(`Error uploading file`, `${err}`);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ import {
 | 
				
			|||||||
} from '@nestjs/common';
 | 
					} from '@nestjs/common';
 | 
				
			||||||
import { InjectRepository } from '@nestjs/typeorm';
 | 
					import { InjectRepository } from '@nestjs/typeorm';
 | 
				
			||||||
import { createHash } from 'node:crypto';
 | 
					import { createHash } from 'node:crypto';
 | 
				
			||||||
import { QueryFailedError, Repository } from 'typeorm';
 | 
					import { Repository } from 'typeorm';
 | 
				
			||||||
import { AuthUserDto } from '../../decorators/auth-user.decorator';
 | 
					import { AuthUserDto } from '../../decorators/auth-user.decorator';
 | 
				
			||||||
import { AssetEntity, AssetType } from '@app/database/entities/asset.entity';
 | 
					import { AssetEntity, AssetType } from '@app/database/entities/asset.entity';
 | 
				
			||||||
import { constants, createReadStream, ReadStream, stat } from 'fs';
 | 
					import { constants, createReadStream, ReadStream, stat } from 'fs';
 | 
				
			||||||
@ -53,31 +53,17 @@ export class AssetService {
 | 
				
			|||||||
    createAssetDto: CreateAssetDto,
 | 
					    createAssetDto: CreateAssetDto,
 | 
				
			||||||
    originalPath: string,
 | 
					    originalPath: string,
 | 
				
			||||||
    mimeType: string,
 | 
					    mimeType: string,
 | 
				
			||||||
 | 
					    checksum: Buffer,
 | 
				
			||||||
  ): Promise<AssetEntity> {
 | 
					  ): Promise<AssetEntity> {
 | 
				
			||||||
    const checksum = await this.calculateChecksum(originalPath);
 | 
					    const assetEntity = await this._assetRepository.create(
 | 
				
			||||||
 | 
					      createAssetDto,
 | 
				
			||||||
 | 
					      authUser.id,
 | 
				
			||||||
 | 
					      originalPath,
 | 
				
			||||||
 | 
					      mimeType,
 | 
				
			||||||
 | 
					      checksum,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    return assetEntity;
 | 
				
			||||||
      const assetEntity = await this._assetRepository.create(
 | 
					 | 
				
			||||||
        createAssetDto,
 | 
					 | 
				
			||||||
        authUser.id,
 | 
					 | 
				
			||||||
        originalPath,
 | 
					 | 
				
			||||||
        mimeType,
 | 
					 | 
				
			||||||
        checksum,
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return assetEntity;
 | 
					 | 
				
			||||||
    } catch (err) {
 | 
					 | 
				
			||||||
      if (err instanceof QueryFailedError && (err as any).constraint === 'UQ_userid_checksum') {
 | 
					 | 
				
			||||||
        const [assetEntity, _] = await Promise.all([
 | 
					 | 
				
			||||||
          this._assetRepository.getAssetByChecksum(authUser.id, checksum),
 | 
					 | 
				
			||||||
          fs.unlink(originalPath)
 | 
					 | 
				
			||||||
        ]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return assetEntity;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      throw err;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public async getUserAssetsByDeviceId(authUser: AuthUserDto, deviceId: string) {
 | 
					  public async getUserAssetsByDeviceId(authUser: AuthUserDto, deviceId: string) {
 | 
				
			||||||
@ -478,7 +464,11 @@ export class AssetService {
 | 
				
			|||||||
    return mapAssetCountByTimeBucket(result);
 | 
					    return mapAssetCountByTimeBucket(result);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private calculateChecksum(filePath: string): Promise<Buffer> {
 | 
					  getAssetByChecksum(userId: string, checksum: Buffer) {
 | 
				
			||||||
 | 
					    return this._assetRepository.getAssetByChecksum(userId, checksum);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  calculateChecksum(filePath: string): Promise<Buffer> {
 | 
				
			||||||
    const fileReadStream = createReadStream(filePath);
 | 
					    const fileReadStream = createReadStream(filePath);
 | 
				
			||||||
    const sha1Hash = createHash('sha1');
 | 
					    const sha1Hash = createHash('sha1');
 | 
				
			||||||
    const deferred = new Promise<Buffer>((resolve, reject) => {
 | 
					    const deferred = new Promise<Buffer>((resolve, reject) => {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user