started video thumbnails

This commit is contained in:
subnub
2024-06-29 13:39:11 -04:00
parent 576d92f724
commit e3970ad394
7 changed files with 387 additions and 54 deletions
@@ -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;
+13 -25
View File
@@ -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
View File
@@ -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",