A modern, easy-to-use, feature-rich async-ready API wrapper for Discord written in Python
—
Discord gateway events and event handling system for real-time bot functionality including comprehensive event types, custom event dispatching, event filtering, and gateway connection management for responsive Discord bot applications.
Core event handling infrastructure for Discord gateway events and custom bot events.
@bot.event
async def on_ready():
"""
Called when the bot is ready and connected to Discord.
This event is called once when the bot successfully connects
and is ready to receive events and process commands.
"""
@bot.event
async def on_resumed():
"""
Called when a previously disconnected bot resumes its connection.
"""
@bot.event
async def on_connect():
"""
Called when the bot connects to Discord (before ready).
"""
@bot.event
async def on_disconnect():
"""
Called when the bot disconnects from Discord.
"""
@bot.event
async def on_shard_connect(shard_id: int):
"""
Called when a shard connects to Discord.
Parameters:
- shard_id: ID of the connected shard
"""
@bot.event
async def on_shard_disconnect(shard_id: int):
"""
Called when a shard disconnects from Discord.
Parameters:
- shard_id: ID of the disconnected shard
"""
@bot.event
async def on_shard_ready(shard_id: int):
"""
Called when a shard is ready.
Parameters:
- shard_id: ID of the ready shard
"""
@bot.event
async def on_shard_resumed(shard_id: int):
"""
Called when a shard resumes connection.
Parameters:
- shard_id: ID of the resumed shard
"""
def wait_for(
event: str,
*,
check: Optional[Callable[..., bool]] = None,
timeout: Optional[float] = None
) -> Any:
"""
Wait for a specific event to occur.
Parameters:
- event: Name of the event to wait for
- check: Optional function to check event conditions
- timeout: Maximum time to wait in seconds
Returns:
Event data when the event occurs
Raises:
asyncio.TimeoutError: If timeout is reached
"""
def dispatch(event: str, *args, **kwargs) -> None:
"""
Dispatch a custom event.
Parameters:
- event: Event name (without 'on_' prefix)
- args: Event arguments
- kwargs: Event keyword arguments
"""Events related to message creation, editing, deletion, and reactions.
@bot.event
async def on_message(message: Message):
"""
Called when a message is sent.
Parameters:
- message: The message that was sent
"""
@bot.event
async def on_message_edit(before: Message, after: Message):
"""
Called when a message is edited.
Parameters:
- before: Message before editing
- after: Message after editing
"""
@bot.event
async def on_message_delete(message: Message):
"""
Called when a message is deleted.
Parameters:
- message: The deleted message
"""
@bot.event
async def on_bulk_message_delete(messages: List[Message]):
"""
Called when messages are bulk deleted.
Parameters:
- messages: List of deleted messages
"""
@bot.event
async def on_raw_message_edit(payload: RawMessageUpdateEvent):
"""
Called when a message is edited (raw event).
Parameters:
- payload: Raw message update data
"""
@bot.event
async def on_raw_message_delete(payload: RawMessageDeleteEvent):
"""
Called when a message is deleted (raw event).
Parameters:
- payload: Raw message delete data
"""
@bot.event
async def on_raw_bulk_message_delete(payload: RawBulkMessageDeleteEvent):
"""
Called when messages are bulk deleted (raw event).
Parameters:
- payload: Raw bulk delete data
"""
@bot.event
async def on_reaction_add(reaction: Reaction, user: Union[Member, User]):
"""
Called when a reaction is added to a message.
Parameters:
- reaction: The reaction that was added
- user: User who added the reaction
"""
@bot.event
async def on_reaction_remove(reaction: Reaction, user: Union[Member, User]):
"""
Called when a reaction is removed from a message.
Parameters:
- reaction: The reaction that was removed
- user: User who removed the reaction
"""
@bot.event
async def on_reaction_clear(message: Message, reactions: List[Reaction]):
"""
Called when all reactions are cleared from a message.
Parameters:
- message: Message that had reactions cleared
- reactions: List of reactions that were cleared
"""
@bot.event
async def on_reaction_clear_emoji(reaction: Reaction):
"""
Called when all reactions of a specific emoji are cleared.
Parameters:
- reaction: The reaction that was cleared
"""
@bot.event
async def on_raw_reaction_add(payload: RawReactionActionEvent):
"""
Called when a reaction is added (raw event).
Parameters:
- payload: Raw reaction add data
"""
@bot.event
async def on_raw_reaction_remove(payload: RawReactionActionEvent):
"""
Called when a reaction is removed (raw event).
Parameters:
- payload: Raw reaction remove data
"""
@bot.event
async def on_raw_reaction_clear(payload: RawReactionClearEvent):
"""
Called when reactions are cleared (raw event).
Parameters:
- payload: Raw reaction clear data
"""
@bot.event
async def on_raw_reaction_clear_emoji(payload: RawReactionClearEmojiEvent):
"""
Called when emoji reactions are cleared (raw event).
Parameters:
- payload: Raw emoji clear data
"""Events related to guild member changes, presence updates, and member activity.
@bot.event
async def on_member_join(member: Member):
"""
Called when a member joins a guild.
Parameters:
- member: The member that joined
"""
@bot.event
async def on_member_remove(member: Member):
"""
Called when a member leaves a guild.
Parameters:
- member: The member that left
"""
@bot.event
async def on_member_update(before: Member, after: Member):
"""
Called when a member is updated.
Parameters:
- before: Member before update
- after: Member after update
"""
@bot.event
async def on_user_update(before: User, after: User):
"""
Called when a user updates their profile.
Parameters:
- before: User before update
- after: User after update
"""
@bot.event
async def on_member_ban(guild: Guild, user: Union[User, Member]):
"""
Called when a member is banned from a guild.
Parameters:
- guild: Guild where the ban occurred
- user: User that was banned
"""
@bot.event
async def on_member_unban(guild: Guild, user: User):
"""
Called when a user is unbanned from a guild.
Parameters:
- guild: Guild where the unban occurred
- user: User that was unbanned
"""
@bot.event
async def on_presence_update(before: Member, after: Member):
"""
Called when a member's presence updates.
Parameters:
- before: Member presence before update
- after: Member presence after update
"""
@bot.event
async def on_typing(channel: Messageable, user: Union[User, Member], when: datetime):
"""
Called when someone starts typing.
Parameters:
- channel: Channel where typing started
- user: User who started typing
- when: When typing started
"""Events related to guild changes, channels, roles, and guild-specific features.
@bot.event
async def on_guild_join(guild: Guild):
"""
Called when the bot joins a guild.
Parameters:
- guild: Guild that was joined
"""
@bot.event
async def on_guild_remove(guild: Guild):
"""
Called when the bot leaves or is removed from a guild.
Parameters:
- guild: Guild that was left
"""
@bot.event
async def on_guild_update(before: Guild, after: Guild):
"""
Called when a guild is updated.
Parameters:
- before: Guild before update
- after: Guild after update
"""
@bot.event
async def on_guild_available(guild: Guild):
"""
Called when a guild becomes available.
Parameters:
- guild: Guild that became available
"""
@bot.event
async def on_guild_unavailable(guild: Guild):
"""
Called when a guild becomes unavailable.
Parameters:
- guild: Guild that became unavailable
"""
@bot.event
async def on_guild_channel_create(channel: GuildChannel):
"""
Called when a guild channel is created.
Parameters:
- channel: Channel that was created
"""
@bot.event
async def on_guild_channel_delete(channel: GuildChannel):
"""
Called when a guild channel is deleted.
Parameters:
- channel: Channel that was deleted
"""
@bot.event
async def on_guild_channel_update(before: GuildChannel, after: GuildChannel):
"""
Called when a guild channel is updated.
Parameters:
- before: Channel before update
- after: Channel after update
"""
@bot.event
async def on_guild_channel_pins_update(channel: Union[TextChannel, NewsChannel], last_pin: Optional[datetime]):
"""
Called when channel pins are updated.
Parameters:
- channel: Channel with updated pins
- last_pin: Time of last pinned message
"""
@bot.event
async def on_guild_role_create(role: Role):
"""
Called when a guild role is created.
Parameters:
- role: Role that was created
"""
@bot.event
async def on_guild_role_delete(role: Role):
"""
Called when a guild role is deleted.
Parameters:
- role: Role that was deleted
"""
@bot.event
async def on_guild_role_update(before: Role, after: Role):
"""
Called when a guild role is updated.
Parameters:
- before: Role before update
- after: Role after update
"""
@bot.event
async def on_guild_emojis_update(guild: Guild, before: List[Emoji], after: List[Emoji]):
"""
Called when guild emojis are updated.
Parameters:
- guild: Guild with updated emojis
- before: Emojis before update
- after: Emojis after update
"""
@bot.event
async def on_guild_stickers_update(guild: Guild, before: List[GuildSticker], after: List[GuildSticker]):
"""
Called when guild stickers are updated.
Parameters:
- guild: Guild with updated stickers
- before: Stickers before update
- after: Stickers after update
"""Events related to voice channel activity and voice state changes.
@bot.event
async def on_voice_state_update(member: Member, before: VoiceState, after: VoiceState):
"""
Called when a member's voice state changes.
Parameters:
- member: Member whose voice state changed
- before: Voice state before change
- after: Voice state after change
"""
@bot.event
async def on_stage_instance_create(stage_instance: StageInstance):
"""
Called when a stage instance is created.
Parameters:
- stage_instance: Stage instance that was created
"""
@bot.event
async def on_stage_instance_delete(stage_instance: StageInstance):
"""
Called when a stage instance is deleted.
Parameters:
- stage_instance: Stage instance that was deleted
"""
@bot.event
async def on_stage_instance_update(before: StageInstance, after: StageInstance):
"""
Called when a stage instance is updated.
Parameters:
- before: Stage instance before update
- after: Stage instance after update
"""Events related to application commands, components, and modal interactions.
@bot.event
async def on_interaction(interaction: Interaction):
"""
Called when any interaction is received.
Parameters:
- interaction: The interaction that was received
"""
@bot.event
async def on_application_command(interaction: ApplicationCommandInteraction):
"""
Called when an application command is used.
Parameters:
- interaction: Application command interaction
"""
@bot.event
async def on_message_interaction(interaction: MessageInteraction):
"""
Called when a message component interaction occurs.
Parameters:
- interaction: Message component interaction
"""
@bot.event
async def on_modal_submit(interaction: ModalInteraction):
"""
Called when a modal is submitted.
Parameters:
- interaction: Modal submission interaction
"""
@bot.event
async def on_dropdown(interaction: MessageInteraction):
"""
Called when a dropdown/select menu is used.
Parameters:
- interaction: Dropdown interaction
"""
@bot.event
async def on_button_click(interaction: MessageInteraction):
"""
Called when a button is clicked.
Parameters:
- interaction: Button click interaction
"""
@bot.event
async def on_application_command_error(interaction: ApplicationCommandInteraction, error: Exception):
"""
Called when an application command raises an error.
Parameters:
- interaction: Command interaction that caused error
- error: Exception that was raised
"""Events related to thread creation, updates, and member management.
@bot.event
async def on_thread_create(thread: Thread):
"""
Called when a thread is created.
Parameters:
- thread: Thread that was created
"""
@bot.event
async def on_thread_delete(thread: Thread):
"""
Called when a thread is deleted.
Parameters:
- thread: Thread that was deleted
"""
@bot.event
async def on_thread_update(before: Thread, after: Thread):
"""
Called when a thread is updated.
Parameters:
- before: Thread before update
- after: Thread after update
"""
@bot.event
async def on_thread_member_join(member: ThreadMember):
"""
Called when a member joins a thread.
Parameters:
- member: Thread member that joined
"""
@bot.event
async def on_thread_member_remove(member: ThreadMember):
"""
Called when a member leaves a thread.
Parameters:
- member: Thread member that left
"""
@bot.event
async def on_raw_thread_update(payload: RawThreadUpdateEvent):
"""
Called when a thread is updated (raw event).
Parameters:
- payload: Raw thread update data
"""
@bot.event
async def on_raw_thread_delete(payload: RawThreadDeleteEvent):
"""
Called when a thread is deleted (raw event).
Parameters:
- payload: Raw thread delete data
"""Events related to guild scheduled events and event management.
@bot.event
async def on_scheduled_event_create(event: GuildScheduledEvent):
"""
Called when a scheduled event is created.
Parameters:
- event: Scheduled event that was created
"""
@bot.event
async def on_scheduled_event_delete(event: GuildScheduledEvent):
"""
Called when a scheduled event is deleted.
Parameters:
- event: Scheduled event that was deleted
"""
@bot.event
async def on_scheduled_event_update(before: GuildScheduledEvent, after: GuildScheduledEvent):
"""
Called when a scheduled event is updated.
Parameters:
- before: Event before update
- after: Event after update
"""
@bot.event
async def on_scheduled_event_user_add(event: GuildScheduledEvent, user: User):
"""
Called when a user subscribes to a scheduled event.
Parameters:
- event: Scheduled event
- user: User that subscribed
"""
@bot.event
async def on_scheduled_event_user_remove(event: GuildScheduledEvent, user: User):
"""
Called when a user unsubscribes from a scheduled event.
Parameters:
- event: Scheduled event
- user: User that unsubscribed
"""Raw gateway events for handling events without cached objects.
class RawMessageUpdateEvent:
"""Raw message update event data."""
message_id: int
channel_id: int
guild_id: Optional[int]
data: Dict[str, Any]
class RawMessageDeleteEvent:
"""Raw message delete event data."""
message_id: int
channel_id: int
guild_id: Optional[int]
class RawBulkMessageDeleteEvent:
"""Raw bulk message delete event data."""
message_ids: List[int]
channel_id: int
guild_id: Optional[int]
class RawReactionActionEvent:
"""Raw reaction add/remove event data."""
message_id: int
channel_id: int
guild_id: Optional[int]
user_id: int
emoji: PartialEmoji
member: Optional[Member]
class RawReactionClearEvent:
"""Raw reaction clear event data."""
message_id: int
channel_id: int
guild_id: Optional[int]
class RawReactionClearEmojiEvent:
"""Raw emoji reaction clear event data."""
message_id: int
channel_id: int
guild_id: Optional[int]
emoji: PartialEmoji
class RawThreadUpdateEvent:
"""Raw thread update event data."""
thread_id: int
guild_id: int
parent_id: int
data: Dict[str, Any]
class RawThreadDeleteEvent:
"""Raw thread delete event data."""
thread_id: int
guild_id: int
parent_id: int
thread_type: ChannelTypeGateway connection management and configuration for Discord real-time events.
class GatewayParams:
"""Gateway connection parameters."""
def __init__(self): ...
url: str
shard_id: Optional[int]
shard_count: Optional[int]
session_start_limit: SessionStartLimit
class SessionStartLimit:
"""Gateway session start limit information."""
def __init__(self): ...
total: int
remaining: int
reset_after: int
max_concurrency: int
class Intents:
"""Gateway intents bitfield."""
def __init__(self, **kwargs): ...
@classmethod
def default(cls) -> Intents:
"""Default intents (recommended for most bots)."""
@classmethod
def all(cls) -> Intents:
"""All intents (requires privileged intents approval)."""
@classmethod
def none(cls) -> Intents:
"""No intents enabled."""
# Privileged intents (require approval)
@property
def presences(self) -> bool:
"""Presence update intents."""
@property
def members(self) -> bool:
"""Member update intents."""
@property
def message_content(self) -> bool:
"""Message content intents."""
# Non-privileged intents
@property
def guilds(self) -> bool:
"""Guild-related events."""
@property
def guild_messages(self) -> bool:
"""Guild message events."""
@property
def guild_reactions(self) -> bool:
"""Guild reaction events."""
@property
def guild_typing(self) -> bool:
"""Guild typing events."""
@property
def direct_messages(self) -> bool:
"""Direct message events."""
@property
def direct_message_reactions(self) -> bool:
"""DM reaction events."""
@property
def direct_message_typing(self) -> bool:
"""DM typing events."""
@property
def guild_integrations(self) -> bool:
"""Guild integration events."""
@property
def guild_webhooks(self) -> bool:
"""Guild webhook events."""
@property
def guild_invites(self) -> bool:
"""Guild invite events."""
@property
def guild_voice_states(self) -> bool:
"""Voice state events."""
@property
def guild_scheduled_events(self) -> bool:
"""Scheduled event intents."""
@property
def auto_moderation_configuration(self) -> bool:
"""AutoMod configuration events."""
@property
def auto_moderation_execution(self) -> bool:
"""AutoMod execution events."""import disnake
from disnake.ext import commands
# Set up intents
intents = disnake.Intents.default()
intents.message_content = True
intents.members = True
intents.presences = True
bot = commands.Bot(command_prefix='!', intents=intents)
@bot.event
async def on_ready():
print(f'Bot is ready! Logged in as {bot.user}')
print(f'Connected to {len(bot.guilds)} guilds')
print(f'Serving {len(bot.users)} users')
# Set bot activity
await bot.change_presence(
status=disnake.Status.online,
activity=disnake.Game(name="Managing the server!")
)
@bot.event
async def on_guild_join(guild):
"""Welcome message when bot joins a server."""
print(f'Joined new guild: {guild.name} (ID: {guild.id})')
# Send welcome message to system channel
if guild.system_channel and guild.system_channel.permissions_for(guild.me).send_messages:
embed = disnake.Embed(
title="Thanks for adding me!",
description="Use `!help` to see available commands.",
color=0x00ff00
)
embed.set_thumbnail(url=bot.user.display_avatar.url)
await guild.system_channel.send(embed=embed)
@bot.event
async def on_guild_remove(guild):
"""Log when bot leaves a server."""
print(f'Left guild: {guild.name} (ID: {guild.id})')
@bot.event
async def on_message(message):
"""Process messages and auto-responses."""
# Ignore bot messages
if message.author.bot:
return
# Auto-react to certain messages
if 'good bot' in message.content.lower():
await message.add_reaction('😊')
elif 'bad bot' in message.content.lower():
await message.add_reaction('😢')
# Process commands
await bot.process_commands(message)
@bot.event
async def on_message_edit(before, after):
"""Log message edits."""
if before.author.bot or before.content == after.content:
return
print(f'Message edited in {before.channel}:')
print(f'Before: {before.content}')
print(f'After: {after.content}')
@bot.event
async def on_message_delete(message):
"""Log message deletions."""
if message.author.bot:
return
print(f'Message deleted in {message.channel}: {message.content}')
bot.run('YOUR_BOT_TOKEN')@bot.event
async def on_member_join(member):
"""Welcome new members."""
guild = member.guild
# Create welcome embed
embed = disnake.Embed(
title=f"Welcome to {guild.name}!",
description=f"Hello {member.mention}, welcome to our community!",
color=0x00ff00
)
embed.set_thumbnail(url=member.display_avatar.url)
embed.add_field(name="Member Count", value=f"You're member #{guild.member_count}!", inline=False)
embed.add_field(name="Account Created", value=f"<t:{int(member.created_at.timestamp())}:F>", inline=True)
embed.set_footer(text=f"User ID: {member.id}")
# Send to welcome channel
welcome_channel = disnake.utils.get(guild.channels, name='welcome')
if welcome_channel:
await welcome_channel.send(embed=embed)
# Auto-role assignment
auto_role = disnake.utils.get(guild.roles, name='Member')
if auto_role:
try:
await member.add_roles(auto_role, reason="Auto-role on join")
except disnake.Forbidden:
print(f"Cannot assign auto-role in {guild.name}")
# Send DM welcome message
try:
dm_embed = disnake.Embed(
title=f"Welcome to {guild.name}!",
description="Thanks for joining! Here are some helpful tips:",
color=0x00ff00
)
dm_embed.add_field(
name="Getting Started",
value="• Read the rules in #rules\n• Introduce yourself in #introductions\n• Use `!help` to see bot commands",
inline=False
)
await member.send(embed=dm_embed)
except disnake.Forbidden:
pass # User has DMs disabled
@bot.event
async def on_member_remove(member):
"""Log member departures."""
guild = member.guild
# Log to departure channel
log_channel = disnake.utils.get(guild.channels, name='member-logs')
if log_channel:
embed = disnake.Embed(
title="Member Left",
description=f"{member} ({member.id}) has left the server",
color=0xff0000,
timestamp=disnake.utils.utcnow()
)
embed.set_thumbnail(url=member.display_avatar.url)
embed.add_field(name="Joined", value=f"<t:{int(member.joined_at.timestamp())}:F>" if member.joined_at else "Unknown", inline=True)
embed.add_field(name="Member Count", value=f"{guild.member_count} members remaining", inline=True)
if member.roles[1:]: # Exclude @everyone
roles = [role.name for role in member.roles[1:]]
embed.add_field(name="Roles", value=", ".join(roles), inline=False)
await log_channel.send(embed=embed)
@bot.event
async def on_member_update(before, after):
"""Track member changes."""
# Nickname changes
if before.nick != after.nick:
log_channel = disnake.utils.get(after.guild.channels, name='member-logs')
if log_channel:
embed = disnake.Embed(
title="Nickname Changed",
color=0x0099ff,
timestamp=disnake.utils.utcnow()
)
embed.add_field(name="Member", value=after.mention, inline=True)
embed.add_field(name="Before", value=before.display_name, inline=True)
embed.add_field(name="After", value=after.display_name, inline=True)
await log_channel.send(embed=embed)
# Role changes
if before.roles != after.roles:
added_roles = set(after.roles) - set(before.roles)
removed_roles = set(before.roles) - set(after.roles)
if added_roles or removed_roles:
log_channel = disnake.utils.get(after.guild.channels, name='member-logs')
if log_channel:
embed = disnake.Embed(
title="Roles Updated",
color=0x0099ff,
timestamp=disnake.utils.utcnow()
)
embed.add_field(name="Member", value=after.mention, inline=False)
if added_roles:
embed.add_field(name="Roles Added", value=", ".join([role.name for role in added_roles]), inline=False)
if removed_roles:
embed.add_field(name="Roles Removed", value=", ".join([role.name for role in removed_roles]), inline=False)
await log_channel.send(embed=embed)
@bot.event
async def on_member_ban(guild, user):
"""Log member bans."""
log_channel = disnake.utils.get(guild.channels, name='moderation-logs')
if log_channel:
embed = disnake.Embed(
title="Member Banned",
description=f"{user} ({user.id}) was banned",
color=0xff0000,
timestamp=disnake.utils.utcnow()
)
embed.set_thumbnail(url=user.display_avatar.url)
# Try to get ban reason from audit logs
try:
async for entry in guild.audit_logs(limit=1, action=disnake.AuditLogAction.ban):
if entry.target.id == user.id:
embed.add_field(name="Reason", value=entry.reason or "No reason provided", inline=False)
embed.add_field(name="Moderator", value=entry.user.mention, inline=True)
break
except disnake.Forbidden:
pass
await log_channel.send(embed=embed)
@bot.event
async def on_member_unban(guild, user):
"""Log member unbans."""
log_channel = disnake.utils.get(guild.channels, name='moderation-logs')
if log_channel:
embed = disnake.Embed(
title="Member Unbanned",
description=f"{user} ({user.id}) was unbanned",
color=0x00ff00,
timestamp=disnake.utils.utcnow()
)
embed.set_thumbnail(url=user.display_avatar.url)
await log_channel.send(embed=embed)@bot.event
async def on_voice_state_update(member, before, after):
"""Track voice channel activity."""
# Member joined a voice channel
if before.channel is None and after.channel is not None:
log_channel = disnake.utils.get(member.guild.channels, name='voice-logs')
if log_channel:
embed = disnake.Embed(
title="Voice Channel Joined",
description=f"{member.mention} joined {after.channel.mention}",
color=0x00ff00,
timestamp=disnake.utils.utcnow()
)
await log_channel.send(embed=embed)
# Member left a voice channel
elif before.channel is not None and after.channel is None:
log_channel = disnake.utils.get(member.guild.channels, name='voice-logs')
if log_channel:
embed = disnake.Embed(
title="Voice Channel Left",
description=f"{member.mention} left {before.channel.mention}",
color=0xff0000,
timestamp=disnake.utils.utcnow()
)
await log_channel.send(embed=embed)
# Member switched voice channels
elif before.channel is not None and after.channel is not None and before.channel != after.channel:
log_channel = disnake.utils.get(member.guild.channels, name='voice-logs')
if log_channel:
embed = disnake.Embed(
title="Voice Channel Switched",
description=f"{member.mention} moved from {before.channel.mention} to {after.channel.mention}",
color=0x0099ff,
timestamp=disnake.utils.utcnow()
)
await log_channel.send(embed=embed)
# Voice state changes (mute, deafen, etc.)
changes = []
if before.self_mute != after.self_mute:
changes.append(f"Self Mute: {after.self_mute}")
if before.self_deaf != after.self_deaf:
changes.append(f"Self Deafen: {after.self_deaf}")
if before.mute != after.mute:
changes.append(f"Server Mute: {after.mute}")
if before.deaf != after.deaf:
changes.append(f"Server Deafen: {after.deaf}")
if changes and after.channel:
log_channel = disnake.utils.get(member.guild.channels, name='voice-logs')
if log_channel:
embed = disnake.Embed(
title="Voice State Changed",
description=f"{member.mention} in {after.channel.mention}:\n" + "\n".join(changes),
color=0xffa500,
timestamp=disnake.utils.utcnow()
)
await log_channel.send(embed=embed)# Custom events using dispatch
@bot.event
async def on_level_up(member, old_level, new_level):
"""Custom event for level system."""
channel = disnake.utils.get(member.guild.channels, name='general')
if channel:
embed = disnake.Embed(
title="Level Up!",
description=f"{member.mention} reached level {new_level}!",
color=0xffd700
)
embed.set_thumbnail(url=member.display_avatar.url)
await channel.send(embed=embed)
# Dispatch custom events
def check_level_up(member, xp):
old_level = calculate_level(member.old_xp) # Your level calculation
new_level = calculate_level(xp)
if new_level > old_level:
bot.dispatch('level_up', member, old_level, new_level)
# Event filtering and conditions
@bot.event
async def on_message(message):
# Only process messages in specific channels
if message.channel.name not in ['general', 'bot-commands']:
return
# Ignore bot messages
if message.author.bot:
return
# Custom processing
await process_xp(message.author, 10) # Give XP
await bot.process_commands(message)
# Wait for specific events
async def wait_for_confirmation(ctx, timeout=30):
"""Wait for user confirmation."""
def check(reaction, user):
return (user == ctx.author and
str(reaction.emoji) in ['✅', '❌'] and
reaction.message.id == ctx.message.id)
try:
reaction, user = await bot.wait_for('reaction_add', timeout=timeout, check=check)
return str(reaction.emoji) == '✅'
except asyncio.TimeoutError:
return False
# Advanced event handling with error recovery
@bot.event
async def on_error(event, *args, **kwargs):
"""Handle errors in event handlers."""
import traceback
print(f'Error in event {event}:')
traceback.print_exc()
# Log to error channel
error_channel = bot.get_channel(ERROR_CHANNEL_ID)
if error_channel:
error_embed = disnake.Embed(
title=f"Error in {event}",
description=f"```py\n{traceback.format_exc()[:1900]}\n```",
color=0xff0000,
timestamp=disnake.utils.utcnow()
)
await error_channel.send(embed=error_embed)
# Rate limiting and event throttling
from collections import defaultdict, deque
import time
event_buckets = defaultdict(lambda: deque())
async def throttled_event_handler(event_name, handler, *args, **kwargs):
"""Throttle event handlers to prevent spam."""
now = time.time()
bucket = event_buckets[event_name]
# Remove old entries (older than 1 minute)
while bucket and bucket[0] < now - 60:
bucket.popleft()
# Check rate limit (max 10 events per minute)
if len(bucket) >= 10:
print(f"Rate limited event: {event_name}")
return
bucket.append(now)
await handler(*args, **kwargs)import disnake
import asyncio
# Custom gateway configuration
class CustomBot(disnake.Client):
def __init__(self, **kwargs):
# Configure intents
intents = disnake.Intents.default()
intents.message_content = True
intents.members = True
intents.presences = True
super().__init__(
intents=intents,
heartbeat_timeout=60.0,
guild_ready_timeout=2.0,
max_messages=1000,
**kwargs
)
async def on_connect(self):
"""Called when bot connects to gateway."""
print("Connected to Discord gateway")
async def on_disconnect(self):
"""Called when bot disconnects from gateway."""
print("Disconnected from Discord gateway")
async def on_resumed(self):
"""Called when connection is resumed."""
print("Connection resumed")
async def setup_hook(self):
"""Called during bot setup."""
print("Setting up bot...")
# Add any async setup code here
# Sync commands on startup
if hasattr(self, 'sync_commands'):
await self.sync_commands()
# Connection retry logic
async def run_bot_with_retry(bot, token, max_retries=5):
"""Run bot with automatic reconnection."""
for attempt in range(max_retries):
try:
await bot.start(token)
break
except (disnake.ConnectionClosed, disnake.GatewayNotFound) as e:
print(f"Connection failed (attempt {attempt + 1}/{max_retries}): {e}")
if attempt < max_retries - 1:
wait_time = 2 ** attempt # Exponential backoff
print(f"Retrying in {wait_time} seconds...")
await asyncio.sleep(wait_time)
else:
print("Max retries exceeded. Bot failed to connect.")
raise
# Shard-aware event handling
class ShardedBot(commands.AutoShardedBot):
def __init__(self, **kwargs):
super().__init__(**kwargs)
async def on_shard_connect(self, shard_id):
print(f"Shard {shard_id} connected")
async def on_shard_disconnect(self, shard_id):
print(f"Shard {shard_id} disconnected")
async def on_shard_ready(self, shard_id):
print(f"Shard {shard_id} is ready")
shard = self.get_shard(shard_id)
print(f"Shard {shard_id} latency: {shard.latency * 1000:.2f}ms")
async def on_shard_resumed(self, shard_id):
print(f"Shard {shard_id} resumed connection")
# Usage
if __name__ == "__main__":
bot = CustomBot()
# Run with retry logic
asyncio.run(run_bot_with_retry(bot, 'YOUR_BOT_TOKEN'))Install with Tessl CLI
npx tessl i tessl/pypi-disnake