| const fs = require('fs'); | |
| const path = require('path'); | |
| const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; | |
| const { spawn } = require('child_process'); | |
| class AudioConverter { | |
| constructor() { | |
| this.tempDir = path.join(__dirname, '../temp'); | |
| this.ensureTempDir(); | |
| } | |
| ensureTempDir() { | |
| if (!fs.existsSync(this.tempDir)) { | |
| fs.mkdirSync(this.tempDir, { recursive: true }); | |
| } | |
| } | |
| async cleanFile(file) { | |
| if (file && fs.existsSync(file)) { | |
| await fs.promises.unlink(file).catch(() => {}); | |
| } | |
| } | |
| async convert(buffer, args, ext, ext2) { | |
| const inputPath = path.join(this.tempDir, `${Date.now()}.${ext}`); | |
| const outputPath = path.join(this.tempDir, `${Date.now()}.${ext2}`); | |
| try { | |
| await fs.promises.writeFile(inputPath, buffer); | |
| return new Promise((resolve, reject) => { | |
| const ffmpeg = spawn(ffmpegPath, [ | |
| '-y', | |
| '-i', inputPath, | |
| ...args, | |
| outputPath | |
| ], { timeout: 30000 }); | |
| let errorOutput = ''; | |
| ffmpeg.stderr.on('data', (data) => errorOutput += data.toString()); | |
| ffmpeg.on('close', async (code) => { | |
| await this.cleanFile(inputPath); | |
| if (code !== 0) { | |
| await this.cleanFile(outputPath); | |
| return reject(new Error(`Conversion failed with code ${code}`)); | |
| } | |
| try { | |
| const result = await fs.promises.readFile(outputPath); | |
| await this.cleanFile(outputPath); | |
| resolve(result); | |
| } catch (readError) { | |
| reject(readError); | |
| } | |
| }); | |
| ffmpeg.on('error', (err) => { | |
| reject(err); | |
| }); | |
| }); | |
| } catch (err) { | |
| await this.cleanFile(inputPath); | |
| await this.cleanFile(outputPath); | |
| throw err; | |
| } | |
| } | |
| toAudio(buffer, ext) { | |
| return this.convert(buffer, [ | |
| '-vn', | |
| '-ac', '2', | |
| '-b:a', '128k', | |
| '-ar', '44100', | |
| '-f', 'mp3' | |
| ], ext, 'mp3'); | |
| } | |
| toPTT(buffer, ext) { | |
| return this.convert(buffer, [ | |
| '-vn', | |
| '-c:a', 'libopus', | |
| '-b:a', '128k', | |
| '-vbr', 'on', | |
| '-compression_level', '10' | |
| ], ext, 'opus'); | |
| } | |
| } | |
| module.exports = new AudioConverter(); | |