Skip to content

Commit

Permalink
MYR-1340: added upload type
Browse files Browse the repository at this point in the history
  • Loading branch information
irmannmal committed Dec 14, 2021
1 parent 7fcb217 commit 73f607b
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 98 deletions.
42 changes: 19 additions & 23 deletions src/controllers/storage.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
import {FCSService} from '../services/fcs.service';
import {FILE_UPLOAD_SERVICE} from '../keys';
import {FileUploadHandler} from '../types';
import {unlinkSync} from 'fs';
import {config} from '../config';
import {UploadType} from '../enums';

export class StorageController {
constructor(
Expand Down Expand Up @@ -45,40 +45,36 @@ export class StorageController {
this.handler(request, response, (err: unknown) => {
if (err) reject(err);
else {
resolve(this.getFilesAndFields(userId, kind, request));
const targetDir = `users/${userId}/${kind}`;
resolve(this.getFilesAndFields(targetDir, request));
}
});
});
}

/**
* Get files and fields for the request
* @param request - Http request
*/
private async getFilesAndFields(
userId: string,
kind: string,
request: Request,
) {
private async getFilesAndFields(targetDir: string, request: Request) {
const uploadedFiles = request.files;
const mapper = async (f: globalThis.Express.Multer.File) => {
let downloadURL: String = '';
const mapper = async (file: globalThis.Express.Multer.File) => {
let fileURL: String = '';
if (config.FIREBAE_STORAGE_BUCKET) {
if (f.mimetype.toLowerCase().startsWith('image')) {
downloadURL = await this.fcsService.uploadImage(userId, kind, f.path);
} else {
downloadURL = await this.fcsService.uploadVideo(userId, kind, f.path);
let uploadType = UploadType.IMAGE;
if (file.mimetype.toLowerCase().startsWith('video')) {
uploadType = UploadType.VIDEO;
}

unlinkSync(f.path);
fileURL = await this.fcsService.upload(
uploadType,
targetDir,
file.path,
);
}

return {
fieldname: f.fieldname,
originalname: f.originalname,
mimetype: f.mimetype,
size: f.size,
url: downloadURL,
fieldname: file.fieldname,
originalname: file.originalname,
mimetype: file.mimetype,
size: file.size,
url: fileURL,
};
};
let files: object[] = [];
Expand Down
1 change: 1 addition & 0 deletions src/enums/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from './reference-type.enum';
export * from './report-type.enum';
export * from './account-setting-type.enum';
export * from './post-status-type.enum';
export * from './upload-type.enum';
4 changes: 4 additions & 0 deletions src/enums/upload-type.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum UploadType {
IMAGE = 'image',
VIDEO = 'video',
}
148 changes: 73 additions & 75 deletions src/services/fcs.service.ts
Original file line number Diff line number Diff line change
@@ -1,110 +1,108 @@
import {BindingScope, injectable} from '@loopback/core';
import * as firebaseAdmin from 'firebase-admin';
import sharp from 'sharp';
import ffmpegInstaller from '@ffmpeg-installer/ffmpeg';
import ffmpeg from 'fluent-ffmpeg';
import fs from 'fs';
import os from 'os';
import path from 'path';
import {unlinkSync} from 'fs';
import sharp from 'sharp';
import {UploadType} from '../enums';

ffmpeg.setFfmpegPath(ffmpegInstaller.path);

@injectable({scope: BindingScope.TRANSIENT})
export class FCSService {
constructor() {}

async uploadImage(
userId: string,
kind: string,
async upload(
type: UploadType,
targetDir: string,
filePath: string,
): Promise<String> {
const parsed = path.parse(filePath);
const format = 'jpg';
const mutations = [
const bucket = firebaseAdmin.storage().bucket();
const tempDir = os.tmpdir();
const baseName = path.basename(filePath);
let format = 'jpg';
let mutations = [
{
type: 'thumbnail',
suffix: '_thumbnail',
width: 200,
height: 200,
},
{
type: 'small',
suffix: '_small',
width: 400,
height: 400,
},
{
type: 'medium',
suffix: '_medium',
width: 600,
height: 600,
},
{
type: 'origin',
suffix: '',
width: 0,
},
];

const bucket = firebaseAdmin.storage().bucket();
const options = {resumable: false, metadata: {contentType: 'image/jpg'}};

const buffer = await sharp(filePath).toBuffer();
if (type === UploadType.VIDEO) {
format = 'mp4';
mutations = [
{
type: 'origin',
suffix: '',
width: 0,
},
];
}

let result = '';
for (const mutation of mutations) {
const file = bucket.file(
`${userId}/${kind}/${parsed.name}_${mutation.type}.${format}`,
);

const resized = await sharp(buffer)
.resize({width: mutation.width})
.toFormat(format)
.toBuffer({resolveWithObject: true});

await file.save(resized.data, options);
await file.makePublic();
const formattedFilePath = `${tempDir}/${baseName}${mutation.suffix}_formatted.${format}`;
const uploadFilePath = `${targetDir}/${baseName}${mutation.suffix}.${format}`;

if (mutation.type === 'origin') {
if (type === UploadType.IMAGE) {
await sharp(filePath)
.toFormat(sharp.format.jpg)
.toFile(formattedFilePath);
} else {
await new Promise((resolve, reject) => {
ffmpeg(filePath)
.videoCodec('libx264')
.audioCodec('libmp3lame')
.format(format)
.on('error', err => {
reject(err);
})
.on('end', () => {
resolve(formattedFilePath);
})
.saveToFile(formattedFilePath);
});
}
} else {
if (type === UploadType.IMAGE) {
await sharp(filePath)
.resize({width: mutation.width})
.toFormat(sharp.format.jpg)
.toFile(formattedFilePath);
}
}

const [file] = await bucket.upload(formattedFilePath, {
resumable: false,
public: true,
destination: uploadFilePath,
});
result = file.publicUrl();

fs.unlinkSync(formattedFilePath);
}

const file = bucket.file(`${userId}/${kind}/${parsed.name}.${format}`);
const resized = await sharp(buffer)
.toFormat(format)
.toBuffer({resolveWithObject: true});

await file.save(resized.data, options);

await file.makePublic();

return file.publicUrl();
}

async uploadVideo(
userId: string,
kind: string,
filePath: string,
): Promise<String> {
const parsed = path.parse(filePath);
const format = 'mp4';

const bucket = firebaseAdmin.storage().bucket();
const options = {
destination: `${userId}/${kind}/${parsed.name}.${format}`,
resumable: false,
metadata: {contentType: 'video/mp4'},
};

const convertedFilePath = `/tmp/convert_${parsed.name}.${format}`;

const result: string = await new Promise((resolve, reject) => {
ffmpeg(filePath)
.videoCodec('libx264')
.audioCodec('libmp3lame')
.format('mp4')
.on('error', err => {
reject(err);
})
.on('end', () => {
resolve(convertedFilePath);
})
.saveToFile(convertedFilePath);
});

const [file] = await bucket.upload(result, options);

unlinkSync(result);

await file.makePublic();
fs.unlinkSync(filePath);

return file.publicUrl();
return result;
}
}

0 comments on commit 73f607b

Please sign in to comment.