diff --git a/Makefile b/Makefile index 33ddf504b8..033ffd6196 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ dev: docker-compose -f ./server/docker-compose.yml up -update: +dev-update: docker-compose -f ./server/docker-compose.yml up --build -V \ No newline at end of file diff --git a/mobile/lib/shared/providers/backup.provider.dart b/mobile/lib/shared/providers/backup.provider.dart index e17466e053..61477e79b5 100644 --- a/mobile/lib/shared/providers/backup.provider.dart +++ b/mobile/lib/shared/providers/backup.provider.dart @@ -35,7 +35,7 @@ class BackupNotifier extends StateNotifier { void getBackupInfo() async { _updateServerInfo(); - List list = await PhotoManager.getAssetPathList(onlyAll: true, type: RequestType.image); + List list = await PhotoManager.getAssetPathList(onlyAll: true, type: RequestType.common); if (list.isEmpty) { debugPrint("No Asset On Device"); @@ -59,7 +59,7 @@ class BackupNotifier extends StateNotifier { // await PhotoManager.presentLimited(); // Gather assets info List list = - await PhotoManager.getAssetPathList(hasAll: true, onlyAll: true, type: RequestType.image); + await PhotoManager.getAssetPathList(hasAll: true, onlyAll: true, type: RequestType.common); if (list.isEmpty) { debugPrint("No Asset On Device - Abort Backup Process"); diff --git a/mobile/lib/shared/services/backup.service.dart b/mobile/lib/shared/services/backup.service.dart index 0058dfadef..5ecdd4d103 100644 --- a/mobile/lib/shared/services/backup.service.dart +++ b/mobile/lib/shared/services/backup.service.dart @@ -12,7 +12,6 @@ import 'package:immich_mobile/utils/files_helper.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:http_parser/http_parser.dart'; import 'package:path/path.dart' as p; -import 'package:exif/exif.dart'; class BackupService { final NetworkService _networkService = NetworkService(); diff --git a/server/src/api-v1/asset/asset.controller.ts b/server/src/api-v1/asset/asset.controller.ts index 9acb48b287..ff6c0daafc 100644 --- a/server/src/api-v1/asset/asset.controller.ts +++ b/server/src/api-v1/asset/asset.controller.ts @@ -22,7 +22,7 @@ import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator'; import { CreateAssetDto } from './dto/create-asset.dto'; import { createReadStream } from 'fs'; import { ServeFileDto } from './dto/serve-file.dto'; -import { ImageOptimizeService } from '../../modules/image-optimize/image-optimize.service'; +import { AssetOptimizeService } from '../../modules/image-optimize/image-optimize.service'; import { AssetType } from './entities/asset.entity'; import { GetAllAssetQueryDto } from './dto/get-all-asset-query.dto'; @@ -31,7 +31,7 @@ import { GetAllAssetQueryDto } from './dto/get-all-asset-query.dto'; export class AssetController { constructor( private readonly assetService: AssetService, - private readonly imageOptimizeService: ImageOptimizeService, + private readonly assetOptimizeService: AssetOptimizeService, ) {} @Post('upload') @@ -45,7 +45,11 @@ export class AssetController { const savedAsset = await this.assetService.createUserAsset(authUser, assetInfo, file.path, file.mimetype); if (savedAsset && savedAsset.type == AssetType.IMAGE) { - await this.imageOptimizeService.resizeImage(savedAsset); + await this.assetOptimizeService.resizeImage(savedAsset); + } + + if (savedAsset && savedAsset.type == AssetType.IMAGE) { + await this.assetOptimizeService.resizeVideo(savedAsset); } }); diff --git a/server/src/api-v1/asset/asset.module.ts b/server/src/api-v1/asset/asset.module.ts index 2665845090..88e1a28e1d 100644 --- a/server/src/api-v1/asset/asset.module.ts +++ b/server/src/api-v1/asset/asset.module.ts @@ -4,13 +4,13 @@ import { AssetController } from './asset.controller'; import { TypeOrmModule } from '@nestjs/typeorm'; import { AssetEntity } from './entities/asset.entity'; import { ImageOptimizeModule } from '../../modules/image-optimize/image-optimize.module'; -import { ImageOptimizeService } from '../../modules/image-optimize/image-optimize.service'; +import { AssetOptimizeService } from '../../modules/image-optimize/image-optimize.service'; import { BullModule } from '@nestjs/bull'; @Module({ imports: [ BullModule.registerQueue({ - name: 'image', + name: 'optimize', defaultJobOptions: { attempts: 3, removeOnComplete: true, @@ -29,7 +29,7 @@ import { BullModule } from '@nestjs/bull'; ImageOptimizeModule, ], controllers: [AssetController], - providers: [AssetService, ImageOptimizeService], + providers: [AssetService, AssetOptimizeService], exports: [], }) export class AssetModule {} diff --git a/server/src/modules/image-optimize/image-optimize.module.ts b/server/src/modules/image-optimize/image-optimize.module.ts index 2b0222ec7f..5d378e3aa0 100644 --- a/server/src/modules/image-optimize/image-optimize.module.ts +++ b/server/src/modules/image-optimize/image-optimize.module.ts @@ -6,13 +6,13 @@ import { AssetModule } from '../../api-v1/asset/asset.module'; import { AssetService } from '../../api-v1/asset/asset.service'; import { AssetEntity } from '../../api-v1/asset/entities/asset.entity'; import { ImageOptimizeProcessor } from './image-optimize.processor'; -import { ImageOptimizeService } from './image-optimize.service'; +import { AssetOptimizeService } from './image-optimize.service'; import { MachineLearningProcessor } from './machine-learning.processor'; @Module({ imports: [ BullModule.registerQueue({ - name: 'image', + name: 'optimize', defaultJobOptions: { attempts: 3, removeOnComplete: true, @@ -30,7 +30,7 @@ import { MachineLearningProcessor } from './machine-learning.processor'; TypeOrmModule.forFeature([AssetEntity]), ], - providers: [ImageOptimizeService, ImageOptimizeProcessor, MachineLearningProcessor], - exports: [ImageOptimizeService], + providers: [AssetOptimizeService, ImageOptimizeProcessor, MachineLearningProcessor], + exports: [AssetOptimizeService], }) export class ImageOptimizeModule {} diff --git a/server/src/modules/image-optimize/image-optimize.processor.ts b/server/src/modules/image-optimize/image-optimize.processor.ts index 87fac6aedb..2f3496d13e 100644 --- a/server/src/modules/image-optimize/image-optimize.processor.ts +++ b/server/src/modules/image-optimize/image-optimize.processor.ts @@ -8,7 +8,7 @@ import fs, { existsSync, mkdirSync } from 'fs'; import { ConfigService } from '@nestjs/config'; import { randomUUID } from 'crypto'; -@Processor('image') +@Processor('optimize') export class ImageOptimizeProcessor { constructor( @InjectRepository(AssetEntity) private assetRepository: Repository, @@ -16,8 +16,8 @@ export class ImageOptimizeProcessor { private configService: ConfigService, ) {} - @Process('optimize') - async handleOptimization(job: Job) { + @Process('resize-image') + async resizeUploadedImage(job: Job) { const { savedAsset }: { savedAsset: AssetEntity } = job.data; const basePath = this.configService.get('UPLOAD_LOCATION'); @@ -58,4 +58,46 @@ export class ImageOptimizeProcessor { return 'ok'; } + + @Process('resize-video') + async resizeUploadedVideo(job: Job) { + const { savedAsset }: { savedAsset: AssetEntity } = job.data; + + const basePath = this.configService.get('UPLOAD_LOCATION'); + const resizePath = savedAsset.originalPath.replace('/original/', '/thumb/'); + + // Create folder for thumb image if not exist + const resizeDir = `${basePath}/${savedAsset.userId}/thumb/${savedAsset.deviceId}`; + + if (!existsSync(resizeDir)) { + mkdirSync(resizeDir, { recursive: true }); + } + + fs.readFile(savedAsset.originalPath, (err, data) => { + if (err) { + console.error('Error Reading File'); + } + + sharp(data) + .resize(512, 512, { fit: 'outside' }) + .toFile(resizePath, async (err, info) => { + if (err) { + console.error('Error resizing file ', err); + } + + await this.assetRepository.update(savedAsset, { resizePath: resizePath }); + + // Send file to object detection after resizing + // const detectionJob = await this.machineLearningQueue.add( + // 'object-detection', + // { + // resizePath, + // }, + // { jobId: randomUUID() }, + // ); + }); + }); + + return 'ok'; + } } diff --git a/server/src/modules/image-optimize/image-optimize.service.ts b/server/src/modules/image-optimize/image-optimize.service.ts index 3425980baf..4824e9ffd6 100644 --- a/server/src/modules/image-optimize/image-optimize.service.ts +++ b/server/src/modules/image-optimize/image-optimize.service.ts @@ -7,12 +7,26 @@ import { AssetEntity } from '../../api-v1/asset/entities/asset.entity'; import { AuthUserDto } from '../../decorators/auth-user.decorator'; @Injectable() -export class ImageOptimizeService { - constructor(@InjectQueue('image') private imageQueue: Queue) {} +export class AssetOptimizeService { + constructor(@InjectQueue('optimize') private optimizeQueue: Queue) {} public async resizeImage(savedAsset: AssetEntity) { - const job = await this.imageQueue.add( - 'optimize', + const job = await this.optimizeQueue.add( + 'resize-image', + { + savedAsset, + }, + { jobId: randomUUID() }, + ); + + return { + jobId: job.id, + }; + } + + public async resizeVideo(savedAsset: AssetEntity) { + const job = await this.optimizeQueue.add( + 'resize-video', { savedAsset, },