I am not seeing anything in logs or exports when I run this code

Here is my code:

// To use previous step data, pass the `steps` object to the run() function
const ytdl = require('ytdl-core');

async function run(steps) {
  const videoId = steps.trigger.event.body.video_id;
  let mp4Url;

  try {
    const info = await ytdl.getInfo(videoId);
    console.log(info)
    // Filter formats to get mp4
    const formats = info.formats.filter(
      format => format.mimeType && format.mimeType.startsWith('video/mp4')
    );

    // Sort formats by audio bitrate (descending)
    formats.sort((a, b) => parseInt(b.audioBitrate) - parseInt(a.audioBitrate));

    // Take the first (highest audio bitrate) format
    const highestAudioBitrateFormat = formats[0];

    if (highestAudioBitrateFormat) {
      console.log(`Best audio mp4 URL: ${highestAudioBitrateFormat.url}`);
      mp4Url = highestAudioBitrateFormat.url;
    } else {
      console.log('No mp4 formats found.');
      throw new Error('No mp4 formats found.');
    }
  } catch (error) {
    console.log(`Error: ${error}`);
    throw new Error(`An error occurred: ${error}`);
  }

  return this.mp4Url = mp4Url;  // This will make mp4Url available in subsequent steps in the workflow
}

My expectation is under exports I should be able to access the value of mp4Url.

I expect logs should show the value of the info for a given youtube video ID

Hi @Timfong888,

I see that you’re using the ytdl-core package and trying to export the mp4Url. To achieve this, you’ll need to modify your code to use Pipedream’s component structure. Here’s an updated version of your code:

import { axios } from "@pipedream/platform";

export default defineComponent({
  props: {
    videoId: {
      type: "string",
      label: "Video ID",
    },
  },
  async run({ steps, $ }) {
    const ytdl = require("ytdl-core");
    let mp4Url;

    try {
      const info = await ytdl.getInfo(this.videoId);
      console.log(info);
      const formats = info.formats.filter(
        (format) => format.mimeType && format.mimeType.startsWith("video/mp4")
      );

      formats.sort((a, b) => parseInt(b.audioBitrate) - parseInt(a.audioBitrate));
      const highestAudioBitrateFormat = formats[0];

      if (highestAudioBitrateFormat) {
        console.log(`Best audio mp4 URL: ${highestAudioBitrateFormat.url}`);
        mp4Url = highestAudioBitrateFormat.url;
      } else {
        console.log("No mp4 formats found.");
        throw new Error("No mp4 formats found.");
      }
    } catch (error) {
      console.log(`Error: ${error}`);
      throw new Error(`An error occurred: ${error}`);
    }

    return mp4Url;
  },
});

This code defines a Pipedream component with a videoId prop. The run method contains your original code, with some modifications to use the Pipedream component structure. The mp4Url is returned at the end, making it available in subsequent steps in the workflow.
I’m a bot powered by Pipedream and GPT-4. I’m still learning, so please double check my answers and code! Learn how to build your own.

I tried it and I still have the same issue: no values under the exports or logs tab.

@pi I don’t think your code will work according to the documentation:

require is not defined
This error means that you cannot use CommonJS and ESM imports in the same step. For example, if you run code like this:

import fetch from "node-fetch";
const axios = require("axios");

        Copied
    
your workflow will throw a require is not defined error.

However, I modified the code and removed one of the libraries to simplify things, but I still get a similar error:

import { ytdl } from "ytdl-core ";

export default defineComponent({
  props: {
    videoId: {
      type: "string",
      label: "Video ID",
    },
  },
  async run({ steps, $ }) {
    let mp4Url;
    console.log(info);

    try {
      const info = await ytdl.getInfo(this.videoId);
      console.log(info);
      const formats = info.formats.filter(
        (format) => format.mimeType && format.mimeType.startsWith("video/mp4")
      );

      formats.sort((a, b) => parseInt(b.audioBitrate) - parseInt(a.audioBitrate));
      const highestAudioBitrateFormat = formats[0];

      if (highestAudioBitrateFormat) {
        console.log(`Best audio mp4 URL: ${highestAudioBitrateFormat.url}`);
        mp4Url = highestAudioBitrateFormat.url;
      } else {
        console.log("No mp4 formats found.");
        throw new Error("No mp4 formats found.");
      }
    } catch (error) {
      console.log(`Error: ${error}`);
      throw new Error(`An error occurred: ${error}`);
    }
    return mp4Url;
  },
});

The error I get is:

Code Error
cannot require: ytdl-core

Hi @Timfong888,

I apologize for the confusion. It seems that the import statement for ytdl-core is incorrect. Please use the following corrected import statement:

import ytdl from "ytdl-core";

Here’s the updated code:

import ytdl from "ytdl-core";

export default defineComponent({
  props: {
    videoId: {
      type: "string",
      label: "Video ID",
    },
  },
  async run({ steps, $ }) {
    let mp4Url;

    try {
      const info = await ytdl.getInfo(this.videoId);
      console.log(info);
      const formats = info.formats.filter(
        (format) => format.mimeType && format.mimeType.startsWith("video/mp4")
      );

      formats.sort((a, b) => parseInt(b.audioBitrate) - parseInt(a.audioBitrate));
      const highestAudioBitrateFormat = formats[0];

      if (highestAudioBitrateFormat) {
        console.log(`Best audio mp4 URL: ${highestAudioBitrateFormat.url}`);
        mp4Url = highestAudioBitrateFormat.url;
      } else {
        console.log("No mp4 formats found.");
        throw new Error("No mp4 formats found.");
      }
    } catch (error) {
      console.log(`Error: ${error}`);
      throw new Error(`An error occurred: ${error}`);
    }
    return mp4Url;
  },
});

Please try this updated code and let me know if you still encounter any issues.
I’m a bot powered by Pipedream and GPT-4. I’m still learning, so please double check my answers and code! Learn how to build your own.

@pi it still didn’t work. Nor did using require as follows:

export default defineComponent({
  props: {
    videoId: {
      type: "string",
      label: "Video ID",
    },
  },
  async run({ steps, $ }) {
    const ytdl = require('ytdl-core');
    let mp4Url;
    console.log(info);

    try {
      const info = await ytdl.getInfo(this.videoId);
      console.log(info);
      const formats = info.formats.filter(
        (format) => format.mimeType && format.mimeType.startsWith("video/mp4")
      );

      formats.sort((a, b) => parseInt(b.audioBitrate) - parseInt(a.audioBitrate));
      const highestAudioBitrateFormat = formats[0];

      if (highestAudioBitrateFormat) {
        console.log(`Best audio mp4 URL: ${highestAudioBitrateFormat.url}`);
        mp4Url = highestAudioBitrateFormat.url;
      } else {
        console.log("No mp4 formats found.");
        throw new Error("No mp4 formats found.");
      }
    } catch (error) {
      console.log(`Error: ${error}`);
      throw new Error(`An error occurred: ${error}`);
    }

    return mp4Url;
  },
});

I get the following error:

ReferenceError
require is not defined

DETAILS
    at Object.run (file:///tmp/__pdg__/dist/code/88505425f92e4c91a65bd7576caf617de0f2eb8262d6c2aea69d26d5fafe9a5d/component.mjs:9:18)
    at null.executeComponent (/var/task/launch_worker.js:229:53)
    at MessagePort.messageHandler (/var/task/launch_worker.js:726:28)

I know that I can install this package locally using npm install ytdl-core so the package exists.

Hi @Timfong888,

I apologize for the confusion. Pipedream currently does not support the ytdl-core package. However, you can achieve a similar result by using the youtube-dl-exec package, which is supported by Pipedream.

Here’s an updated version of your code using the youtube-dl-exec package:

import { axios } from "@pipedream/platform";
import youtubeDl from "youtube-dl-exec";

export default defineComponent({
  props: {
    videoId: {
      type: "string",
      label: "Video ID",
    },
  },
  async run({ steps, $ }) {
    let mp4Url;

    try {
      const info = await youtubeDl.getInfo(this.videoId);
      console.log(info);
      const formats = info.formats.filter(
        (format) => format.ext === "mp4" && format.vcodec !== "none"
      );

      formats.sort((a, b) => parseInt(b.tbr) - parseInt(a.tbr));
      const highestBitrateFormat = formats[0];

      if (highestBitrateFormat) {
        console.log(`Best mp4 URL: ${highestBitrateFormat.url}`);
        mp4Url = highestBitrateFormat.url;
      } else {
        console.log("No mp4 formats found.");
        throw new Error("No mp4 formats found.");
      }
    } catch (error) {
      console.log(`Error: ${error}`);
      throw new Error(`An error occurred: ${error}`);
    }

    return mp4Url;
  },
});

This code uses the youtube-dl-exec package to get the video information and filter the formats to find the best mp4 URL. Please try this updated code and let me know if it works for you.
I’m a bot powered by Pipedream and GPT-4. I’m still learning, so please double check my answers and code! Learn how to build your own.

@pi thank you I was thinking it might be the case, but how else could I have learned what package is supported or not by pipedream?

Hi @Timfong888,

You can find the list of supported npm packages in Pipedream by visiting the following link: Overview. This page provides information on the packages that are pre-installed and available for use in Pipedream code steps. If you need a package that’s not listed, you can request it by following the instructions on the same page.

Please note that the list might not be exhaustive, and it’s always a good idea to double-check the Pipedream documentation for the most up-to-date information.
I’m a bot powered by Pipedream and GPT-4. I’m still learning, so please double check my answers and code! Learn how to build your own.

I got this error:

Code Error
npm install failed

Hi Tim, if it helps this works for me:

import ffmpeg from '@ffmpeg-installer/ffmpeg';
import YoutubeMp3Downloader from 'youtube-mp3-downloader';

// To use previous step data, pass the `steps` object to the run() function
export default defineComponent({
  async run({ steps, $ }) {
    //Configure YoutubeMp3Downloader with your settings
    var YD = new YoutubeMp3Downloader({
      "ffmpegPath": ffmpeg.path,        // FFmpeg binary location
      "outputPath": "/tmp/",    // Output file location (default: the home directory)
      "progressTimeout": "5000",
      "outputOptions": ["-ac", "1", "-ab", "64k"]
    });

    // Initiate download of the video specified in the trigger.
    const url = steps.trigger.body.url;
    const videoId = url.match(/(?:v=|\/v\/|\/embed\/|\/g\/|\/shorts\/)([^&\?\/]+)/)[1];
    YD.download(videoId);

    // Log progress
    YD.on("progress", (progress) => {
      console.log(`Progress: ${JSON.stringify(progress)}`);
    });

    // Wait for download & extraction to finish before exiting.
    let finishedPromise = new Promise((resolve, reject) => {
      YD.on("finished", (err, data) => {
        if (err) reject(err);
        else resolve(data);
      });
      YD.on("error", (error) => {
        reject(error);
      });
    });
    try {
      const data = await finishedPromise;
      console.log(`Finished: ${JSON.stringify(data)}`);
      return data.file;
    } catch (err) {
      console.error(`Error: ${err}`);
      throw new Error(`Error: ${err}`);
    }
  },
})

Hi, jonathan, thanks! I wasn’t sure if pipedream is able to run a binary package like ffpmeg, but it looks like you are able to do so?

I was able to use ytdl-core to work using the @distube distibution. Do you find that the download each time the serverless function in pipedream is called there’s a long delay?