fent / node-ytdl-core

YouTube video downloader in javascript.
MIT License
4.47k stars 790 forks source link

Caught exception: Error: Video unavailable #918

Open NathanPeake opened 3 years ago

NathanPeake commented 3 years ago

Caught exception: Error: Video unavailable

I have no idea why this is happening, I also checked all the issues and no one has had this issue

Caught exception: Error: Video unavailable
    at Object.exports.playError (Z:\Personal\repos\RedactedProjectName\node_modules\ytdl-core\lib\utils.js:124:12)
    at validate (Z:\Personal\repos\RedactedProjectName\node_modules\ytdl-core\lib\info.js:53:25)
    at pipeline (Z:\Personal\repos\RedactedProjectName\node_modules\ytdl-core\lib\info.js:175:11)
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
    at async exports.getBasicInfo (Z:\Personal\repos\RedactedProjectName\node_modules\ytdl-core\lib\info.js:62:14)

this is the code that has been used

url = the video url id = randomly generated id so I can retrieve the video later on (not relevant to the error as it is for file path)

var dl = ytdl(url).pipe(fs.createWriteStream(`./videos/${id}.mp4`));
dl.on('finish', () => {
callback( id )
})
TimeForANinja commented 3 years ago

Can you access the URL via a webbrowser? And is the script hosted in (at least) the same region?

kevin4dhd commented 3 years ago

any solution?

TimeForANinja commented 3 years ago

any solution?

Not without help narrowing down the problem

kevin4dhd commented 3 years ago

Video Youtube: https://www.youtube.com/watch?v=KHOrp6Fcp9M

image

just before that another error occurred, like 10 seconds before

Video Youtube: https://www.youtube.com/watch?v=qqSMqgGuSgU image

kevin4dhd commented 3 years ago

I am trying to ignore the exception so that my program does not stop but even so the process ends up, it would be a great help if you told me how to ignore that exception

Code:

"use strict";
var os = require("os");
var EventEmitter = require("events").EventEmitter;
var ffmpeg = require("fluent-ffmpeg");
var ytdl = require("ytdl-core");
var async = require("async");
var progress = require("progress-stream");
var sanitize = require("sanitize-filename");

class YoutubeMp3Downloader extends EventEmitter {
    constructor(options) {
        super();
        this.youtubeBaseUrl = "http://www.youtube.com/watch?v=";
        this.youtubeVideoQuality =
            options && options.youtubeVideoQuality
                ? options.youtubeVideoQuality
                : "highestaudio";
        this.outputPath =
            options && options.outputPath ? options.outputPath : os.homedir();
        this.queueParallelism =
            options && options.queueParallelism ? options.queueParallelism : 1;
        this.progressTimeout =
            options && options.progressTimeout ? options.progressTimeout : 1000;
        this.fileNameReplacements = [
            [/'/g, ""],
            [/\|/g, ""],
            [/'/g, ""],
            [/\//g, ""],
            [/\?/g, ""],
            [/:/g, ""],
            [/;/g, ""],
        ];
        this.requestOptions =
            options && options.requestOptions
                ? options.requestOptions
                : { maxRedirects: 5 };
        this.outputOptions =
            options && options.outputOptions ? options.outputOptions : [];
        this.allowWebm =
            options && options.allowWebm ? options.allowWebm : false;

        if (options && options.ffmpegPath) {
            ffmpeg.setFfmpegPath(options.ffmpegPath);
        }

        this.setupQueue();
    }

    setupQueue() {
        let self = this;
        //Async download/transcode queue
        this.downloadQueue = async.queue(function (task, callback) {
            self.emit(
                "queueSize",
                self.downloadQueue.running() + self.downloadQueue.length()
            );

            self.performDownload(task, function (err, result) {
                callback(err, result);
            });
        }, self.queueParallelism);
    }

    cleanFileName(fileName) {
        this.fileNameReplacements.forEach(function (replacement) {
            fileName = fileName.replace(replacement[0], replacement[1]);
        });
        return fileName;
    }

    download(videoId, fileName) {
        let self = this;
        const task = {
            videoId: videoId,
            fileName: fileName,
        };

        this.downloadQueue.push(task, function (err, data) {
            self.emit(
                "queueSize",
                self.downloadQueue.running() + self.downloadQueue.length()
            );

            if (err) {
                self.emit("error", err, data);
            } else {
                self.emit("finished", err, data);
            }
        });
    }

    async performDownload(task, callback) {
        let self = this;
        const videoUrl = this.youtubeBaseUrl + task.videoId;
        let resultObj = {
            videoId: task.videoId,
        };

        const info = await ytdl.getInfo(videoUrl, {
            quality: this
                .youtubeVideoQuality /*requestOptions: {
                headers: {
                    cookie: COOKIE,
                },
            }*/,
        });

        var videoTitle = this.cleanFileName(info.videoDetails.title);
        var artist = "Unknown";
        var title = "Unknown";
        var thumbnail = info.videoDetails.thumbnail.thumbnails[0].url || null;

        if (videoTitle.indexOf("-") > -1) {
            var temp = videoTitle.split("-");
            if (temp.length >= 2) {
                artist = temp[0].trim();
                title = temp[1].trim();
            }
        } else {
            title = videoTitle;
        }

        //Derive file name, if given, use it, if not, from video title
        const fileName = task.fileName
            ? self.outputPath + "/" + task.fileName
            : self.outputPath +
              "/" +
              (sanitize(videoTitle) || info.videoId) +
              ".mp3";

        //Stream setup

        const streamOptions = {
            quality: self.youtubeVideoQuality,
            requestOptions: self.requestOptions,
            /*requestOptions: {
                headers: {
                    cookie: COOKIE,
                },
            }*/
        };

        if (!self.allowWebm) {
            streamOptions.filter = (format) => format.container === "mp4";
        }

        try {
            const stream = ytdl.downloadFromInfo(info, streamOptions);
            stream.on("response", function (httpResponse) {
                //Setup of progress module
                const str = progress({
                    length: parseInt(httpResponse.headers["content-length"]),
                    time: self.progressTimeout,
                });

                //Add progress event listener
                str.on("progress", function (progress) {
                    if (progress.percentage === 100) {
                        resultObj.stats = {
                            transferredBytes: progress.transferred,
                            runtime: progress.runtime,
                            averageSpeed: parseFloat(progress.speed.toFixed(2)),
                        };
                    }
                    self.emit("progress", {
                        videoId: task.videoId,
                        progress: progress,
                    });
                });
                let outputOptions = [
                    "-id3v2_version",
                    "4",
                    "-metadata",
                    "title=" + title,
                    "-metadata",
                    "artist=" + artist,
                ];
                if (self.outputOptions) {
                    outputOptions = outputOptions.concat(self.outputOptions);
                }

                //Start encoding
                const proc = new ffmpeg({
                    source: stream.pipe(str),
                })
                    .audioBitrate(info.formats[0].audioBitrate || 96)
                    .withAudioCodec("libmp3lame")
                    .toFormat("mp3")
                    .outputOptions(...outputOptions)
                    .on("error", function (err) {
                        //return callback(err.message, null);//error por arreglar
                    })
                    .on("end", function () {
                        resultObj.file = fileName;
                        resultObj.youtubeUrl = videoUrl;
                        resultObj.videoTitle = videoTitle;
                        resultObj.artist = artist;
                        resultObj.title = title;
                        resultObj.thumbnail = thumbnail;
                        callback(null, resultObj);
                    })
                    .saveToFile(fileName);
            });
        } catch (err) {
            self.emit("error", err, "");
        }
    }
}

module.exports = YoutubeMp3Downloader;

Call Class:

//Configure YoutubeMp3Downloader with your settings
var YD = new YoutubeMp3Downloader({
    //"ffmpegPath": '/usr/bin/ffmpeg', // FFmpeg binary location
    "ffmpegPath": ffmpeg.path,
    "outputPath": "./youtube_mp3/mp3", // Output file location (default: the home directory)
    "youtubeVideoQuality": "highestaudio", // Desired video quality (default: highestaudio)
    "queueParallelism": 10, // Download parallelism (default: 1)
    //"progressTimeout": 500, // Interval in ms for the progress reports (default: 1000)
    "allowWebm": false // Enable download from WebM sources (default: false)
});
YD.download(url, nombreFile);
YD.on("finished", async function (err, dataYD) {
///...
});
YD.on("error", async function (err, dataYD) {
**//No working**
});
TimeForANinja commented 3 years ago

ytdl.downloadFromInfo(info, streamOptions); should not "throw" an error but emit an error event so try listening for that event instead of the try / catch

NathanPeake commented 3 years ago

my server is local to me, same network and has access to the internet. and I can view it on YouTube just fine