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 create-next-app@latest
- you can opt for customisation
What is your project named? my-app
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 😄
Discover more from Coursity
Subscribe to get the latest posts sent to your email.