Search code examples
node.jsreactjsmulterlarge-filescloudinary

Uploading large video file with nodejs, multer and cloudinary


My code works very well for small videos up to 50MB however when videos weight more than 50MB, it uploads the video but I dont get any cloudinary url hence the video is not loading in my frontend part . I am using nodejs and multer in my backend with cloudinary as storage and react as my frontend. Any suggestion ?

Cloudinary config

require("dotenv").config();
const cloudinary = require("cloudinary");
cloudinary.config({
  cloud_name: process.env.CLOUD_NAME ,
  api_key: process.env.API_KEY ,
  api_secret: process.env.API_SECRET ,
});
exports.uploads = (file) => {
  return new Promise((resolve) => {
    cloudinary.uploader.upload(
      file,
      (result) => {
        resolve({ url: result.url, id: result.public_id });
      },
      { resource_type: "auto" }
    );
  });
};

Video controller

const Video = require("../models/videoModel"),
  cloud = require("../config/cloudinaryConfig");
module.exports = {
  // Create action for a new video
  create: (req, res, next) => {
    // First check if the file exists in the Database
    let test = {
      name: req.files[0].originalname,
      url: req.files[0].path,
      id: "",
    };
    console.log(req.files[0].originalname);
    Video.find({ name: test.name }, (err, cb) => {
      if (err) {
        res.json({
          error: true,
          message: `There was a problem uploading the video because: ${err.message}`,
        });
      } else {
        let file = {
          name: req.files[0].originalname,
          url: req.files[0].path,
          id: "",
        };
        cloud
          .uploads(file.url)
          .then((result) => {
            Video.create({
              name: req.files[0].originalname,
              url: result.url,
              id: result.id,
            });
          })
          .then((result) => {
            res.json({
              success: true,
              data: result,
            });
          })
          .catch((err) => {
            res.json({
              error: true,
              message: err.message,
            });
          });
      }
    });
  },
};

Multer config

const multer = require("multer"),
  path = require("path");
//multer.diskStorage() creates a storage space for storing files.
const imageStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
      cb(null, path.join(__dirname, "../files"));
    } else {
      cb({ message: "This file is not an image file" }, false);
    }
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname);
  },
});

const videoStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    if (file.mimetype === "video/mp4") {
      cb(null, path.join(__dirname, "../files"));
    } else {
      cb({ message: "This file is not in video format." }, false);
    }
  },
  filename: (req, file, cb) => {
    cb(null, file.originalname);
  },
});
module.exports = {
  imageUpload: multer({ storage: imageStorage }),
  videoUpload: multer({ storage: videoStorage }),
};

Solution

  • When uploading files to Cloudinary, the maximum size of the request body can be 100MB. Any request that is larger than this would receive the 413 error you are seeing. To upload files larger than 100MB, these need to be sent in chunks.

    Since you are using the Cloudinary NodeJS SDK, you can update your code to use the upload_large method for your uploads instead of the regular upload method.

    The upload_large method should be used for all files >100MB as it splits the file and uploads it in parts automatically for you. That said, you can also use this uplaod_large method for all files, even if they are small in filesize and those would work as well.

    It takes the exact same parameters as the upload method and also optionally accepts a chunk_size (default 20MB).