import Express from "express"; import busboy from "connect-busboy"; import path from "path"; import fs from "node:fs"; import { exec } from "node:child_process"; import util from "node:util"; import * as Minio from "minio"; //#region src/index.ts const execPromise = util.promisify(exec); process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0"; const minioClient = new Minio.Client({ endPoint: "garage-ikea.jdf2.org.local", region: "garage", useSSL: false, accessKey: "GK35dcc0e32a7954e2ee725582", secretKey: "0017fab8d149ee7215e1b3cecf6c3b13eb8acb8132db4b4042dacdf2801ab48f" }); let currentlyExecFfmpeg = false; const workingDir = "/opt/prod/storage"; const app = Express(); app.use(busboy()); app.use(Express.json()); app.post("/uploadVideo", async (req, res) => { try { console.log("Starting upload"); const videoId = req.query.videoId; req.busboy.on("file", (fieldname, uploadingFile, fileInfo) => { if (currentlyExecFfmpeg) { console.log("Waiting"); res.send({ status: "wait", statusMessage: "FFmpeg is currently processing another file. Please wait." }); res.end(); return; } console.log(`Saving ${fileInfo.filename} as ${videoId}`); const videoExt = fileInfo.filename.split(".").at(-1); var targetPath = path.join(`${workingDir}/uploadsPart1`, `${videoId}.${videoExt}`); const formattedPath = `${workingDir}/uploadsPart2/${videoId}-formatted.mp4`; const fileStream = fs.createWriteStream(targetPath); uploadingFile.pipe(fileStream); fileStream.on("close", () => { console.log(`Completed upload ${fileInfo.filename}`); const ffmpegCommand = `ffmpeg -y -loglevel error -i "${targetPath}" -c:v libx264 -crf 23 -preset medium -movflags +faststart -c:a aac -b:a 128k ${formattedPath}`; currentlyExecFfmpeg = true; execPromise(ffmpegCommand).then(async ({ stdout, stderr }) => { if (stderr && stderr.length > 0) console.log("FFmpeg stderr:", stderr); await minioClient.fPutObject("videos-garage", videoId, formattedPath); fs.unlinkSync(formattedPath); console.log(await minioClient.presignedGetObject("videos-garage", videoId, 24 * 60 * 60)); }).catch((error) => { console.log("FFmpeg caught error:", error); }).finally(() => { console.log(`Completed processing ${fileInfo.filename}`); fs.unlinkSync(targetPath); currentlyExecFfmpeg = false; }); res.send({ status: "good", statusMessage: "Upload part 1 complete" }); }); }); req.pipe(req.busboy); } catch (err) { res.status(500).send(err); } }); app.listen(3001); //#endregion