import crypto from "crypto"; import sharp from "sharp"; import { FileInterface } from "../../../models/file-model"; import { UserInterface } from "../../../models/user-model"; import fs from "fs"; import { v4 as uuidv4 } from "uuid"; import env from "../../../enviroment/env"; import ffmpeg from "fluent-ffmpeg"; import { S3Actions } from "../actions/S3-actions"; import { FilesystemActions } from "../actions/file-system-actions"; import { createGenericParams } from "./storageHelper"; import { getStorageActions } from "../actions/helper-actions"; import { getFSStoragePath } from "../../../utils/getFSStoragePath"; import { getFileDB, getThumbnailDB } from "../../../db/dbFactory"; const storageActions = getStorageActions(); const fileDB = getFileDB(); const thumbnailDB = getThumbnailDB(); const tempCreateVideoThumbnail = ( file: FileInterface, filename: string, user: UserInterface ) => { return new Promise((resolve, reject) => { const password = user.getEncryptionKey(); let CIPHER_KEY = crypto.createHash("sha256").update(password!).digest(); const thumbnailFilename = uuidv4(); const readStreamParams = createGenericParams({ filePath: file.metadata.filePath, Key: file.metadata.s3ID, }); const readStream = storageActions.createReadStream(readStreamParams); const { writeStream, emitter } = storageActions.createWriteStream( readStreamParams, readStream, thumbnailFilename ); const tempDirectory = env.tempDirectory + thumbnailFilename; const tempWriteStream = fs.createWriteStream(tempDirectory); const decipher = crypto.createDecipheriv( "aes256", CIPHER_KEY, file.metadata.IV ); const thumbnailIV = crypto.randomBytes(16); const thumbnailCipher = crypto.createCipheriv( "aes256", CIPHER_KEY, thumbnailIV ); const decryptedReadStream = readStream.pipe(decipher); decryptedReadStream.pipe(tempWriteStream, { end: true }); if (emitter) { emitter.on("finish", async () => { await handleFinish(); }); } const handleFinish = async () => { const thumbnailModel = await thumbnailDB.createThumbnail({ name: filename, owner: user._id.toString(), IV: thumbnailIV, path: getFSStoragePath() + thumbnailFilename, s3ID: thumbnailFilename, }); if (!file._id) { return reject(); } const updatedFile = await fileDB.setVideoThumbnail( file._id.toString(), user._id.toString(), thumbnailModel._id.toString() ); if (!updatedFile) return reject(); fs.unlink(tempDirectory, (err) => { resolve(updatedFile); }); }; const attemptToRemoveTempDirectory = () => { return new Promise((resolve, reject) => { fs.unlink(tempDirectory, (err) => { resolve(!err); }); }); }; tempWriteStream.on("finish", () => { ffmpeg(tempDirectory, { timeout: 60, }) .seek(1) .format("image2pipe") .outputOptions([ "-f image2pipe", "-vframes 1", "-vf scale='if(gt(iw,ih),600,-1):if(gt(ih,iw),300,-1)'", ]) .on("start", () => {}) .on("end", async () => { if (!emitter) { await handleFinish(); } }) .on("error", (err, _, stderr) => { console.log("error", err, stderr); attemptToRemoveTempDirectory(); resolve(file); }) .pipe(thumbnailCipher) .pipe(writeStream, { end: true }); }); }); }; export default tempCreateVideoThumbnail;