Fullstack alchemy with nextjs and ffmpeg: convert video to audio version

RMAG news

Let’s build a simple nextjs app which will convert video to audio files and downloads it.
No extra backend, VMs or server, everything running on nextjs and can be easily deployed on vercel.

Background Story of our main elements

Nextjs – A backend (yes, backend) framework developed by vercel which ships react (kinda not exactly) to the browser with so many rendering strategies, some good, some more confusing than F1’s ferrari team strategy. Summing up, really cool tool if you want to move fast and ship production grade full-stack apps. It comes with in-built support for creating apis which runs on server environment for your client without the extra effort for set backend deployment or those docker containers or lambdas; they somehow mimic ec2 behaviour though.
FFMPEG – Beast tool, probably one of the biggest gigachad stuff available on the internet. Officiaily they go with – A complete, cross-platform solution to record, convert and stream audio and video.

Let’s begin; Try to follow along

Create a new nextjs app by

npx createnextapp@latest

you can opt for customisation

What is your project named? myapp
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the default import alias (@/*)? No / Yes
What import alias would you like configured? @/*

For using ffmpeg inside our app, we will use fluent-ffmpeg which makes it easier to create a ffmpeg command in a nodejs like module. They say this on their page
This library abstracts the complex command-line usage of ffmpeg into a fluent, easy to use node.js module.
https://www.npmjs.com/package/fluent-ffmpeg

We will also be using multer for this for uploading a file. You can download multer from
https://www.npmjs.com/package/multer

Create an api folder inside app directory and create a folder named convertAudio.ts. Paste the following code there

import multer from multer;
import { exec } from child_process;
import { promises as fs } from fs;

const upload = multer({ dest: /tmp });

export const config = {
api: {
bodyParser: false,
},
};

export default async (req, res) => {
if (req.method === POST) {
const convertAudio = async (filePath: any, outputFormat: any) => {
return new Promise((resolve, reject) => {
const outputPath = `/tmp/output.${outputFormat}`;
exec(`ffmpeg -i ${filePath} ${outputPath}`, (error) => {
if (error) {
reject(error);
} else {
resolve(outputPath);
}
});
});
};

const fileHandlingMiddleware = upload.single(audioFile);

fileHandlingMiddleware(req, res, async (err) => {
if (err) {
return res.status(500).json({ error: Error uploading file. });
}

try {
const convertedFilePath = await convertAudio(req.file.path, mp3); // Convert to mp3 for this example
const fileBuffer = await fs.readFile(convertedFilePath);

res.setHeader(
Content-Disposition,
attachment; filename=converted.mp3
);
res.setHeader(Content-Type, audio/mp3);
res.end(fileBuffer);

// Cleanup temp files
await fs.unlink(req.file.path);
await fs.unlink(convertedFilePath);
} catch (error) {
res
.status(500)
.json({ error: Error converting audio. Some problem occured });
}
});
} else {
res.status(405).json({ error: Only POST requests are allowed. });
}
};

Let’s understand this code briefly

exec(`ffmpeg -i ${filePath} ${outputPath}`, (error) => {
if (error) {
reject(error);
} else {
resolve(outputPath);
}
});

This will create a ffmpeg command taking original file path and an output path to store the audio file.

res.setHeader(
Content-Disposition,
attachment; filename=converted.mp3
);
res.setHeader(Content-Type, audio/mp3);
res.end(fileBuffer);

This set necessary headers (“Content-Disposition”,) to the response object to tell the browser to directly download the file with the name (“attachment; filename={file_name}”).

That’s it, running your nextjs app will make this api available at /api/convertAudio for your nextjs app which you can directly use with a post request.

Note: This will only work for form-type multipart/form-data since we are using multer.

No need to setup an environment, directly deploy it to vercel and it will work fine.

That’s one the best part of nextjs is to remove the line or atleast blur between frontend and backend.

Thanks for reading 😄

Leave a Reply

Your email address will not be published. Required fields are marked *