Bots

Command routing over REST + Gateway, with voice conveniences
from IPython.display import Audio

import wave
dc = DiscordClient()
gld = await dc.guild('1327046393453613076')
chs = await gld.channels()
vch = chs[3]
intents = (1 << 0) | (1 << 7) | (1 << 9) | (1 << 15) # GUILDS | VOICE_EVENTS | GUILD_MESSAGES | MESSAGE_CONTENT

Bot ties together DiscordClient (REST) and GatewayClient (events) into a single object with a decorator-based command router. Commands are registered with @bot.cmd — the function name becomes the command name, prefixed with ! in Discord. So def echo responds to !echo. Every command handler takes two arguments: the Message object and a string of everything the user typed after the command name (empty string if nothing).

The _on_msg handler ignores messages from the bot itself to prevent infinite loops — a common gotcha with Discord bots. It splits the message into command name + args, so !echo hello world passes "hello world" as the args string to the handler.


source

Bot

def Bot(
    intents, **kw
):

Discord bot with command routing

bot = Bot(intents)
await bot.start()

Commands can be registered at any time — even after bot.start(). This works because @bot.cmd just adds the function to a dict; the message handler looks up commands dynamically on each message.

@bot.cmd
async def echo(msg, args): await (await msg.channel()).send(f'You said: {args}')
bot
Bot(cmds=['echo'])

Errors in command handlers are caught and stored in bot.errors — useful for debugging in dynamic environments like solveit where you can inspect the list after the fact. For real-time handling (e.g. notifying the user in Discord), register a handler with @bot.on_error. Both mechanisms work simultaneously.


source

Bot.on_error

def on_error(
    f
):

Call self as a function.

@bot.on_error
async def handle_err(msg, e): print('error')
@bot.cmd
def err(msg): raise Exception('test')
bot.errors
[]

Voice integration reuses the existing VoiceClientBot just provides convenience methods to manage the lifecycle. The bot can only be in one voice channel at a time.


source

Bot.leave_voice

async def leave_voice():

Leave the current voice channel


source

Bot.join_voice

async def join_voice(
    channel
):

Join a voice channel and return VoiceClient

vc = await bot.join_voice(vch); vc
VoiceClient(self.ch=Channel(id=1327046393453613080, name='General', type=2))
voice json 11 {'user_ids': ['346450717025894400']}
voice json 18 {'user_id': '346450717025894400', 'flags': 2}
voice json 20 {'user_id': '346450717025894400', 'platform': 0}
voice json 15 {'any': 100}
vc.start_recording()
'/tmp/recording.mp3'
pth = vc.stop_recording()
await bot.leave_voice()
# Audio(pth)