started video thumbnails
This commit is contained in:
@@ -31,6 +31,7 @@ import ForbiddenError from "../../utils/ForbiddenError";
|
||||
import { ObjectId } from "mongodb";
|
||||
import FolderService from "../FolderService";
|
||||
import MongoFileService from "../FileService";
|
||||
import createVideoThumbnailFS from "./utils/createVideoThumbnailFS";
|
||||
|
||||
const dbUtilsFile = new DbUtilFile();
|
||||
const dbUtilsFolder = new DbUtilFolder();
|
||||
@@ -107,8 +108,6 @@ class FileSystemService implements ChunkInterface {
|
||||
const date = new Date();
|
||||
const encryptedFileSize = await getFileSize(metadata.filePath);
|
||||
|
||||
console.log("filtnamed", filename);
|
||||
|
||||
const currentFile = new File({
|
||||
filename,
|
||||
uploadDate: date.toISOString(),
|
||||
@@ -120,11 +119,19 @@ class FileSystemService implements ChunkInterface {
|
||||
|
||||
await addToStoageSize(user, size, personalFile);
|
||||
|
||||
console.log("current file", currentFile);
|
||||
|
||||
const imageCheck = imageChecker(currentFile.filename);
|
||||
const videoCheck = videoChecker(currentFile.filename);
|
||||
|
||||
if (currentFile.length < 15728640 && imageCheck) {
|
||||
if (videoCheck) {
|
||||
console.log("is vidoe");
|
||||
const updatedFile = await createVideoThumbnailFS(
|
||||
currentFile,
|
||||
filename,
|
||||
user
|
||||
);
|
||||
|
||||
return updatedFile;
|
||||
} else if (currentFile.length < 15728640 && imageCheck) {
|
||||
const updatedFile = await createThumbnailAny(currentFile, filename, user);
|
||||
|
||||
return updatedFile;
|
||||
|
||||
@@ -8,6 +8,7 @@ import fs from "fs";
|
||||
import uuid from "uuid";
|
||||
import env from "../../../enviroment/env";
|
||||
import { ObjectId } from "mongodb";
|
||||
import File from "../../../models/file";
|
||||
|
||||
const conn = mongoose.connection;
|
||||
|
||||
@@ -82,32 +83,27 @@ const createThumbnailFS = (
|
||||
if (!file._id) {
|
||||
return reject();
|
||||
}
|
||||
const getUpdatedFile = await conn.db
|
||||
.collection("fs.files")
|
||||
.findOneAndUpdate(
|
||||
{ _id: new ObjectId(file._id) },
|
||||
{
|
||||
$set: {
|
||||
"metadata.hasThumbnail": true,
|
||||
"metadata.thumbnailID": thumbnailModel._id,
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!getUpdatedFile) {
|
||||
const updateFileResponse = await File.updateOne(
|
||||
{ _id: new ObjectId(file._id), "metadata.owner": user._id },
|
||||
{
|
||||
$set: {
|
||||
"metadata.hasThumbnail": true,
|
||||
"metadata.thumbnailID": thumbnailModel._id,
|
||||
},
|
||||
}
|
||||
);
|
||||
if (updateFileResponse.modifiedCount === 0) {
|
||||
return reject();
|
||||
}
|
||||
let updatedFile: FileInterface = getUpdatedFile.value;
|
||||
|
||||
updatedFile = {
|
||||
...updatedFile,
|
||||
metadata: {
|
||||
...updatedFile.metadata,
|
||||
hasThumbnail: true,
|
||||
thumbnailID: thumbnailModel._id,
|
||||
},
|
||||
} as FileInterface;
|
||||
const updatedFile = await File.findById({
|
||||
_id: new ObjectId(file._id),
|
||||
"metadata.owner": user._id,
|
||||
});
|
||||
|
||||
resolve(updatedFile);
|
||||
if (!updatedFile) return reject();
|
||||
|
||||
resolve(updatedFile?.toObject());
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Thumbnail error", e);
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
import mongoose from "../../../db/mongoose";
|
||||
import crypto from "crypto";
|
||||
import Thumbnail from "../../../models/thumbnail";
|
||||
import sharp from "sharp";
|
||||
import { FileInterface } from "../../../models/file";
|
||||
import { UserInterface } from "../../../models/user";
|
||||
import fs from "fs";
|
||||
import uuid from "uuid";
|
||||
import env from "../../../enviroment/env";
|
||||
import { ObjectId } from "mongodb";
|
||||
import File from "../../../models/file";
|
||||
import ffmpeg from "fluent-ffmpeg";
|
||||
import tempCreateVideoThumbnailFS from "./tempCreateVideoThumbnailFS";
|
||||
|
||||
const createVideoThumbnailFS = (
|
||||
file: FileInterface,
|
||||
filename: string,
|
||||
user: UserInterface
|
||||
) => {
|
||||
return new Promise<FileInterface>(async (resolve, reject) => {
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
let CIPHER_KEY = crypto.createHash("sha256").update(password!).digest();
|
||||
|
||||
const thumbnailFilename = uuid.v4();
|
||||
|
||||
const readStream = fs.createReadStream(file.metadata.filePath!);
|
||||
console.log("env", env);
|
||||
const writeStream = fs.createWriteStream(
|
||||
env.fsDirectory + thumbnailFilename
|
||||
);
|
||||
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);
|
||||
|
||||
// const encryptedWriteStream = thumbnailCipher
|
||||
// .pipe(writeStream)
|
||||
// .on("finish", async () => {
|
||||
// const thumbnailModel = new Thumbnail({
|
||||
// name: filename,
|
||||
// owner: user._id,
|
||||
// IV: thumbnailIV,
|
||||
// path: env.fsDirectory + thumbnailFilename,
|
||||
// });
|
||||
|
||||
// await thumbnailModel.save();
|
||||
// if (!file._id) {
|
||||
// return reject();
|
||||
// }
|
||||
// const updateFileResponse = await File.updateOne(
|
||||
// { _id: new ObjectId(file._id), "metadata.owner": user._id },
|
||||
// {
|
||||
// $set: {
|
||||
// "metadata.hasThumbnail": true,
|
||||
// "metadata.thumbnailID": thumbnailModel._id,
|
||||
// },
|
||||
// }
|
||||
// );
|
||||
// if (updateFileResponse.modifiedCount === 0) {
|
||||
// return reject();
|
||||
// }
|
||||
|
||||
// const updatedFile = await File.findById({
|
||||
// _id: new ObjectId(file._id),
|
||||
// "metadata.owner": user._id,
|
||||
// });
|
||||
|
||||
// if (!updatedFile) return reject();
|
||||
|
||||
// resolve(updatedFile?.toObject());
|
||||
// });
|
||||
|
||||
ffmpeg(decryptedReadStream, {
|
||||
timeout: 60,
|
||||
})
|
||||
.seek(1)
|
||||
.format("image2pipe")
|
||||
.outputOptions([
|
||||
"-f image2pipe",
|
||||
"-vframes 1",
|
||||
"-vf scale='if(gt(iw,ih),600,-1):if(gt(ih,iw),600,-1)'",
|
||||
])
|
||||
.on("start", (command) => {
|
||||
/**
|
||||
* log
|
||||
*/
|
||||
})
|
||||
.on("end", async () => {
|
||||
console.log("end");
|
||||
const thumbnailModel = new Thumbnail({
|
||||
name: filename,
|
||||
owner: user._id,
|
||||
IV: thumbnailIV,
|
||||
path: env.fsDirectory + thumbnailFilename,
|
||||
});
|
||||
|
||||
await thumbnailModel.save();
|
||||
if (!file._id) {
|
||||
return reject();
|
||||
}
|
||||
const updateFileResponse = await File.updateOne(
|
||||
{ _id: new ObjectId(file._id), "metadata.owner": user._id },
|
||||
{
|
||||
$set: {
|
||||
"metadata.hasThumbnail": true,
|
||||
"metadata.thumbnailID": thumbnailModel._id,
|
||||
},
|
||||
}
|
||||
);
|
||||
if (updateFileResponse.modifiedCount === 0) {
|
||||
return reject();
|
||||
}
|
||||
|
||||
const updatedFile = await File.findById({
|
||||
_id: new ObjectId(file._id),
|
||||
"metadata.owner": user._id,
|
||||
});
|
||||
|
||||
if (!updatedFile) return reject();
|
||||
|
||||
resolve(updatedFile?.toObject());
|
||||
})
|
||||
.on("error", async (err, _, stderr) => {
|
||||
console.log("thumbnail error attempting temp directory fix");
|
||||
const updatedFile = await tempCreateVideoThumbnailFS(
|
||||
file,
|
||||
filename,
|
||||
user
|
||||
);
|
||||
resolve(updatedFile);
|
||||
/**
|
||||
* log
|
||||
*/
|
||||
})
|
||||
.pipe(thumbnailCipher)
|
||||
.pipe(writeStream, { end: true });
|
||||
|
||||
// ffmpeg()
|
||||
// .input(readStream.pipe(decipher))
|
||||
// .seekInput("00:00:01.00")
|
||||
// .outputFormat("image2")
|
||||
// .pipe(writeStream, { end: true })
|
||||
// .on("end", async () => {
|
||||
// const thumbnailModel = new Thumbnail({
|
||||
// name: filename,
|
||||
// owner: user._id,
|
||||
// IV: thumbnailIV,
|
||||
// path: env.fsDirectory + thumbnailFilename,
|
||||
// });
|
||||
|
||||
// await thumbnailModel.save();
|
||||
// resolve(file);
|
||||
// })
|
||||
// .on("error", (e) => {
|
||||
// console.log("error", e);
|
||||
// reject(e);
|
||||
// });
|
||||
|
||||
// ffmpeg()
|
||||
// .input(readStream.pipe(decipher))
|
||||
// .size("300x?")
|
||||
// .outputOptions("-frames:v 1")
|
||||
// .on("end", async () => {
|
||||
// const thumbnailModel = new Thumbnail({
|
||||
// name: filename,
|
||||
// owner: user._id,
|
||||
// IV: thumbnailIV,
|
||||
// path: env.fsDirectory + thumbnailFilename,
|
||||
// });
|
||||
|
||||
// await thumbnailModel.save();
|
||||
// resolve(file);
|
||||
// })
|
||||
// .output(writeStream);
|
||||
});
|
||||
};
|
||||
|
||||
export default createVideoThumbnailFS;
|
||||
@@ -13,7 +13,6 @@ const getBusboyData = (busboy: any) => {
|
||||
const formData = new Map();
|
||||
|
||||
busboy.on("field", (field: any, val: any) => {
|
||||
console.log("field", field, val, typeof val);
|
||||
// ????? why does it make undefined a string?
|
||||
if (typeof val !== "string" || val !== "undefined") {
|
||||
formData.set(field, val);
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import mongoose from "../../../db/mongoose";
|
||||
import crypto from "crypto";
|
||||
import Thumbnail from "../../../models/thumbnail";
|
||||
import sharp from "sharp";
|
||||
import { FileInterface } from "../../../models/file";
|
||||
import { UserInterface } from "../../../models/user";
|
||||
import fs from "fs";
|
||||
import uuid from "uuid";
|
||||
import env from "../../../enviroment/env";
|
||||
import { ObjectId } from "mongodb";
|
||||
import File from "../../../models/file";
|
||||
import ffmpeg from "fluent-ffmpeg";
|
||||
|
||||
const tempCreateVideoThumbnailFS = (
|
||||
file: FileInterface,
|
||||
filename: string,
|
||||
user: UserInterface
|
||||
) => {
|
||||
return new Promise<FileInterface>(async (resolve, reject) => {
|
||||
const password = user.getEncryptionKey();
|
||||
|
||||
let CIPHER_KEY = crypto.createHash("sha256").update(password!).digest();
|
||||
|
||||
const thumbnailFilename = uuid.v4();
|
||||
|
||||
const readStream = fs.createReadStream(file.metadata.filePath!);
|
||||
console.log("env", env);
|
||||
const writeStream = fs.createWriteStream(
|
||||
env.fsDirectory + thumbnailFilename
|
||||
);
|
||||
const tempWriteStream = fs.createWriteStream(
|
||||
env.fsDirectory + "temp/" + thumbnailFilename
|
||||
);
|
||||
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 });
|
||||
|
||||
ffmpeg(env.fsDirectory + "temp/" + thumbnailFilename, {
|
||||
timeout: 60,
|
||||
})
|
||||
.seek(1)
|
||||
.format("image2pipe")
|
||||
.outputOptions([
|
||||
"-f image2pipe",
|
||||
"-vframes 1",
|
||||
"-vf scale='if(gt(iw,ih),600,-1):if(gt(ih,iw),600,-1)'",
|
||||
])
|
||||
.on("start", (command) => {
|
||||
/**
|
||||
* log
|
||||
*/
|
||||
})
|
||||
.on("end", async () => {
|
||||
console.log("end");
|
||||
const thumbnailModel = new Thumbnail({
|
||||
name: filename,
|
||||
owner: user._id,
|
||||
IV: thumbnailIV,
|
||||
path: env.fsDirectory + thumbnailFilename,
|
||||
});
|
||||
|
||||
await thumbnailModel.save();
|
||||
if (!file._id) {
|
||||
return reject();
|
||||
}
|
||||
const updateFileResponse = await File.updateOne(
|
||||
{ _id: new ObjectId(file._id), "metadata.owner": user._id },
|
||||
{
|
||||
$set: {
|
||||
"metadata.hasThumbnail": true,
|
||||
"metadata.thumbnailID": thumbnailModel._id,
|
||||
},
|
||||
}
|
||||
);
|
||||
if (updateFileResponse.modifiedCount === 0) {
|
||||
return reject();
|
||||
}
|
||||
|
||||
const updatedFile = await File.findById({
|
||||
_id: new ObjectId(file._id),
|
||||
"metadata.owner": user._id,
|
||||
});
|
||||
|
||||
if (!updatedFile) return reject();
|
||||
|
||||
resolve(updatedFile?.toObject());
|
||||
})
|
||||
.on("error", (err, _, stderr) => {
|
||||
console.log("error", err, stderr);
|
||||
resolve(file);
|
||||
/**
|
||||
* log
|
||||
*/
|
||||
})
|
||||
.pipe(thumbnailCipher)
|
||||
.pipe(writeStream, { end: true });
|
||||
|
||||
// ffmpeg()
|
||||
// .input(readStream.pipe(decipher))
|
||||
// .seekInput("00:00:01.00")
|
||||
// .outputFormat("image2")
|
||||
// .pipe(writeStream, { end: true })
|
||||
// .on("end", async () => {
|
||||
// const thumbnailModel = new Thumbnail({
|
||||
// name: filename,
|
||||
// owner: user._id,
|
||||
// IV: thumbnailIV,
|
||||
// path: env.fsDirectory + thumbnailFilename,
|
||||
// });
|
||||
|
||||
// await thumbnailModel.save();
|
||||
// resolve(file);
|
||||
// })
|
||||
// .on("error", (e) => {
|
||||
// console.log("error", e);
|
||||
// reject(e);
|
||||
// });
|
||||
|
||||
// ffmpeg()
|
||||
// .input(readStream.pipe(decipher))
|
||||
// .size("300x?")
|
||||
// .outputOptions("-frames:v 1")
|
||||
// .on("end", async () => {
|
||||
// const thumbnailModel = new Thumbnail({
|
||||
// name: filename,
|
||||
// owner: user._id,
|
||||
// IV: thumbnailIV,
|
||||
// path: env.fsDirectory + thumbnailFilename,
|
||||
// });
|
||||
|
||||
// await thumbnailModel.save();
|
||||
// resolve(file);
|
||||
// })
|
||||
// .output(writeStream);
|
||||
});
|
||||
};
|
||||
|
||||
export default tempCreateVideoThumbnailFS;
|
||||
@@ -1,31 +1,19 @@
|
||||
const imageExtList = [
|
||||
"jpeg",
|
||||
"jpg",
|
||||
"png",
|
||||
"gif",
|
||||
"svg",
|
||||
"tiff",
|
||||
"bmp"
|
||||
]
|
||||
const imageExtList = ["jpeg", "jpg", "png", "gif", "svg", "tiff", "bmp"];
|
||||
|
||||
const imageChecker = (filename: string) => {
|
||||
const imageChecker = (filename: string) => {
|
||||
if (filename.length < 1 || !filename.includes(".")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filename.length < 1 || !filename.includes(".")) {
|
||||
const extSplit = filename.split(".");
|
||||
|
||||
return false;
|
||||
}
|
||||
if (extSplit.length <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const extSplit = filename.split(".");
|
||||
const ext = extSplit[extSplit.length - 1];
|
||||
|
||||
if (extSplit.length <= 1) {
|
||||
|
||||
return false;
|
||||
}
|
||||
return imageExtList.includes(ext.toLowerCase());
|
||||
};
|
||||
|
||||
const ext = extSplit[extSplit.length - 1];
|
||||
|
||||
return imageExtList.includes(ext.toLowerCase());
|
||||
|
||||
}
|
||||
|
||||
export default imageChecker;
|
||||
export default imageChecker;
|
||||
|
||||
+2
-1
@@ -83,7 +83,7 @@
|
||||
"diskusage": "^1.1.3",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.19.2",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"font-awesome": "^4.7.0",
|
||||
"helmet": "^3.21.2",
|
||||
"history": "^4.10.1",
|
||||
@@ -117,6 +117,7 @@
|
||||
"vite": "^5.2.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fluent-ffmpeg": "^2.1.24",
|
||||
"@types/lodash": "^4.17.5",
|
||||
"@typescript-eslint/eslint-plugin": "^2.20.0",
|
||||
"@typescript-eslint/parser": "^2.20.0",
|
||||
|
||||
Reference in New Issue
Block a user