I'm creating YouTube video downloader and I'm working with ytdl-core library and it cannot download high quality videos with audio, because youtube has it in another files, but I need to download it all in one file.
I already did this
app.get('/download', async (req, res, next) => {
const { videoId, format } = req.query;
ytdl.getInfo(videoId)
.then(info => {
const { title } = info.videoDetails;
res.header('Content-Disposition', `attachment; filename=${title}.mp4`);
const streams = {}
if (format === 'video') {
const resolution = req.query.resolution;
const videoFormat = chain(info.formats)
.filter(
format => format.height === +resolution && format.videoCodec?.startsWith('avc1')
)
.orderBy('fps', 'desc')
.head()
.value();
streams.video = ytdl(videoId, {
quality: videoFormat.itag,
format: 'mp4',
});
streams.audio = ytdl(videoId, { quality: 'highestaudio' });
}
});
});
Here is an example for you by using FFmpeg
import ffmpegPath from 'ffmpeg-static';
import cp from 'child_process';
import stream from 'stream';
import ytdl from "ytdl-core";
const ytmixer = (link, options = {}) => {
const result = new stream.PassThrough({ highWaterMark: (options as
any).highWaterMark || 1024 * 512 });
ytdl.getInfo(link, options).then(info => {
let audioStream = ytdl.downloadFromInfo(info, { ...options, quality:
'highestaudio' });
let videoStream = ytdl.downloadFromInfo(info, { ...options, quality:
'highestvideo' });
// create the ffmpeg process for muxing
let ffmpegProcess = cp.spawn(ffmpegPath, [
// supress non-crucial messages
'-loglevel', '8', '-hide_banner',
// input audio and video by pipe
'-i', 'pipe:3', '-i', 'pipe:4',
// map audio and video correspondingly
'-map', '0:a', '-map', '1:v',
// no need to change the codec
'-c', 'copy',
// output mp4 and pipe
'-f', 'matroska', 'pipe:5'
], {
// no popup window for Windows users
windowsHide: true,
stdio: [
// silence stdin/out, forward stderr,
'inherit', 'inherit', 'inherit',
// and pipe audio, video, output
'pipe', 'pipe', 'pipe'
]
});
audioStream.pipe(ffmpegProcess.stdio[3]);
videoStream.pipe(ffmpegProcess.stdio[4]);
ffmpegProcess.stdio[5].pipe(result);
});
return result;
};
ytmixer('Your Url').pipe(res);