3

Been playing around trying to get a simple youtube downloader working with ytdl-core & nextjs.

I have an onClick handler, making a call to the api.

const onClick = async () => {
    await fetch("/api")
      .then(async (res: any) => {
        const blob = res.blob();
        console.log("resBlob", blob);
        return blob;
      })
      .then((blob: any) => console.log("BLOB", blob));
  };
export async function GET(request: Request) {
  const url =
    "https://www.youtube.com/watch?v=r_LroCsdB20&ab_channel=riserecords";
  const res = await ytdl(url)
    .pipe(fs.createWriteStream("video.mp4"))
    .on("finish", function () {
      console.log("FINISHED");
    });

  return new Response(res);
}

It appears it returns the response immediately, before the socket finishes. I notice that if I move the response return to the .on("finish"..., it throws a headers error. The onClick handler first logs a promise under "resBlob", then logs a blob with size: 15, type: "text/plain. I'm not sure where to go from here.

Tried returning the response on the socket on.("finish".... I want to be able to return a response to the frontend and then with that response, to download the video.

1 Answers1

0

You need to set the Headers before returning the response. Please note that sometimes the name is not encoded correct and you will need to change the name in order for it to download the file properly

Here is a full working example:

import ytdl from "ytdl-core";
import { NextResponse } from "next/server";

export async function GET(request: Request, response: Response) {
  const { searchParams } = new URL(request.url);
  const url = searchParams.get("link");
  const responseHeaders = new Headers(response.headers);

  if (!url) {
    return NextResponse.json({ data: "No URL" });
  }

  const randomName = Math.random().toString(36).substring(2, 15);

  responseHeaders.set(
    "Content-Disposition",
    `attachment; filename="${randomName}.mp4"`,
  );

  responseHeaders.set(
    "User-Agent",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
  );

  const data = ytdl(url);

  return new Response(data as any, {
    headers: responseHeaders,
  });
}

You do not have to use await. It will automatically wait until the data has fetched.

Enjoy.

Or Nakash
  • 1,345
  • 1
  • 9
  • 22