audio-merger.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.AudioMerger = void 0;
  7. const fs_1 = __importDefault(require("fs"));
  8. const child_process_1 = require("child_process");
  9. const util_1 = require("util");
  10. const execAsync = (0, util_1.promisify)(child_process_1.exec);
  11. class AudioMerger {
  12. // 合并多个音频文件
  13. static async merge(inputFiles, outputPath) {
  14. if (inputFiles.length === 0) {
  15. throw new Error('没有音频文件需要合并');
  16. }
  17. if (inputFiles.length === 1) {
  18. // 单个文件直接复制
  19. fs_1.default.copyFileSync(inputFiles[0], outputPath);
  20. return outputPath;
  21. }
  22. try {
  23. // 创建文件列表
  24. const listContent = inputFiles.map(f => `file '${f}'`).join('\n');
  25. const listFile = '/tmp/ffmpeg_list.txt';
  26. fs_1.default.writeFileSync(listFile, listContent);
  27. // 检查输出格式
  28. const outputExt = outputPath.split('.').pop()?.toLowerCase();
  29. // 构建 FFmpeg 命令
  30. let cmd;
  31. if (outputExt === 'mp3') {
  32. // MP3 需要转码(WAV/PCM -> MP3)
  33. cmd = `ffmpeg -f concat -safe 0 -i "${listFile}" -c:a libmp3lame -b:a 192k -y "${outputPath}"`;
  34. }
  35. else {
  36. // 其他格式直接复制
  37. cmd = `ffmpeg -f concat -safe 0 -i "${listFile}" -c copy -y "${outputPath}"`;
  38. }
  39. await execAsync(cmd, { timeout: 120000 });
  40. console.log(`✅ 音频合并成功: ${outputPath}`);
  41. return outputPath;
  42. }
  43. catch (error) {
  44. console.error('❌ 音频合并失败:', error);
  45. throw new Error('音频合并失败');
  46. }
  47. }
  48. // 获取音频时长
  49. static async getDuration(filePath) {
  50. try {
  51. const cmd = `ffprobe -i "${filePath}" -show_entries format=duration -v quiet -of csv="p=0"`;
  52. const { stdout } = await execAsync(cmd, { timeout: 10000 });
  53. return Math.round(parseFloat(stdout.trim()) || 0);
  54. }
  55. catch (error) {
  56. console.error('❌ 获取音频时长失败:', error);
  57. return 0;
  58. }
  59. }
  60. }
  61. exports.AudioMerger = AudioMerger;