如何在Railway安装FFmpeg?Discord.js代码运行无输出求助
问题排查与解决方案
一、代码无输出/无响应的原因及修复
你的代码存在几个关键问题,导致异步流程静默失败且无日志:
1. 错误监听缺失
所有异步操作(fs.readdir、https.get、ffmpeg进程)都未绑定error事件,一旦出错会直接静默终止,不会打印任何错误信息。必须给每个异步步骤加上错误捕获:
- 给
fs.readdir添加错误回调处理 - 给
https.get的请求对象绑定on('error') - 给每个
ffmpeg实例添加on('error', (err) => console.error(err))
2. 路径模板字符串错误
modbait变量里的${slash}被包裹在双引号中,不会被解析为变量,导致路径错误:
// 错误写法 var modbait = __dirname + "${slash}tmp${slash}baitt" + rnum // 正确写法(用模板字符串) var modbait = `${__dirname}${slash}tmp${slash}baitt${rnum}`
3. 跨平台命令不兼容
你用了Windows的copy /b和Del命令,但Railway是Linux环境,必须替换为Linux命令:
// 替换concat命令为Linux的cat var concat = `cat "${modbait}" "${B}" > "${output}"` // 替换DeleteFiles为Linux的rm var DeleteFiles = `rm -f "${A}" "${B}" "${output}" "${modbait}"`
4. ffmpeg进程未正确监听结束/错误
ffmpeg的end事件仅在成功完成时触发,若进程出错(比如文件不存在、编码失败)会直接触发error事件,不会走end,所以必须同时监听两个事件。
修改后的关键代码片段
function run(interaction, client, slash) { const [file, rnum] = [interaction.options.getAttachment("file").url, Math.floor(Math.random() * 999)] interaction.reply("adding bypass to your audio " + slash) // 处理fs.readdir错误 fs.readdir(`${__dirname}${slash}baits`, function (err, Baits) { if (err) { console.error('读取baits目录失败:', err); return interaction.followUp('处理失败:无法读取诱饵文件目录'); } if (!Baits.length) { console.error('baits目录为空'); return interaction.followUp('处理失败:诱饵文件目录为空'); } const req = https.get(file, function (response) { console.log('开始下载用户文件'); const Bait = `${__dirname}${slash}baits${slash}${Baits[Math.floor(Math.random() * Baits.length)]}`; const [A, B, output] = [`${__dirname}${slash}tmp${slash}A_${rnum}.ogg`, `${__dirname}${slash}tmp${slash}B_${rnum}.ogg`, `${__dirname}${slash}tmp${slash}bbbbbb${rnum}.ogg`]; const modbait = `${__dirname}${slash}tmp${slash}baitt${rnum}`; // Linux兼容的concat和删除命令 const concat = `cat "${modbait}" "${B}" > "${output}"`; const DeleteFiles = `rm -f "${A}" "${B}" "${output}" "${modbait}"`; const endFile = fs.createWriteStream(A); const stream = response.pipe(endFile); // 监听文件写入错误 stream.on('error', (err) => { console.error('写入临时文件A失败:', err); interaction.followUp('处理失败:无法保存上传的音频文件'); }); stream.on('finish', function () { console.log('用户文件下载完成,开始处理诱饵文件'); // 处理诱饵文件转码 ffmpeg(Bait) .toFormat("ogg") .saveToFile(modbait) .on('error', (err) => { console.error('转码诱饵文件失败:', err); interaction.followUp('处理失败:诱饵文件转码出错'); }) .on('end', function () { console.log('诱饵文件转码完成,开始处理用户音频'); // 处理用户音频 ffmpeg(A) .audioChannels(2) .audioFrequency(32000) .saveToFile(B) .on('error', (err) => { console.error('转码用户音频失败:', err); interaction.followUp('处理失败:用户音频转码出错'); }) .on('end', function () { console.log('用户音频转码完成,开始合并文件'); // 执行合并命令 _exec(concat, function (err) { if (err) { console.error('合并文件失败:', err); return interaction.followUp('处理失败:文件合并出错'); } interaction.channel.send({ content: "oi", files: [output] }).then(() => { setTimeout(() => { _exec(DeleteFiles, (err) => { if (err) console.error('删除临时文件失败:', err); else console.log('Deleted All Files'); }) }, 15000); }).catch(err => { console.error('发送消息失败:', err); }); }); }); }); }); }); // 监听https请求错误 req.on('error', (err) => { console.error('下载用户文件失败:', err); interaction.followUp('处理失败:无法下载上传的音频文件'); }); }); }
二、在Railway中安装FFmpeg
Railway支持两种方式安装FFmpeg:
1. 使用Nixpacks配置(推荐)
在项目根目录创建nixpacks.toml文件,添加以下内容:
[phases.install] nixPkgs = ["...", "ffmpeg"]
Nixpacks在构建时会自动安装FFmpeg。
2. 通过apt-get安装(适用于Node.js项目)
在package.json的scripts里添加预处理脚本:
{ "scripts": { "prestart": "apt-get update && apt-get install -y ffmpeg", "start": "node index.js" } }
注意:这种方式每次启动都会执行安装,效率不如Nixpacks,但适合快速测试。
内容的提问来源于stack exchange,提问作者miguel
相关产品推荐
相关产品推荐

