@boruto_vk7/opus-ogg
v1.3.2
Published
High-performance OGG Opus converter for WhatsApp/Discord — configurable tempDir, FFmpeg source (system/module), optional axios URL downloads, dual CJS/ESM
Downloads
827
Maintainers
Readme
@boruto_vk7/opus-ogg
High-performance OGG Opus conversion for Node.js
WhatsApp voice notes (iOS mono) · Discord.js · dual CJS/ESM · smart FFmpeg detection
Features
| Feature | Detail |
|---|---|
| WhatsApp iOS | Mono OGG Opus (profile: 'voip') — plays on iPhone PTT |
| Discord.js | OggToOpusStream → raw Opus packets (StreamType.Opus) |
| Dual package | require + import + TypeScript types |
| Smart FFmpeg | env → package bin/ → cwd bin/ → system PATH |
| Streaming | Pipe architecture, low memory |
| HTTP(S) input | Follows redirects, works with remote URLs |
| Termux | Use system FFmpeg (pkg install ffmpeg) |
Install
npm i @boruto_vk7/opus-oggRequires FFmpeg with libopus:
# Debian/Ubuntu
sudo apt install ffmpeg
# macOS
brew install ffmpeg
# Termux
pkg install ffmpeg
# Optional: download static binary into package bin/
node node_modules/@boruto_vk7/opus-ogg/scripts/install-ffmpeg.jsOr set a custom path:
export OPUS_OGG_FFMPEG=/usr/bin/ffmpeg
# or
export FFMPEG_PATH=/usr/bin/ffmpegGlobal configuration
Call once at bot startup:
const { configureOpusOgg, getOpusOggConfig } = require('@boruto_vk7/opus-ogg');
configureOpusOgg({
// Temp folder for EngineOggFile (absolute or relative)
tempDir: './tmp/audio',
// FFmpeg source:
// 'system' → PATH/env first, then package bin (default)
// 'module' → package bin/ first, then system
// 'system-only' → never use package bin
// 'module-only' → never use PATH
// '/usr/bin/ffmpeg' → fixed path
ffmpeg: 'system',
// URL downloads:
// 'auto' → axios if installed, else native http(s) (default)
// 'axios' → always axios (npm i axios)
// 'native' → always Node http/https
urlClient: 'auto',
// Passed to axios when used (timeout, proxy, httpsAgent, headers…)
axiosConfig: {
timeout: 60_000
},
urlHeaders: {
// 'Authorization': 'Bearer …'
},
maxRedirects: 5,
// Defaults for every EngineOgg* call (per-call options still win)
defaults: {
profile: 'voip',
forceStereo: false
}
});
console.log(getOpusOggConfig());Per-call overrides:
EngineOgg(url, {
ffmpeg: 'module',
urlClient: 'axios',
urlHeaders: { 'Authorization': 'Bearer x' },
profile: 'voip'
});
// Temp dir only for this file write
await EngineOggFile('id', input, { tempDir: '/tmp/my-ogg' });Optional axios:
npm i axiosQuick start
WhatsApp voice note (Baileys / iOS)
const { EngineOgg, EngineOggBuffer } = require('@boruto_vk7/opus-ogg');
const fs = require('fs');
// Stream
EngineOgg('./voice.mp3', { profile: 'voip', forceStereo: false })
.pipe(fs.createWriteStream('./ptt.ogg'));
// Or buffer (small clips)
const ogg = await EngineOggBuffer('./voice.mp3', { profile: 'voip' });
// sock.sendMessage(jid, { audio: ogg, ptt: true, mimetype: 'audio/ogg; codecs=opus' })Discord.js voice
const { EngineOgg, OggToOpusStream } = require('@boruto_vk7/opus-ogg');
const { createAudioResource, StreamType } = require('@discordjs/voice');
const ogg = EngineOgg('https://example.com/track.mp3', {
profile: 'audio',
forceStereo: true,
bitrate: '128k'
});
const resource = createAudioResource(OggToOpusStream(ogg), {
inputType: StreamType.Opus
});ESM
import { EngineOgg, isFfmpegAvailable } from '@boruto_vk7/opus-ogg';
if (!isFfmpegAvailable()) {
throw new Error('Install FFmpeg first');
}
const stream = EngineOgg('./audio.wav', { profile: 'voip' });Temp file helper
const { EngineOggFile } = require('@boruto_vk7/opus-ogg');
const filePath = await EngineOggFile('msg1', './input.m4a', { profile: 'voip' });
// ... use filePath, then fs.unlinkSync(filePath)Temp files cleanup
const {
configureOpusOgg,
cleanTempDir,
deleteTempFile,
listTempFiles,
EngineOggFile
} = require('@boruto_vk7/opus-ogg');
configureOpusOgg({ tempDir: './tmp/audio' });
// list what's there
console.log(await listTempFiles());
// delete ALL files in tempDir
const r = await cleanTempDir();
console.log(r.deletedFiles.length, 'files,', r.freedBytes, 'bytes freed');
// only .ogg older than 1 hour
await cleanTempDir({
maxAgeMs: 60 * 60 * 1000,
match: '.ogg'
});
// dry-run
await cleanTempDir({ dryRun: true });
// delete one file returned by EngineOggFile
const f = await EngineOggFile('x', './a.mp3');
await deleteTempFile(f);Baileys PTT helper
const { toWhatsAppPtt } = require('@boruto_vk7/opus-ogg');
await sock.sendMessage(jid, await toWhatsAppPtt('./voz.mp3'));
// → { audio: Buffer, ptt: true, mimetype: 'audio/ogg; codecs=opus' }Buffer input also works:
EngineOgg(audioBuffer, { profile: 'voip' })
await EngineOggBuffer(audioBuffer)API
EngineOgg(input, options?) → Readable
| Option | Type | Default | Description |
|---|---|---|---|
| profile | 'voip' \| 'audio' \| 'lowdelay' | 'voip' | libopus application |
| forceStereo | boolean | false | 2 channels (avoid for WA iOS) |
| bitrate | string | 64k / 128k | e.g. 48k, 96k |
| sampleRate | number | 48000 | Hz |
| frameDuration | 2.5…60 | 20 | Opus frame ms |
| ffmpegPath | string | auto | Custom binary |
| extraArgs | string[] | [] | Extra FFmpeg args |
| signal | AbortSignal | — | Cancel conversion |
| highWaterMark | number | 128KiB | Pipe buffer |
input: local path · http(s):// URL · Readable stream
OggToOpusStream(oggReadable) → Readable (objectMode packets)
EngineOggFile(id, input, options?) → Promise<string>
EngineOggBuffer(input, options?) → Promise<Buffer>
resolveFFmpeg() / getFfmpegPath() / isFfmpegAvailable()
OggDemuxer (class)
WhatsApp tips
- Use
profile: 'voip'andforceStereo: false(mono). - Mime:
audio/ogg; codecs=opuswithptt: true. - Prefer converting before upload; keep clips reasonably short.
- Errors from FFmpeg now surface on the stream (
errorevent) — always handle them.
const s = EngineOgg(file, { profile: 'voip' });
s.on('error', console.error);Changelog
1.3.2
cleanTempDir()/deleteTempFile()/listTempFiles()- Buffer/Uint8Array input
toWhatsAppPtt()helper for Baileys
1.3.1
configureOpusOgg({ tempDir, ffmpeg, urlClient, axiosConfig, defaults })- FFmpeg mode:
system|module|system-only|module-only| custom path - URL downloads via axios (optional peer) or native http(s)
getOpusOggConfig(),resolveTempDir(),isAxiosAvailable()
1.3.0
- Fix ESM path resolution (no broken
__dirname) - HTTP redirects followed for URL inputs
- Local files passed to FFmpeg with
-i file(not always pipe) - stderr from FFmpeg propagated as stream errors
AbortSignalsupportEngineOggBuffer,isFfmpegAvailable, richer options- Safer OggDemuxer packet lacing / resync
- Dual package
exports.typesorder fixed postinstallno longer forced (optional script instead)- Keywords + clearer README
License
MIT © eduh_dev021 (Borutovk7)
