mmm / data /converter.js
ravenbs1's picture
Upload 140 files
046b271 verified
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();