You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js结合ytdl与FFmpeg处理视频下载合并问题求助

Node.js ytdl+FFmpeg 合并视频音频的问题排查与修复

问题1:视频时长超出正常范围

原因

当前代码仅监听音频流的finish事件就触发合并操作,但视频流的下载是独立的异步任务,此时视频文件大概率还未完全写入磁盘。合并未完成的视频文件会导致媒体时长解析异常,甚至生成损坏的文件。

修复方案

用Promise封装视频和音频的下载流程,等待两者都完成后再执行合并。

问题2:fluent-ffmpeg提示找不到FFmpeg

原因

fluent-ffmpeg只是Node.js的FFmpeg封装库,本身不包含FFmpeg二进制程序。必须在系统中单独安装FFmpeg,并确保Node.js进程能访问到其可执行文件路径。

修复方案

  1. 安装FFmpeg
    • Windows:下载FFmpeg二进制包,解压后将ffmpeg.exe所在目录添加到系统PATH环境变量;
    • macOS:通过Homebrew执行brew install ffmpeg;
    • Linux:通过系统包管理器安装,例如Ubuntu执行sudo apt install ffmpeg。
  2. 代码中指定FFmpeg路径(可选)
    如果环境变量配置后仍无法识别,可在代码开头手动指定路径:
    ffmpeg.setFfmpegPath('/usr/local/bin/ffmpeg'); // 替换为你的FFmpeg实际路径
    

修复后的完整代码

const fs = require('fs');
const ytdl = require('ytdl-core');
const ffmpeg = require('fluent-ffmpeg');

// 可选:手动指定FFmpeg路径,根据你的系统调整
// ffmpeg.setFfmpegPath('/usr/local/bin/ffmpeg');

// 封装下载流为Promise
function downloadStream(stream, outputPath) {
  return new Promise((resolve, reject) => {
    stream.pipe(fs.createWriteStream(outputPath))
      .on('finish', resolve)
      .on('error', reject);
  });
}

// Function to download the youtube video
function download() {
    const linkInput = document.getElementById('linkInp');
    const resolution = document.getElementById('resolution');
    const videoTitle = document.getElementById('videoTitle');
    const videoAuthor = document.getElementById('videoAuthor');
    const videoUploadDate = document.getElementById('videoUploadDate');
    const videoPicture = document.getElementById('videoPic');
    const link = linkInput.value;
    console.log('Downloading following video from link: ', link, ' with resolution id: ', resolution.value);

    ytdl.getInfo(link).then(async (info) => {
        const format = ytdl.chooseFormat(info.formats, { quality: `${resolution.value}` });
        const videoFilePath = `${info.videoDetails.title}.${format.container}`;
        const audioFilePath = `${info.videoDetails.title}.mp3`;

        // 填充元数据
        videoTitle.innerHTML = info.videoDetails.title;
        videoAuthor.innerHTML = info.videoDetails.author.name;
        videoUploadDate.innerHTML = info.videoDetails.uploadDate;
        videoPicture.src = info.videoDetails.thumbnails[0].url;

        // 同时下载视频和音频,等待两者完成
        try {
          await Promise.all([
            downloadStream(ytdl.downloadFromInfo(info, { format: format }), videoFilePath),
            downloadStream(ytdl.downloadFromInfo(info, { filter: 'audioonly' }), audioFilePath)
          ]);

          // 合并视频和音频
          ffmpeg()
              .input(videoFilePath)
              .input(audioFilePath)
              .videoCodec('copy')
              .audioCodec('copy')
              .save(`${info.videoDetails.title}_with_audio.${format.container}`)
              .on('end', () => {
                  console.log('Video with audio merged successfully!');
                  // 删除临时文件
                  fs.unlink(videoFilePath, (err) => err && console.error(err));
                  fs.unlink(audioFilePath, (err) => err && console.error(err));
              })
              .on('error', (err) => console.error('Merge error:', err));
        } catch (err) {
          console.error('Download error:', err);
          document.getElementById('msg').style.display = 'block';
          document.getElementById('message').innerHTML = err;
        }

    }).catch((err) => {
        console.error(err);
        document.getElementById('msg').style.display = 'block';
        document.getElementById('message').innerHTML = err;
    });
}

内容的提问来源于stack exchange,提问作者zlElo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 21:58:27