setup image resize processor

This commit is contained in:
Alex Tran 2022-02-05 01:34:23 -06:00
parent 0020c7be94
commit 168676075f
8 changed files with 80 additions and 21 deletions

View file

@ -1,5 +1,5 @@
dev: dev:
docker-compose -f ./server/docker-compose.yml up docker-compose -f ./server/docker-compose.yml up
update: dev-update:
docker-compose -f ./server/docker-compose.yml up --build -V docker-compose -f ./server/docker-compose.yml up --build -V

View file

@ -35,7 +35,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
void getBackupInfo() async { void getBackupInfo() async {
_updateServerInfo(); _updateServerInfo();
List<AssetPathEntity> list = await PhotoManager.getAssetPathList(onlyAll: true, type: RequestType.image); List<AssetPathEntity> list = await PhotoManager.getAssetPathList(onlyAll: true, type: RequestType.common);
if (list.isEmpty) { if (list.isEmpty) {
debugPrint("No Asset On Device"); debugPrint("No Asset On Device");
@ -59,7 +59,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
// await PhotoManager.presentLimited(); // await PhotoManager.presentLimited();
// Gather assets info // Gather assets info
List<AssetPathEntity> list = List<AssetPathEntity> list =
await PhotoManager.getAssetPathList(hasAll: true, onlyAll: true, type: RequestType.image); await PhotoManager.getAssetPathList(hasAll: true, onlyAll: true, type: RequestType.common);
if (list.isEmpty) { if (list.isEmpty) {
debugPrint("No Asset On Device - Abort Backup Process"); debugPrint("No Asset On Device - Abort Backup Process");

View file

@ -12,7 +12,6 @@ import 'package:immich_mobile/utils/files_helper.dart';
import 'package:photo_manager/photo_manager.dart'; import 'package:photo_manager/photo_manager.dart';
import 'package:http_parser/http_parser.dart'; import 'package:http_parser/http_parser.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:exif/exif.dart';
class BackupService { class BackupService {
final NetworkService _networkService = NetworkService(); final NetworkService _networkService = NetworkService();

View file

@ -22,7 +22,7 @@ import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator';
import { CreateAssetDto } from './dto/create-asset.dto'; import { CreateAssetDto } from './dto/create-asset.dto';
import { createReadStream } from 'fs'; import { createReadStream } from 'fs';
import { ServeFileDto } from './dto/serve-file.dto'; 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 { AssetType } from './entities/asset.entity';
import { GetAllAssetQueryDto } from './dto/get-all-asset-query.dto'; 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 { export class AssetController {
constructor( constructor(
private readonly assetService: AssetService, private readonly assetService: AssetService,
private readonly imageOptimizeService: ImageOptimizeService, private readonly assetOptimizeService: AssetOptimizeService,
) {} ) {}
@Post('upload') @Post('upload')
@ -45,7 +45,11 @@ export class AssetController {
const savedAsset = await this.assetService.createUserAsset(authUser, assetInfo, file.path, file.mimetype); const savedAsset = await this.assetService.createUserAsset(authUser, assetInfo, file.path, file.mimetype);
if (savedAsset && savedAsset.type == AssetType.IMAGE) { 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);
} }
}); });

View file

@ -4,13 +4,13 @@ import { AssetController } from './asset.controller';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { AssetEntity } from './entities/asset.entity'; import { AssetEntity } from './entities/asset.entity';
import { ImageOptimizeModule } from '../../modules/image-optimize/image-optimize.module'; 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'; import { BullModule } from '@nestjs/bull';
@Module({ @Module({
imports: [ imports: [
BullModule.registerQueue({ BullModule.registerQueue({
name: 'image', name: 'optimize',
defaultJobOptions: { defaultJobOptions: {
attempts: 3, attempts: 3,
removeOnComplete: true, removeOnComplete: true,
@ -29,7 +29,7 @@ import { BullModule } from '@nestjs/bull';
ImageOptimizeModule, ImageOptimizeModule,
], ],
controllers: [AssetController], controllers: [AssetController],
providers: [AssetService, ImageOptimizeService], providers: [AssetService, AssetOptimizeService],
exports: [], exports: [],
}) })
export class AssetModule {} export class AssetModule {}

View file

@ -6,13 +6,13 @@ import { AssetModule } from '../../api-v1/asset/asset.module';
import { AssetService } from '../../api-v1/asset/asset.service'; import { AssetService } from '../../api-v1/asset/asset.service';
import { AssetEntity } from '../../api-v1/asset/entities/asset.entity'; import { AssetEntity } from '../../api-v1/asset/entities/asset.entity';
import { ImageOptimizeProcessor } from './image-optimize.processor'; import { ImageOptimizeProcessor } from './image-optimize.processor';
import { ImageOptimizeService } from './image-optimize.service'; import { AssetOptimizeService } from './image-optimize.service';
import { MachineLearningProcessor } from './machine-learning.processor'; import { MachineLearningProcessor } from './machine-learning.processor';
@Module({ @Module({
imports: [ imports: [
BullModule.registerQueue({ BullModule.registerQueue({
name: 'image', name: 'optimize',
defaultJobOptions: { defaultJobOptions: {
attempts: 3, attempts: 3,
removeOnComplete: true, removeOnComplete: true,
@ -30,7 +30,7 @@ import { MachineLearningProcessor } from './machine-learning.processor';
TypeOrmModule.forFeature([AssetEntity]), TypeOrmModule.forFeature([AssetEntity]),
], ],
providers: [ImageOptimizeService, ImageOptimizeProcessor, MachineLearningProcessor], providers: [AssetOptimizeService, ImageOptimizeProcessor, MachineLearningProcessor],
exports: [ImageOptimizeService], exports: [AssetOptimizeService],
}) })
export class ImageOptimizeModule {} export class ImageOptimizeModule {}

View file

@ -8,7 +8,7 @@ import fs, { existsSync, mkdirSync } from 'fs';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { randomUUID } from 'crypto'; import { randomUUID } from 'crypto';
@Processor('image') @Processor('optimize')
export class ImageOptimizeProcessor { export class ImageOptimizeProcessor {
constructor( constructor(
@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>, @InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>,
@ -16,8 +16,8 @@ export class ImageOptimizeProcessor {
private configService: ConfigService, private configService: ConfigService,
) {} ) {}
@Process('optimize') @Process('resize-image')
async handleOptimization(job: Job) { async resizeUploadedImage(job: Job) {
const { savedAsset }: { savedAsset: AssetEntity } = job.data; const { savedAsset }: { savedAsset: AssetEntity } = job.data;
const basePath = this.configService.get('UPLOAD_LOCATION'); const basePath = this.configService.get('UPLOAD_LOCATION');
@ -58,4 +58,46 @@ export class ImageOptimizeProcessor {
return 'ok'; 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';
}
} }

View file

@ -7,12 +7,26 @@ import { AssetEntity } from '../../api-v1/asset/entities/asset.entity';
import { AuthUserDto } from '../../decorators/auth-user.decorator'; import { AuthUserDto } from '../../decorators/auth-user.decorator';
@Injectable() @Injectable()
export class ImageOptimizeService { export class AssetOptimizeService {
constructor(@InjectQueue('image') private imageQueue: Queue) {} constructor(@InjectQueue('optimize') private optimizeQueue: Queue) {}
public async resizeImage(savedAsset: AssetEntity) { public async resizeImage(savedAsset: AssetEntity) {
const job = await this.imageQueue.add( const job = await this.optimizeQueue.add(
'optimize', 'resize-image',
{
savedAsset,
},
{ jobId: randomUUID() },
);
return {
jobId: job.id,
};
}
public async resizeVideo(savedAsset: AssetEntity) {
const job = await this.optimizeQueue.add(
'resize-video',
{ {
savedAsset, savedAsset,
}, },