How to parse audio files to OGG (OPUS) for telegram bot API

Introduction

When sending playable audio files via the telegram bot API, you must convert them to the required format, specifically the OGG/OGA extension with OPUS codec as the document states, otherwise, there will be issues like the spectrogram won’t be visible or the audio file’s duration will be set to zero (00:00).

To solve this issue, we must convert it and then send it to the user. This will work for any type of audio file since I wanted to convert synthetically generated audio files (TTS) after receiving them from Amazon Polly.

Solution

We will be using the FFMPEG library (NodeJS), the solution will be more or less the same if you’re using any other framework/language.

Install two packages:

npm install fluent-ffmpeg @ffmpeg-installer/ffmpeg -g

Initialize them:

const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;

// Set the path for FFmpeg
ffmpeg.setFfmpegPath(ffmpegPath);

Using the library to OGG-OPUS conversion:

// temporary file path
const oggFilePath = `${ctx.chat.id}.OGG`;
// temporary WAV file path
const wavFilePath = `${Date.now()}.wav`;  

ffmpeg()
// Input format can be of any type mention here
  .input(wavFilePath).inputFormat('wav')
  .on('error', function(err, stdout, stderr) {
    // also show error to the user
    console.log('Cannot process audio: ' + err.message);
   // Deleting the file if error occurs.
    fs.unlinkSync(wavFilePath);
  })
// encoding to OGG - OPUS format, you can also toggle other options from here.
  .outputOptions('-c:a libopus')
  .output(oggFilePath)
  .on('end', () => {
    console.log(`Converted to OGA ${oggFilePath}`);
}).run();

Step-by-step explanation:

  1. const oggFilePath =${ctx.chat.id}.OGG; and const wavFilePath =${Date.now()}.wav; define the paths for the temporary OGG and WAV files.
  2. ffmpeg() initializes the ffmpeg command.
  3. .input(wavFilePath).inputFormat('wav') specifies the input file and its format.
  4. The on('error', function(err, stdout, stderr) {...}) block handles any errors that occur during the process. If an error occurs, it logs the error message, deletes the input file, and sends an error response.
  5. .outputOptions('-c:a libopus') sets the codec to ‘libopus’, which is used for the OPUS format output.
  6. .output(oggFilePath) specifies the output file path.
  7. The on('end', () => {...}) block runs when the conversion process ends. It logs a message indicating the conversion is complete.
  8. .run() executes the ffmpeg command.

Suggested: How to setup webhook for telegram bots

Sending the file to the user

ctx.telegram.sendVoice(ctx.chat.id, {
  source: fs.createReadStream(oggFilePath)
}).then(()=>{
// Deleting the temp files
  fs.unlinkSync(oggFilePath);
  fs.unlinkSync(wavFilePath);
});

Conclusion

Hope you were able to convert your files and send them to your users without any errors, if there are any errors revisit your code. This code/script cannot run on serverless platforms like hop.io, etc. As it requires compute resources to do the processing.

Feel free to reach out on Twitter.