@jubbio/voice
v1.0.9
Published
Voice library for Jubbio bots with LiveKit backend
Maintainers
Readme
Installation
npm install @jubbio/voiceFeatures
- 🎵 Audio Playback - Play local files or stream from URLs
- 📺 YouTube Support - Built-in yt-dlp integration
- 🔊 LiveKit Backend - High-quality, low-latency audio
- ⏯️ Playback Controls - Play, pause, stop, volume
- 📊 Easy Queue Management - Build music bots easily
Quick Start
import { Client, GatewayIntentBits, EmbedBuilder, Colors } from '@jubbio/core';
import {
joinVoiceChannel,
createAudioPlayer,
createAudioResourceFromUrl,
probeAudioInfo,
getVoiceConnection,
AudioPlayerStatus
} from '@jubbio/voice';
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates
]
});
// Store players per guild
const players = new Map();
function getPlayer(guildId) {
let player = players.get(guildId);
if (!player) {
player = createAudioPlayer();
players.set(guildId, player);
}
return player;
}
client.on('interactionCreate', async (interaction) => {
if (!interaction.isCommand()) return;
if (interaction.commandName === 'play') {
const url = interaction.options.getString('url', true);
const voiceChannel = interaction.member?.voice?.channelId;
if (!voiceChannel) {
return interaction.reply('❌ Join a voice channel first!');
}
await interaction.deferReply();
try {
const info = await probeAudioInfo(url);
// Check for existing connection, only join if not connected
let connection = getVoiceConnection(interaction.guildId);
if (!connection) {
connection = joinVoiceChannel({
channelId: voiceChannel,
guildId: interaction.guildId,
adapterCreator: client.voice.adapters.get(interaction.guildId)
});
const player = getPlayer(interaction.guildId);
connection.subscribe(player);
}
const player = getPlayer(interaction.guildId);
const resource = createAudioResourceFromUrl(info.url);
player.play(resource);
const minutes = Math.floor(info.duration / 60);
const seconds = info.duration % 60;
const durationStr = `${minutes}:${seconds.toString().padStart(2, '0')}`;
const embed = new EmbedBuilder()
.setTitle('🎵 Now Playing')
.setDescription(`**${info.title}**`)
.setColor(Colors.Blue)
.addFields({ name: 'Duration', value: durationStr, inline: true })
.setTimestamp();
if (info.thumbnail) {
embed.setThumbnail(info.thumbnail);
}
await interaction.editReply({ embeds: [embed] });
} catch (error) {
await interaction.editReply(`❌ Error: ${error.message}`);
}
}
});
client.login(process.env.BOT_TOKEN);API Reference
joinVoiceChannel(options)
Join a voice channel and return a VoiceConnection.
const connection = joinVoiceChannel({
channelId: '123456789', // Voice channel ID
guildId: '987654321', // Guild ID
adapterCreator: adapter, // From client.voice.adapters
selfMute: false, // Join muted (default: false)
selfDeaf: false // Join deafened (default: false)
});createAudioPlayer(options?)
Create an AudioPlayer instance.
const player = createAudioPlayer({
behaviors: {
noSubscriber: 'pause' // 'pause' | 'play' | 'stop'
}
});createAudioResource(input, options?)
Create an AudioResource from a file path.
const resource = createAudioResource('/path/to/audio.mp3', {
metadata: { title: 'My Song' }
});createAudioResourceFromUrl(url, options?)
Create an AudioResource from a URL (YouTube, SoundCloud, etc.).
const resource = createAudioResourceFromUrl('https://youtube.com/watch?v=...', {
metadata: { title: 'YouTube Video' }
});probeAudioInfo(url)
Get information about an audio URL.
const info = await probeAudioInfo('https://youtube.com/watch?v=...');
console.log(info.title); // Video title
console.log(info.duration); // Duration in seconds
console.log(info.thumbnail); // Thumbnail URLPlayer Controls
// Play
player.play(resource);
// Pause
player.pause();
// Resume
player.unpause();
// Stop
player.stop();
// Check status
if (player.state.status === AudioPlayerStatus.Playing) {
console.log('Currently playing!');
}Connection Controls
// Disconnect
connection.disconnect();
// Destroy (cleanup)
connection.destroy();
// Check status
if (connection.state.status === VoiceConnectionStatus.Ready) {
console.log('Connected!');
}Events
AudioPlayer Events
player.on('stateChange', (oldState, newState) => {
console.log(`${oldState.status} -> ${newState.status}`);
});
player.on('error', (error) => {
console.error('Player error:', error);
});VoiceConnection Events
connection.on('stateChange', (oldState, newState) => {
if (newState.status === VoiceConnectionStatus.Disconnected) {
console.log('Disconnected from voice channel');
}
});
connection.on('error', (error) => {
console.error('Connection error:', error);
});Status Enums
AudioPlayerStatus
| Status | Description |
|--------|-------------|
| Idle | Not playing anything |
| Buffering | Loading audio |
| Playing | Currently playing |
| Paused | Playback paused |
| AutoPaused | Paused (no subscribers) |
VoiceConnectionStatus
| Status | Description |
|--------|-------------|
| Connecting | Establishing connection |
| Ready | Connected and ready |
| Disconnected | Disconnected |
| Destroyed | Connection destroyed |
| Signalling | Exchanging connection info |
Requirements
- Node.js 18.0.0 or higher
- FFmpeg installed and in PATH
- yt-dlp installed (for YouTube support)
Installing Dependencies
# Ubuntu/Debian
sudo apt install ffmpeg
pip install yt-dlp
# macOS
brew install ffmpeg yt-dlp
# Windows
# Download from ffmpeg.org and yt-dlp GitHub releasesLicense
MIT © Jubbio Team
