基于node-youtube-dl构建Node.js服务:下载YouTube视频并转发为Form-Data
Node.js实现YouTube视频下载并以Form-Data转发到其他服务
我帮你把这个流程补全并优化,直接给你可运行的完整方案,分两种场景(无本地文件缓存和带本地缓存)来写:
首先准备依赖
推荐用更活跃的youtube-dl-exec替代旧的node-youtube-dl,同时需要axios和form-data来处理表单请求:
npm install youtube-dl-exec axios form-data express
方案一:直接流转发(无本地文件,高效)
这种方式不需要把视频存到磁盘,直接把YouTube的视频流通过管道传给目标服务,节省磁盘空间和IO时间:
const youtubeDl = require('youtube-dl-exec'); const axios = require('axios'); const FormData = require('form-data'); const express = require('express'); const app = express(); async function downloadAndForwardVideo(req, res) { const videoUrl = req.query.url; if (!videoUrl) { return res.status(400).send('请提供视频URL参数(?url=xxx)'); } try { // 1. 获取视频流(直接输出到stdout,避免写入本地) const videoStream = await youtubeDl(videoUrl, { format: 'best[height<=480]', // 筛选480p以内的最佳画质 output: '-' // 输出到标准输出,获取流 }, { stdio: ['ignore', 'pipe', 'ignore'] // 配置stdio,让stdout作为可读流返回 }); // 2. 获取视频基本信息(用于文件名) const videoInfo = await youtubeDl.getInfo(videoUrl); const videoFileName = `${videoInfo.title}.mp4`; // 3. 构建Form-Data表单 const formData = new FormData(); formData.append('video', videoStream, { filename: videoFileName, contentType: 'video/mp4' }); // 4. 发送到目标服务 const targetServiceUrl = 'https://你的目标服务地址/upload'; // 替换成实际地址 const forwardResponse = await axios.post(targetServiceUrl, formData, { headers: { ...formData.getHeaders(), // 自动生成Form-Data所需的头部 // 如果目标服务需要授权,在这里加:'Authorization': 'Bearer 你的token' } }); // 5. 返回结果给客户端 res.status(200).json({ success: true, videoTitle: videoInfo.title, targetServiceResult: forwardResponse.data }); } catch (err) { console.error('处理视频出错:', err); res.status(500).send(`视频处理失败:${err.message}`); } } // 注册接口,启动服务 app.get('/forward-youtube-video', downloadAndForwardVideo); app.listen(3000, () => { console.log('服务启动在3000端口:http://localhost:3000/forward-youtube-video?url=YouTube视频链接'); });
方案二:先下载到本地再转发(适合需要缓存的场景)
如果需要临时保存视频文件(比如做备份),可以用这个版本:
const youtubeDl = require('youtube-dl-exec'); const axios = require('axios'); const FormData = require('form-data'); const express = require('express'); const fs = require('fs'); const path = require('path'); const app = express(); // 创建临时目录 const tempDir = path.join(__dirname, 'temp'); if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir); async function downloadAndForwardWithCache(req, res) { const videoUrl = req.query.url; if (!videoUrl) { return res.status(400).send('请提供视频URL参数(?url=xxx)'); } try { // 1. 获取视频信息,生成文件名 const videoInfo = await youtubeDl.getInfo(videoUrl); const videoFileName = `${videoInfo.title}.mp4`; const localFilePath = path.join(tempDir, videoFileName); // 2. 下载视频到本地文件 await youtubeDl(videoUrl, { format: 'best[height<=480]', output: localFilePath }); // 3. 构建Form-Data,读取本地文件流 const formData = new FormData(); formData.append('video', fs.createReadStream(localFilePath), { filename: videoFileName, contentType: 'video/mp4' }); // 4. 发送到目标服务 const targetServiceUrl = 'https://你的目标服务地址/upload'; const forwardResponse = await axios.post(targetServiceUrl, formData, { headers: formData.getHeaders() }); // 5. 可选:删除临时文件(如果不需要缓存的话) fs.unlinkSync(localFilePath); // 6. 返回结果 res.status(200).json({ success: true, videoTitle: videoInfo.title, targetServiceResult: forwardResponse.data }); } catch (err) { console.error('处理视频出错:', err); res.status(500).send(`视频处理失败:${err.message}`); } } app.get('/forward-youtube-video-with-cache', downloadAndForwardWithCache); app.listen(3000, () => { console.log('服务启动在3000端口:http://localhost:3000/forward-youtube-video-with-cache?url=YouTube视频链接'); });
注意事项
- 工具选择:建议安装
yt-dlp替代官方youtube-dl(因为youtube-dl已经停止维护),youtube-dl-exec会自动检测系统中的yt-dlp,你可以手动安装或者通过youtube-dl-exec的download选项自动下载。 - 目标服务兼容性:确保目标服务支持接收
multipart/form-data格式的文件,并且表单字段名(这里是video)和目标服务的要求一致。 - 大视频处理:流转发方案内存占用更低,但要确保服务器有足够的带宽;本地缓存方案需要注意磁盘空间,记得定期清理临时文件。
内容的提问来源于stack exchange,提问作者Brainjump




