Search code examples
node.jsexpresspromiseyoutube-dl

resolve() function is returning undefined in a promise


I am converting youtube-dl npm package to have promise instead of callbacks so I have working function but its not resolving the resolve function am I missing something here? my youtube downloader function looks like this :

const fs = require('fs');
const youtubedl = require('youtube-dl');


const downloadVideoAsync = (url) => {
    const video = youtubedl(url,['--format=18'],{ cwd: __dirname }); 
     if( video !== null) {
         video.on('info', function(info) {
             console.log('Download started');
             console.log('filename: ' + info._filename);
             console.log('size: ' + info.size);
             const videoName = info.fulltitle.replace(/\s+/g, '-').toLowerCase();
             if(videoName) {

                 return new Promise((resolve, reject) =>{
                     video.pipe(fs.createWriteStream(`videos/${videoName}.mp4`));
                     video.on('end', function() {
                        console.log(`this is the videoName in async ${videoName}`);
                        resolve(true);
                     })



                 });
             }

         });
     }

}

module.exports.downloadVideoAsync = downloadVideoAsync;

And I am calling that function in main server.js file like this :

 const asdf = async () => {
      const result = await downloadVideoAsync('https://www.youtube.com/watch?v=EsceiAe1B6w');
      console.log(`this is the result ${result}`);
  }

  asdf();

Solution

  • It returns undefined because that's what downloadVideoAsync is returning.

      console.log(
          typeof downloadVideoAsync('https://www.youtube.com/watch?v=EsceiAe1B6w')
      ); // undefined
    

    For your code to work like you want, you should wrap the video.on('info' with a Promise.

    const downloadVideoAsync = (url) => {
    
        return new Promise((resolve, reject) => {
    
            const video = youtubedl(url,['--format=18'],{ cwd: __dirname }); 
            if(!video)
                return reject(new Error('Video is empty...'));
    
             video.on('error', reject);
    
             video.on('info', function(info) {
                 console.log('Download started');
                 console.log('filename: ' + info._filename);
                 console.log('size: ' + info.size);
                 const videoName = info.fulltitle.replace(/\s+/g, '-').toLowerCase();
                 if(!videoName)
                      return reject(new Error('Empty name'));
    
                 video.pipe(fs.createWriteStream(`videos/${videoName}.mp4`));
                 video.on('end', function() {
                      console.log(`this is the videoName in async ${videoName}`);
                      resolve(true);
                 });
    
    
             });
    
        });
    }
    

    Now, downloadVideoAsync returns a Promise, instead of undefined, and it will wait until end is called before resolving, or it will reject if the video is empty.