kenpeter
kenpeter

Reputation: 8294

How to resolve this promise when converting to mp3 is completed (fluent-ffmpeg)

I have a simple nodejs script to download youtube video and convert to mp3. I have some problems with promise pattern and need some help. Basically, there is only one resolve();, but the script never reach that part. If I move resolve(); under console.log('Finished downloading! start to convert to mp3');

It starts to work, so the problem is something related to the resolve(); sitting side a callback function.

Full code: https://github.com/kenpeter/test_youtube_dl

Code snippet:

// input
var input = [
  "https://www.youtube.com/watch?v=YWZ7KtRSoAo",
  "https://www.youtube.com/watch?v=0kdbu8RZNaY"
];

// lib
var youtubedl = require('youtube-dl');

// fs
var fs = require('fs');

// ffmpeg
var ffmpeg = require('fluent-ffmpeg');

// Promise
var Promise = require("bluebird");


// https://www.promisejs.org/
function youtubedl_get_info() {
  return new Promise(function (resolve, reject){
    youtubedl.getInfo(input, function(err, info) {
      if (err) {
        reject(err);
      }  
      else
      {
        //console.log(info);
        resolve(info); 
      }  
    });    
  });
}

youtubedl_get_info().then(function(infos) {

  // info is array
  // http://bluebirdjs.com/docs/api/promise.each.html
  Promise.each(infos, function(info) {

    // return new promise
    return new Promise(function(resolve, reject) {

      // output
      var video_output = info._filename.replace(/[&\/\\#,+()$~%'":*?<>{}\ ]/g, "_");

      var audio_title = info.title;
      audio_title = audio_title.replace(/[&\/\\#,+()$~%'":*?<>{}\ ]/g, "_");

      // dl zero
      var downloaded = 0;

      // fs file exist sync
      if (fs.existsSync(video_output)) {
        downloaded = fs.statSync(video_output).size;
      }


      var video = youtubedl(
        info.webpage_url,
        ['--format=18'],
        { start: downloaded, cwd: __dirname + "/video" }
      );

      video.on('info', function(info) {
        console.log('Download started');
        console.log('filename: ' + video_output);

        var total = info.size + downloaded;
        console.log('size: ' + total);

        if (downloaded > 0) {
          console.log('resuming from: ' + downloaded);
          console.log('remaining bytes: ' + info.size);
        }
      });

      video.pipe(fs.createWriteStream("./video/" + video_output, { flags: 'a' }));

      video.on('complete', function complete(info) {
        'use strict';
        console.log('filename: ' + video_output + ' already downloaded.');
      });


      video.on('end', function() {
        console.log('Finished downloading! start to convert to mp3');

        // It seems I cannot do more async here.
        // https://codedump.io/share/KVSJfXwwlRSI/1/nodejs--how-to-pipe---youtube-to-mp4-to-mp3
        var proc = new ffmpeg({source: "./video/" + video_output});

        proc.setFfmpegPath('/usr/bin/ffmpeg');
        proc.saveToFile("./audio/" + audio_title + ".mp3", function(stdout, stderr) {
          console.log("----- done -----");

          // Why I never come here??????????????????????????????????
          resolve();
        });

      });


    });

  });

});

Upvotes: 2

Views: 2384

Answers (1)

Antonio Narkevich
Antonio Narkevich

Reputation: 4336

This happens because .saveToFile doesn't accept a callback. Try running it like this:

proc.setFfmpegPath('./ffmpeg');
proc.output("./audio/" + audio_title + ".mp3");
proc.on('error', function (err) {
	console.log(err);
});
proc.on('end', function () {
	resolve();
});
proc.run();

Here are the docs on this topic.

Nice song btw :)

Upvotes: 4

Related Questions