Skip to content

Full Featured Bot

This example is a production-ready bot covering all Voltricx features: multi-node, caching, autoplay, filters, history, and more.

See the full source on GitHub for the complete code.

Features Demonstrated

  • ✅ Multi-node connection with regions
  • ✅ HyperCache enabled
  • ✅ Default search source
  • ✅ Logger with debug output
  • ✅ Track history & previous track command
  • ✅ All audio filter presets
  • ✅ AutoPlay modes
  • ✅ Queue pagination
  • ✅ Node info & cache inspection
  • ✅ Inactivity timeout handling
  • ✅ Failover event handling

Bot Setup

full_bot.py (setup)
import asyncio, os, discord
from discord.ext import commands
from dotenv import load_dotenv
import voltricx

load_dotenv()

class FullMusicBot(commands.Bot):
    def __init__(self):
        intents = discord.Intents.default()
        intents.message_content = True
        intents.voice_states = True
        super().__init__(command_prefix="!", intents=intents, help_command=None)

    async def setup_hook(self):
        voltricx.voltricx_logger.enable()
        voltricx.voltricx_logger.set_level("INFO")

        nodes = []
        for i in range(1, 10):
            uri = os.getenv(f"NODE_{i}_URI")
            pwd = os.getenv(f"NODE_{i}_PASSWORD")
            region = os.getenv(f"NODE_{i}_REGION", "global")
            if uri and pwd:
                nodes.append(voltricx.NodeConfig(
                    identifier=f"Node-{i}",
                    uri=uri, password=pwd, region=region,
                ))

        await voltricx.Pool.connect(
            client=self,
            nodes=nodes,
            cache_config={"capacity": 100, "track_capacity": 1000},
            default_search_source="dzsearch",
        )

    async def close(self):
        await voltricx.Pool.close()
        await super().close()

Event Handlers

full_bot.py (events)
@bot.event
async def on_voltricx_track_start(player: voltricx.Player, track: voltricx.Playable):
    if player.home:
        await player.home.send(f"🎶 **Started**: {track.title}")

@bot.event
async def on_voltricx_track_end(player, track, reason):
    if player.home and str(reason) == "finished":
        await player.home.send(f"✅ **Finished**: {track.title}")

@bot.event
async def on_voltricx_track_exception(player, track, exception):
    if player.home:
        await player.home.send(f"⚠️ **Error** with {track.title}: `{exception}`")

@bot.event
async def on_voltricx_failover(old_node, new_node, players):
    for player in players:
        if player.home:
            await player.home.send(
                f"🔄 **Failover**: migrated to `{new_node.identifier}`"
            )

@bot.event
async def on_voltricx_inactive_player(player: voltricx.Player):
    if player.home:
        await player.home.send("💤 Leaving due to inactivity.")
    await player.disconnect()

Playback Commands

full_bot.py (playback)
@bot.command(aliases=["p"])
async def play(ctx: commands.Context, *, query: str):
    if not ctx.author.voice:
        return await ctx.send("❌ Join a voice channel!")
    if not ctx.voice_client:
        player: voltricx.Player = await ctx.author.voice.channel.connect(cls=voltricx.Player)
        player.home = ctx.channel
        player.inactive_timeout = 300
    else:
        player: voltricx.Player = ctx.voice_client

    results = await voltricx.Pool.fetch_tracks(query)
    if not results:
        return await ctx.send("❌ No results.")

    if isinstance(results, voltricx.Playlist):
        added = player.queue.put(results)
        await ctx.send(f"📋 Added **{results.name}** ({added} tracks)")
    else:
        track = results[0]
        player.queue.put(track)
        await ctx.send(f"➕ Added **{track.title}**")

    if not player.playing:
        await player.play(player.queue.get(), populate=True)


@bot.command()
async def previous(ctx: commands.Context):
    """Play the previous track."""
    player: voltricx.Player = ctx.voice_client
    if not player or not player.queue.history:
        return await ctx.send("No history.")
    try:
        player.queue.history.pop()
        prev = player.queue.history.pop()
        player.queue.put_at_front(prev)
        await player.skip(force=True)
        await ctx.send(f"⏪ Back to **{prev.title}**")
    except Exception:
        await ctx.send("No previous track.")

Filter Commands

full_bot.py (filters)
FILTER_PRESETS = {
    "nightcore": lambda f: f.timescale.set(speed=1.3, pitch=1.3),
    "vaporwave": lambda f: f.timescale.set(speed=0.8, pitch=0.8),
    "8d":        lambda f: f.rotation.set(rotation_hz=0.2),
    "chipmunk":  lambda f: f.timescale.set(speed=1.0, pitch=1.5),
    "deepvoice": lambda f: f.timescale.set(speed=1.0, pitch=0.6),
    "karaoke":   lambda f: f.karaoke.set(level=1.0, mono_level=1.0),
}

@bot.command()
async def filter(ctx: commands.Context, preset: str):
    """Apply a filter preset."""
    player: voltricx.Player = ctx.voice_client
    if not player:
        return
    preset = preset.lower()
    if preset not in FILTER_PRESETS and preset != "reset":
        return await ctx.send(f"Available: {', '.join(FILTER_PRESETS)} reset")

    filters = player.filters
    if preset == "reset":
        filters = voltricx.Filters()
    else:
        FILTER_PRESETS[preset](filters)

    await player.set_filters(filters)
    await ctx.send(f"🎛️ Filter: **{preset}**")

@bot.command()
async def bassboost(ctx: commands.Context):
    """Toggle bass boost."""
    player: voltricx.Player = ctx.voice_client
    if not player:
        return
    filters = player.filters
    if any(filters.equalizer.payload[i]["gain"] > 0 for i in range(4)):
        filters.equalizer.reset()
        await ctx.send("Bass Boost **OFF**")
    else:
        for i in range(4):
            filters.equalizer.set_band(band=i, gain=0.25)
        await ctx.send("🔊 Bass Boost **ON**")
    await player.set_filters(filters)

System Commands

full_bot.py (system)
@bot.command()
async def nodeinfo(ctx: commands.Context):
    """Show all node stats."""
    nodes = voltricx.Pool.nodes()
    lines = []
    for ident, node in nodes.items():
        icon = "✅" if node.status == voltricx.NodeStatus.connected else "❌"
        cpu = f"{node.stats_cpu.system_load * 100:.1f}%" if node.stats_cpu else "N/A"
        mem = f"{node.stats_memory.used / 1024 / 1024:.1f} MB" if node.stats_memory else "N/A"
        lines.append(f"{icon} **{ident}**: {node.playing_count} players | CPU {cpu} | Mem {mem}")

    embed = discord.Embed(title="🖥️ Node Status", description="\n".join(lines), color=0x7c3aed)
    await ctx.send(embed=embed)

@bot.command()
async def cache(ctx: commands.Context):
    """Show HyperCache stats."""
    stats = voltricx.Pool.get_cache_stats()
    await ctx.send(
        f"🚀 **HyperCache**\n"
        f"• L1 (Queries): `{stats['l1_queries']}`\n"
        f"• L2 (Tracks): `{stats['l2_tracks']}`"
    )

@bot.command()
async def autoplay(ctx: commands.Context, mode: str = "partial"):
    """Set autoplay mode: enabled, partial, disabled."""
    player: voltricx.Player = ctx.voice_client
    if not player:
        return
    try:
        amode = voltricx.AutoPlayMode(mode.lower())
        player.autoplay = amode
        await ctx.send(f"AutoPlay: **{amode.value}**")
    except ValueError:
        await ctx.send("Use: `enabled`, `partial`, or `disabled`")