├── .dockerignore ├── .gitignore ├── docker-compose.yml ├── package.json ├── Dockerfile ├── video.js └── server.js /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | temp 4 | .DS_Store -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | nodejs-video-compression: 3 | build: . 4 | ports: 5 | - "5000:5000" 6 | volumes: 7 | - ./temp:/usr/src/app/temp 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-video-compression", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cors": "^2.8.5", 14 | "express": "^4.18.1", 15 | "express-fileupload": "^1.4.0", 16 | "fluent-ffmpeg": "^2.1.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | # Create app directory 3 | WORKDIR /usr/src/app 4 | 5 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 6 | # where available (npm@5+) 7 | COPY package*.json ./ 8 | 9 | # Install FFmpeg 10 | RUN apt-get update 11 | RUN apt-get install ffmpeg -y 12 | 13 | # Install app dependencies 14 | RUN npm install 15 | # If you are building your code for production 16 | # RUN npm ci --only=production 17 | # Bundle app source 18 | 19 | # Copy app source to /usr/src/app 20 | COPY . . 21 | 22 | # Run the app 23 | EXPOSE 5000 24 | CMD [ "npm", "run", "start" ] -------------------------------------------------------------------------------- /video.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const ffmpeg = require("fluent-ffmpeg"); 3 | 4 | process.on("message", (payload) => { 5 | const { tempFilePath, name } = payload; 6 | 7 | const endProcess = (endPayload) => { 8 | const { statusCode, text } = endPayload; 9 | // Remove temp file 10 | fs.unlink(tempFilePath, (err) => { 11 | if (err) { 12 | process.send({ statusCode: 500, text: err.message }); 13 | } 14 | }); 15 | // Format response so it fits the api response 16 | process.send({ statusCode, text }); 17 | // End process 18 | process.exit(); 19 | }; 20 | 21 | // Process video and send back the result 22 | ffmpeg(tempFilePath) 23 | .fps(30) 24 | .addOptions(["-crf 28"]) 25 | .on("end", () => { 26 | endProcess({ statusCode: 200, text: "Success" }); 27 | }) 28 | .on("error", (err) => { 29 | endProcess({ statusCode: 500, text: err.message }); 30 | }) 31 | .save(`./temp/${name}`); 32 | }); 33 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | const { fork } = require("child_process"); 4 | const fileUpload = require("express-fileupload"); 5 | 6 | // Create a new express application instance 7 | const PORT = 5000; 8 | const app = express(); 9 | 10 | // Middleware 11 | app.use(cors()); 12 | app.use(express.json()); 13 | app.use( 14 | fileUpload({ 15 | tempFileDir: "temp", 16 | useTempFiles: true, 17 | }) 18 | ); 19 | 20 | // Routes 21 | app.get("/", (req, res) => { 22 | res.send("Hello World!"); 23 | }); 24 | 25 | app.post("/compress-video", (req, res) => { 26 | const video = req.files.video; 27 | 28 | // When file is uploaded it is stored in temp file 29 | // this is made possible by express-fileupload 30 | const tempFilePath = video.tempFilePath; 31 | 32 | if (video && tempFilePath) { 33 | // Create a new child process 34 | const child = fork("video.js"); 35 | // Send message to child process 36 | child.send({ tempFilePath, name: video.name }); 37 | // Listen for message from child process 38 | child.on("message", (message) => { 39 | const { statusCode, text } = message; 40 | res.status(statusCode).send(text); 41 | }); 42 | } else { 43 | res.status(400).send("No file uploaded"); 44 | } 45 | }); 46 | 47 | // Start the server 48 | app.listen(PORT, () => { 49 | console.log(`Server started on http://localhost:${PORT}`); 50 | }); 51 | --------------------------------------------------------------------------------