I've created a Next.js TypeScript API to download separate audio_only.mp3 and video_only.mp4 files from a YouTube video. However, I'm encountering a problem where the audio_only.mp3 file is empty, and there's no sound when I try to listen to it. I'm using a MacBook, and I'm wondering if the issue could be related to the Next.js server running on my machine. Can you help me troubleshoot and resolve this audio issue ?
import { NextResponse, NextRequest } from "next/server";
import * as fs from "fs/promises";
import { v4 as uuidv4 } from "uuid";
import { spawn } from "child_process";
import ytdl from "ytdl-core";
export async function POST(request: NextRequest) {
try {
const { type, lang, link } = await request.json();
if (
typeof type !== "string" ||
typeof lang !== "string" ||
typeof link !== "string"
) {
return NextResponse.json(
{
message:
"Invalid input format. Please provide valid strings for 'type', 'lang', and 'link'.",
},
{ status: 400 }
);
}
let filePath;
if (type === "local") {
filePath = link;
// Generate a unique ID for the video
const videoId = uuidv4();
// Create a folder with the unique ID
const folderPath = `videos/${videoId}`;
await fs.mkdir(folderPath);
// Define output file paths within the folder
const audioOutputPath = `${folderPath}/audio_only.mp3`;
const videoOutputPath = `${folderPath}/video_only.mp4`;
const ffmpegProcess = spawn("ffmpeg", [
"-i",
filePath,
"-q:a",
"0",
"-map",
"a",
audioOutputPath,
"-q:v",
"0",
"-map",
"v",
videoOutputPath,
]);
await new Promise((resolve, reject) => {
ffmpegProcess.on("close", (code) => {
if (code !== 0) {
reject(`ffmpeg process exited with code ${code}`);
}
});
});
return NextResponse.json(
{
message: `Video saved at ${folderPath}`,
videoId: videoId,
},
{ status: 200 }
);
} else if (type === "youtube") {
const videoId = uuidv4();
const folderPath = `videos/${videoId}`;
await fs.mkdir(folderPath);
// Download audio
const audioOutputPath = `${folderPath}/audio_only.mp3`;
const audioStream = ytdl(link, { quality: "highestaudio" });
await pipeToFile(audioStream, audioOutputPath);
// Download video
const videoOutputPath = `${folderPath}/video_only.mp4`;
const videoStream = ytdl(link, { quality: "highestvideo" });
await pipeToFile(videoStream, videoOutputPath);
return NextResponse.json(
{
message: `YouTube video saved at ${folderPath}`,
videoId: videoId,
},
{ status: 200 }
);
} else {
return NextResponse.json(
{
message:
"Invalid value for 'type'. It should be either 'youtube' or 'local'.",
},
{ status: 200 }
);
}
} catch (error) {
console.error("Error:", error);
return NextResponse.json(
{ error: "Internal server error. Please try again later." },
{ status: 500 }
);
}
}
async function pipeToFile(stream: any, filePath: any) {
const fs = require("fs");
const fileStream = fs.createWriteStream(filePath);
return new Promise<void>((resolve, reject) => {
stream.pipe(fileStream);
stream.on("end", () => {
resolve();
});
fileStream.on("error", reject);
});
}