CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-disnake

A modern, easy-to-use, feature-rich async-ready API wrapper for Discord written in Python

Pending
Overview
Eval results
Files

users-members.mddocs/

Users and Members

User and member objects representing Discord users and guild members with comprehensive profile information, permissions, voice states, and user-specific operations including member management and user data access.

Capabilities

User Objects

Basic Discord user representation with profile information and account details.

class User:
    def __init__(self): ...

    id: int
    name: str
    discriminator: str
    avatar: Optional[Asset]
    banner: Optional[Asset]
    accent_color: Optional[Colour]
    accent_colour: Optional[Colour]
    bot: bool
    system: bool
    public_flags: PublicUserFlags
    avatar_decoration: Optional[Asset]
    clan: Optional[UserClan]

    @property
    def display_name(self) -> str:
        """User's display name (global name or username)."""

    @property
    def global_name(self) -> Optional[str]:
        """User's global display name."""

    @property
    def mention(self) -> str:
        """String to mention the user."""

    @property
    def display_avatar(self) -> Asset:
        """User's display avatar (avatar or default)."""

    @property
    def default_avatar(self) -> Asset:
        """User's default avatar."""

    @property
    def avatar_decoration_sku_id(self) -> Optional[int]:
        """Avatar decoration SKU ID."""

    def mentioned_in(self, message: Message) -> bool:
        """
        Check if user is mentioned in a message.
        
        Parameters:
        - message: Message to check
        
        Returns:
        True if user is mentioned
        """

    async def create_dm(self) -> DMChannel:
        """
        Create a DM channel with this user.
        
        Returns:
        DM channel object
        """

    def dm_channel(self) -> Optional[DMChannel]:
        """
        Get cached DM channel with this user.
        
        Returns:
        DM channel if cached
        """

    async def send(
        self,
        content: Optional[str] = None,
        *,
        tts: bool = False,
        embed: Optional[Embed] = None,
        embeds: Optional[List[Embed]] = None,
        file: Optional[File] = None,
        files: Optional[List[File]] = None,
        allowed_mentions: Optional[AllowedMentions] = None,
        reference: Optional[Union[Message, MessageReference, PartialMessage]] = None,
        mention_author: Optional[bool] = None,
        view: Optional[View] = None,
        components: Optional[Union[ActionRow, List[ActionRow], List[List[Component]], List[Component]]] = None,
        delete_after: Optional[float] = None,
        suppress_embeds: bool = False,
        flags: Optional[MessageFlags] = None
    ) -> Message:
        """
        Send a direct message to this user.
        
        Parameters:
        - content: Message text content
        - tts: Whether message should be read with text-to-speech
        - embed: Single embed to include
        - embeds: List of embeds to include (max 10)
        - file: Single file to attach
        - files: List of files to attach (max 10)
        - allowed_mentions: Controls @ mentions in the message
        - reference: Message to reply to
        - mention_author: Whether to mention the author when replying
        - view: UI components view
        - components: Raw components to include
        - delete_after: Seconds after which to delete the message
        - suppress_embeds: Whether to suppress embeds
        - flags: Message flags
        
        Returns:
        The sent message
        """

    async def mutual_guilds(self) -> List[Guild]:
        """
        Get guilds shared with the bot.
        
        Returns:
        List of mutual guilds
        """

    def is_friend(self) -> bool:
        """
        Check if user is friends with the bot.
        
        Returns:
        True if friends
        """

    def is_blocked(self) -> bool:
        """
        Check if user is blocked by the bot.
        
        Returns:
        True if blocked
        """

    async def profile(self) -> UserProfile:
        """
        Fetch user's full profile.
        
        Returns:
        User profile with additional information
        """

Client User

Special user object representing the bot's own user account with additional capabilities.

class ClientUser(User):
    def __init__(self): ...

    verified: bool
    locale: Optional[str]
    mfa_enabled: bool

    async def edit(
        self,
        *,
        username: str = ...,
        avatar: Optional[bytes] = ...,
        banner: Optional[bytes] = ...
    ) -> ClientUser:
        """
        Edit the bot's profile.
        
        Parameters:
        - username: New username
        - avatar: New avatar bytes
        - banner: New banner bytes
        
        Returns:
        Updated client user
        """

Member Objects

Guild member representation extending user with guild-specific information and capabilities.

class Member(User):
    def __init__(self): ...

    guild: Guild
    joined_at: Optional[datetime]
    premium_since: Optional[datetime]
    roles: List[Role]
    activities: List[Activity]
    status: Status
    raw_status: str
    mobile_status: Status
    desktop_status: Status
    web_status: Status
    nick: Optional[str]
    pending: bool
    timed_out_until: Optional[datetime]
    flags: MemberFlags
    avatar: Optional[Asset]
    banner: Optional[Asset]
    communication_disabled_until: Optional[datetime]

    @property
    def display_name(self) -> str:
        """Member's display name (nick, global name, or username)."""

    @property
    def mention(self) -> str:
        """String to mention the member."""

    @property
    def display_avatar(self) -> Asset:
        """Member's display avatar (guild avatar, user avatar, or default)."""

    @property
    def guild_avatar(self) -> Optional[Asset]:
        """Member's guild-specific avatar."""

    @property
    def activity(self) -> Optional[Activity]:
        """Member's primary activity."""

    @property
    def colour(self) -> Colour:
        """Member's role color."""

    @property
    def color(self) -> Colour:
        """Member's role color (alias)."""

    @property
    def top_role(self) -> Role:
        """Member's highest role."""

    @property
    def guild_permissions(self) -> Permissions:
        """Member's guild-wide permissions."""

    @property
    def voice(self) -> Optional[VoiceState]:
        """Member's voice state."""

    def permissions_in(self, channel: GuildChannel) -> Permissions:
        """
        Get member's permissions in a specific channel.
        
        Parameters:
        - channel: Guild channel
        
        Returns:
        Permissions in the channel
        """

    async def add_roles(
        self,
        *roles: Role,
        reason: Optional[str] = None,
        atomic: bool = True
    ) -> None:
        """
        Add roles to the member.
        
        Parameters:
        - roles: Roles to add
        - reason: Audit log reason
        - atomic: Whether to add all roles in single API call
        """

    async def remove_roles(
        self,
        *roles: Role,
        reason: Optional[str] = None,
        atomic: bool = True
    ) -> None:
        """
        Remove roles from the member.
        
        Parameters:
        - roles: Roles to remove
        - reason: Audit log reason
        - atomic: Whether to remove all roles in single API call
        """

    async def edit(
        self,
        *,
        nick: Optional[str] = ...,
        mute: bool = ...,
        deafen: bool = ...,
        suppress: bool = ...,
        roles: List[Role] = ...,
        voice_channel: Optional[VoiceChannel] = ...,
        reason: Optional[str] = None,
        timed_out_until: Optional[Union[datetime, float]] = ...,
        communication_disabled_until: Optional[Union[datetime, float]] = ...,
        flags: MemberFlags = ...
    ) -> Member:
        """
        Edit the member.
        
        Parameters:
        - nick: New nickname (None to remove)
        - mute: Whether to server mute in voice
        - deafen: Whether to server deafen in voice
        - suppress: Whether to suppress in stage channel
        - roles: New role list (replaces current roles)
        - voice_channel: Voice channel to move to
        - reason: Audit log reason
        - timed_out_until: Timeout duration
        - communication_disabled_until: Communication timeout
        - flags: Member flags
        
        Returns:
        Updated member
        """

    async def timeout(
        self,
        duration: Optional[Union[float, datetime, timedelta]] = None,
        *,
        reason: Optional[str] = None
    ) -> Member:
        """
        Timeout the member.
        
        Parameters:
        - duration: Timeout duration (None to remove timeout)
        - reason: Audit log reason
        
        Returns:
        Updated member
        """

    async def kick(self, *, reason: Optional[str] = None) -> None:
        """
        Kick the member from the guild.
        
        Parameters:
        - reason: Audit log reason
        """

    async def ban(
        self,
        *,
        reason: Optional[str] = None,
        delete_message_days: int = 1,
        delete_message_seconds: Optional[int] = None
    ) -> None:
        """
        Ban the member from the guild.
        
        Parameters:
        - reason: Audit log reason
        - delete_message_days: Days of messages to delete (deprecated)
        - delete_message_seconds: Seconds of messages to delete
        """

    async def unban(self, *, reason: Optional[str] = None) -> None:
        """
        Unban the member.
        
        Parameters:
        - reason: Audit log reason
        """

    async def move_to(self, channel: Optional[VoiceChannel], *, reason: Optional[str] = None) -> None:
        """
        Move member to a voice channel.
        
        Parameters:
        - channel: Voice channel to move to (None to disconnect)
        - reason: Audit log reason
        """

    async def request_to_speak(self) -> None:
        """Request to speak in a stage channel."""

    async def fetch_message(self, id: int) -> Message:
        """
        Fetch a message sent by this member.
        
        Parameters:
        - id: Message ID
        
        Returns:
        Message object
        """

    def mentioned_in(self, message: Message) -> bool:
        """
        Check if member is mentioned in a message.
        
        Parameters:
        - message: Message to check
        
        Returns:
        True if member is mentioned
        """

    def is_timed_out(self) -> bool:
        """
        Check if member is currently timed out.
        
        Returns:
        True if timed out
        """

    def is_on_mobile(self) -> bool:
        """
        Check if member is on mobile.
        
        Returns:
        True if on mobile
        """

Voice States

Member voice connection and activity information.

class VoiceState:
    def __init__(self): ...

    session_id: str
    channel: Optional[Union[VoiceChannel, StageChannel]]
    user_id: int
    member: Optional[Member]
    deaf: bool
    mute: bool
    self_deaf: bool
    self_mute: bool
    self_stream: bool
    self_video: bool
    suppress: bool
    requested_to_speak_at: Optional[datetime]

    @property
    def guild(self) -> Optional[Guild]:
        """Guild the voice state is in."""

    @property
    def user(self) -> Optional[User]:
        """User the voice state belongs to."""

    def is_afk(self) -> bool:
        """
        Check if user is in AFK channel.
        
        Returns:
        True if in AFK channel
        """

User Profiles

Extended user information available through profile fetching.

class UserProfile:
    def __init__(self): ...

    user: User
    connected_accounts: List[ConnectedAccount]
    premium_since: Optional[datetime]
    premium_type: Optional[PremiumType]
    nitro_subscription: Optional[NitroSubscription]
    mutual_guilds: List[PartialGuild]
    mutual_friends: List[User]
    premium_guild_since: Optional[datetime]
    legacy_username: Optional[str]

    @property
    def nitro(self) -> bool:
        """Whether user has Nitro subscription."""

    @property
    def hypesquad(self) -> Optional[HypeSquadHouse]:
        """User's HypeSquad house."""

Activity Objects

User activity and presence information including games, streaming, and custom status.

class Activity:
    def __init__(self): ...

    type: ActivityType
    name: str
    url: Optional[str]
    created_at: datetime
    timestamps: Optional[ActivityTimestamps]
    application_id: Optional[int]
    details: Optional[str]
    state: Optional[str]
    emoji: Optional[PartialEmoji]
    party: Optional[ActivityParty]
    assets: Optional[ActivityAssets]
    secrets: Optional[ActivitySecrets]
    instance: bool
    flags: Optional[ActivityFlags]
    buttons: List[str]

    @property
    def start(self) -> Optional[datetime]:
        """Activity start time."""

    @property
    def end(self) -> Optional[datetime]:
        """Activity end time."""

class Game(Activity):
    """Gaming activity."""

    def __init__(self, name: str):
        """
        Initialize a game activity.
        
        Parameters:
        - name: Game name
        """

class Streaming(Activity):
    """Streaming activity."""

    def __init__(self, *, name: str, url: str):
        """
        Initialize a streaming activity.
        
        Parameters:
        - name: Stream title
        - url: Stream URL
        """

    @property
    def twitch_name(self) -> Optional[str]:
        """Twitch channel name."""

class CustomActivity(Activity):
    """Custom status activity."""

    def __init__(self, name: str, *, emoji: Optional[Union[str, Emoji, PartialEmoji]] = None):
        """
        Initialize a custom activity.
        
        Parameters:
        - name: Status text
        - emoji: Status emoji
        """

Relationships and Connections

User relationship and external account connection information.

class Relationship:
    def __init__(self): ...

    user: User
    type: RelationshipType
    nickname: Optional[str]
    since: Optional[datetime]

class ConnectedAccount:
    def __init__(self): ...

    id: str
    name: str
    type: str
    revoked: bool
    integrations: List[Integration]
    verified: bool
    friend_sync: bool
    show_activity: bool
    visibility: int

Member Flags and Properties

Member-specific flags and configuration options.

class MemberFlags:
    """Member flags bitfield."""

    def __init__(self, value: int = 0): ...

    @classmethod
    def none(cls) -> MemberFlags:
        """No flags set."""

    @classmethod
    def all(cls) -> MemberFlags:
        """All flags set."""

    @property
    def did_rejoin(self) -> bool:
        """Whether member rejoined the guild."""

    @property
    def completed_onboarding(self) -> bool:
        """Whether member completed onboarding."""

    @property
    def bypasses_verification(self) -> bool:
        """Whether member bypasses verification."""

    @property
    def started_onboarding(self) -> bool:
        """Whether member started onboarding."""

class PublicUserFlags:
    """Public user flags bitfield."""

    def __init__(self, value: int = 0): ...

    @property
    def staff(self) -> bool:
        """Discord Staff."""

    @property
    def partner(self) -> bool:
        """Discord Partner."""

    @property
    def hypesquad(self) -> bool:
        """HypeSquad Events."""

    @property
    def bug_hunter(self) -> bool:
        """Bug Hunter Level 1."""

    @property
    def hypesquad_bravery(self) -> bool:
        """HypeSquad Bravery."""

    @property
    def hypesquad_brilliance(self) -> bool:
        """HypeSquad Brilliance."""

    @property
    def hypesquad_balance(self) -> bool:
        """HypeSquad Balance."""

    @property
    def early_supporter(self) -> bool:
        """Early Supporter."""

    @property
    def bug_hunter_level_2(self) -> bool:
        """Bug Hunter Level 2."""

    @property
    def verified_bot(self) -> bool:
        """Verified Bot."""

    @property
    def verified_developer(self) -> bool:
        """Verified Bot Developer."""

    @property
    def certified_moderator(self) -> bool:
        """Discord Certified Moderator."""

    @property
    def bot_http_interactions(self) -> bool:
        """Bot uses HTTP interactions."""

    @property
    def active_developer(self) -> bool:
        """Active Developer."""

Usage Examples

User Information Commands

import disnake
from disnake.ext import commands

bot = commands.Bot(command_prefix='!', intents=disnake.Intents.all())

@bot.command()
async def userinfo(ctx, user: disnake.User = None):
    """Display user information."""
    if user is None:
        user = ctx.author
    
    embed = disnake.Embed(title=f"User Information", color=0x00ff00)
    embed.set_thumbnail(url=user.display_avatar.url)
    
    embed.add_field(name="Username", value=f"{user}", inline=True)
    embed.add_field(name="ID", value=user.id, inline=True)
    embed.add_field(name="Bot", value="Yes" if user.bot else "No", inline=True)
    
    if user.global_name:
        embed.add_field(name="Display Name", value=user.global_name, inline=True)
    
    embed.add_field(name="Created", value=f"<t:{int(user.created_at.timestamp())}:F>", inline=False)
    
    # User flags
    flags = []
    if user.public_flags.staff:
        flags.append("Discord Staff")
    if user.public_flags.partner:
        flags.append("Discord Partner")
    if user.public_flags.verified_developer:
        flags.append("Verified Bot Developer")
    if user.public_flags.early_supporter:
        flags.append("Early Supporter")
    
    if flags:
        embed.add_field(name="Badges", value=", ".join(flags), inline=False)
    
    await ctx.send(embed=embed)

@bot.command()
async def memberinfo(ctx, member: disnake.Member = None):
    """Display member information."""
    if member is None:
        member = ctx.author
    
    embed = disnake.Embed(title=f"Member Information", color=member.color)
    embed.set_thumbnail(url=member.display_avatar.url)
    
    embed.add_field(name="Username", value=f"{member}", inline=True)
    embed.add_field(name="Display Name", value=member.display_name, inline=True)
    embed.add_field(name="ID", value=member.id, inline=True)
    
    embed.add_field(name="Joined Server", value=f"<t:{int(member.joined_at.timestamp())}:F>" if member.joined_at else "Unknown", inline=False)
    embed.add_field(name="Joined Discord", value=f"<t:{int(member.created_at.timestamp())}:F>", inline=False)
    
    # Roles (excluding @everyone)
    roles = [role.mention for role in member.roles[1:]]
    if roles:
        embed.add_field(name=f"Roles ({len(roles)})", value=" ".join(roles), inline=False)
    
    # Status and activity
    status_emojis = {
        disnake.Status.online: "🟢",
        disnake.Status.idle: "🟡",
        disnake.Status.dnd: "🔴",
        disnake.Status.offline: "⚫"
    }
    
    embed.add_field(name="Status", value=f"{status_emojis.get(member.status, '❓')} {member.status.name.title()}", inline=True)
    
    if member.activity:
        activity = member.activity
        activity_type = {
            disnake.ActivityType.playing: "Playing",
            disnake.ActivityType.streaming: "Streaming",
            disnake.ActivityType.listening: "Listening to",
            disnake.ActivityType.watching: "Watching",
            disnake.ActivityType.custom: "Custom Status",
            disnake.ActivityType.competing: "Competing in"
        }
        
        embed.add_field(
            name="Activity", 
            value=f"{activity_type.get(activity.type, 'Unknown')} {activity.name}",
            inline=True
        )
    
    # Boost status
    if member.premium_since:
        embed.add_field(name="Boosting Since", value=f"<t:{int(member.premium_since.timestamp())}:F>", inline=True)
    
    # Timeout status
    if member.is_timed_out():
        embed.add_field(name="Timed Out Until", value=f"<t:{int(member.timed_out_until.timestamp())}:F>", inline=False)
    
    await ctx.send(embed=embed)

@bot.command()
async def avatar(ctx, user: disnake.User = None):
    """Display user's avatar."""
    if user is None:
        user = ctx.author
    
    embed = disnake.Embed(title=f"{user}'s Avatar", color=0x00ff00)
    embed.set_image(url=user.display_avatar.url)
    
    # Add different format links
    formats = ['PNG', 'JPEG', 'WEBP']
    if not user.display_avatar.is_animated():
        format_links = [f"[{fmt}]({user.display_avatar.replace(format=fmt.lower(), size=1024).url})" for fmt in formats]
    else:
        formats.append('GIF')
        format_links = [f"[{fmt}]({user.display_avatar.replace(format=fmt.lower(), size=1024).url})" for fmt in formats]
    
    embed.add_field(name="Formats", value=" | ".join(format_links), inline=False)
    
    await ctx.send(embed=embed)

Member Management

@bot.command()
async def nick(ctx, member: disnake.Member, *, nickname: str = None):
    """Change a member's nickname."""
    if not ctx.author.guild_permissions.manage_nicknames:
        return await ctx.send("You don't have permission to manage nicknames.")
    
    if member.top_role >= ctx.author.top_role and member != ctx.author:
        return await ctx.send("You cannot manage this member's nickname.")
    
    old_nick = member.display_name
    await member.edit(nick=nickname, reason=f"Changed by {ctx.author}")
    
    new_nick = nickname or member.name
    await ctx.send(f"Changed {old_nick}'s nickname to {new_nick}")

@bot.command()
async def timeout(ctx, member: disnake.Member, duration: str, *, reason="No reason provided"):
    """Timeout a member."""
    if not ctx.author.guild_permissions.moderate_members:
        return await ctx.send("You don't have permission to timeout members.")
    
    if member.top_role >= ctx.author.top_role:
        return await ctx.send("You cannot timeout this member.")
    
    # Parse duration (simple implementation)
    duration_map = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}
    
    if duration[-1].lower() in duration_map:
        try:
            time_value = int(duration[:-1])
            time_unit = duration[-1].lower()
            timeout_seconds = time_value * duration_map[time_unit]
            
            if timeout_seconds > 2419200:  # 28 days max
                return await ctx.send("Timeout duration cannot exceed 28 days.")
            
            timeout_until = disnake.utils.utcnow() + timedelta(seconds=timeout_seconds)
            await member.timeout(timeout_until, reason=reason)
            
            await ctx.send(f"Timed out {member.mention} for {duration} - {reason}")
        
        except ValueError:
            await ctx.send("Invalid duration format. Use format like: 1h, 30m, 2d")
    else:
        await ctx.send("Invalid duration format. Use format like: 1h, 30m, 2d")

@bot.command()
async def untimeout(ctx, member: disnake.Member):
    """Remove timeout from a member."""
    if not ctx.author.guild_permissions.moderate_members:
        return await ctx.send("You don't have permission to manage timeouts.")
    
    if not member.is_timed_out():
        return await ctx.send("This member is not timed out.")
    
    await member.timeout(None, reason=f"Timeout removed by {ctx.author}")
    await ctx.send(f"Removed timeout from {member.mention}")

@bot.command()
async def move(ctx, member: disnake.Member, channel: disnake.VoiceChannel = None):
    """Move a member to a voice channel."""
    if not ctx.author.guild_permissions.move_members:
        return await ctx.send("You don't have permission to move members.")
    
    if not member.voice:
        return await ctx.send("Member is not in a voice channel.")
    
    old_channel = member.voice.channel
    await member.move_to(channel, reason=f"Moved by {ctx.author}")
    
    if channel:
        await ctx.send(f"Moved {member.mention} from {old_channel} to {channel}")
    else:
        await ctx.send(f"Disconnected {member.mention} from {old_channel}")

@bot.command()
async def mute(ctx, member: disnake.Member, *, reason="No reason provided"):
    """Server mute a member."""
    if not ctx.author.guild_permissions.mute_members:
        return await ctx.send("You don't have permission to mute members.")
    
    if not member.voice:
        return await ctx.send("Member is not in a voice channel.")
    
    await member.edit(mute=True, reason=reason)
    await ctx.send(f"Server muted {member.mention} - {reason}")

@bot.command()
async def unmute(ctx, member: disnake.Member):
    """Server unmute a member."""
    if not ctx.author.guild_permissions.mute_members:
        return await ctx.send("You don't have permission to unmute members.")
    
    if not member.voice:
        return await ctx.send("Member is not in a voice channel.")
    
    await member.edit(mute=False, reason=f"Unmuted by {ctx.author}")
    await ctx.send(f"Server unmuted {member.mention}")

Status and Activity Tracking

@bot.command()
async def status(ctx, member: disnake.Member = None):
    """Show detailed status information for a member."""
    if member is None:
        member = ctx.author
    
    embed = disnake.Embed(title=f"{member.display_name}'s Status", color=member.color)
    embed.set_thumbnail(url=member.display_avatar.url)
    
    # Overall status
    status_info = {
        disnake.Status.online: ("🟢", "Online"),
        disnake.Status.idle: ("🟡", "Idle"),
        disnake.Status.dnd: ("🔴", "Do Not Disturb"),
        disnake.Status.offline: ("⚫", "Offline"),
        disnake.Status.invisible: ("⚫", "Invisible")
    }
    
    emoji, status_name = status_info.get(member.status, ("❓", "Unknown"))
    embed.add_field(name="Overall Status", value=f"{emoji} {status_name}", inline=True)
    
    # Platform-specific status
    platforms = []
    if member.desktop_status != disnake.Status.offline:
        platforms.append(f"🖥️ Desktop: {member.desktop_status.name.title()}")
    if member.mobile_status != disnake.Status.offline:
        platforms.append(f"📱 Mobile: {member.mobile_status.name.title()}")
    if member.web_status != disnake.Status.offline:
        platforms.append(f"🌐 Web: {member.web_status.name.title()}")
    
    if platforms:
        embed.add_field(name="Platform Status", value="\n".join(platforms), inline=False)
    
    # Activities
    if member.activities:
        activity_list = []
        for activity in member.activities:
            activity_type = {
                disnake.ActivityType.playing: "🎮 Playing",
                disnake.ActivityType.streaming: "🔴 Streaming",
                disnake.ActivityType.listening: "🎵 Listening to",
                disnake.ActivityType.watching: "📺 Watching",
                disnake.ActivityType.custom: "💭 Custom",
                disnake.ActivityType.competing: "🏆 Competing in"
            }
            
            act_type = activity_type.get(activity.type, "❓ Unknown")
            activity_list.append(f"{act_type} {activity.name}")
            
            # Add details for specific activities
            if hasattr(activity, 'details') and activity.details:
                activity_list.append(f"  └ {activity.details}")
            if hasattr(activity, 'state') and activity.state:
                activity_list.append(f"  └ {activity.state}")
        
        embed.add_field(name="Activities", value="\n".join(activity_list), inline=False)
    
    # Voice state
    if member.voice:
        voice_info = []
        voice_info.append(f"Channel: {member.voice.channel.mention}")
        
        voice_flags = []
        if member.voice.deaf:
            voice_flags.append("🔇 Server Deafened")
        if member.voice.mute:
            voice_flags.append("🔇 Server Muted")
        if member.voice.self_deaf:
            voice_flags.append("🔇 Self Deafened")
        if member.voice.self_mute:
            voice_flags.append("🔇 Self Muted")
        if member.voice.self_stream:
            voice_flags.append("📹 Streaming")
        if member.voice.self_video:
            voice_flags.append("📹 Camera On")
        
        if voice_flags:
            voice_info.extend(voice_flags)
        
        embed.add_field(name="Voice Status", value="\n".join(voice_info), inline=False)
    
    await ctx.send(embed=embed)

@bot.event
async def on_member_update(before, after):
    """Track member status changes."""
    # Only track status changes for important members or in specific guilds
    if before.status != after.status:
        # Log status changes
        print(f"{after} changed status from {before.status} to {after.status}")
    
    if before.activities != after.activities:
        # Log activity changes
        print(f"{after} changed activities")

@bot.command()
async def whoisplaying(ctx, *, game: str):
    """Find members playing a specific game."""
    members_playing = []
    
    for member in ctx.guild.members:
        for activity in member.activities:
            if (activity.type == disnake.ActivityType.playing and 
                game.lower() in activity.name.lower()):
                members_playing.append(member)
                break
    
    if not members_playing:
        return await ctx.send(f"No one is currently playing '{game}'")
    
    embed = disnake.Embed(
        title=f"Members playing '{game}'",
        description="\n".join([f"• {member.mention}" for member in members_playing[:20]]),
        color=0x00ff00
    )
    
    if len(members_playing) > 20:
        embed.set_footer(text=f"... and {len(members_playing) - 20} more")
    
    await ctx.send(embed=embed)

Advanced Member Operations

@bot.command()
async def massrole(ctx, action: str, role: disnake.Role, *, criteria: str = "all"):
    """Mass role management."""
    if not ctx.author.guild_permissions.manage_roles:
        return await ctx.send("You don't have permission to manage roles.")
    
    if role >= ctx.author.top_role:
        return await ctx.send("You cannot manage this role.")
    
    if action.lower() not in ['add', 'remove']:
        return await ctx.send("Action must be 'add' or 'remove'")
    
    # Define member filters
    filters = {
        'all': lambda m: not m.bot,
        'bots': lambda m: m.bot,
        'online': lambda m: m.status == disnake.Status.online,
        'boosters': lambda m: m.premium_since is not None,
        'nobots': lambda m: not m.bot,
        'humans': lambda m: not m.bot
    }
    
    member_filter = filters.get(criteria.lower(), filters['all'])
    
    # Get members to modify
    if action.lower() == 'add':
        targets = [m for m in ctx.guild.members if member_filter(m) and role not in m.roles]
    else:
        targets = [m for m in ctx.guild.members if member_filter(m) and role in m.roles]
    
    if not targets:
        return await ctx.send(f"No members found matching criteria '{criteria}' for {action}")
    
    # Confirm action
    embed = disnake.Embed(
        title="Mass Role Operation",
        description=f"**Action:** {action.title()} role {role.mention}\n**Criteria:** {criteria}\n**Affected Members:** {len(targets)}",
        color=0xff9900
    )
    
    embed.add_field(
        name="Preview (first 10)",
        value="\n".join([f"• {m.display_name}" for m in targets[:10]]),
        inline=False
    )
    
    if len(targets) > 10:
        embed.set_footer(text=f"... and {len(targets) - 10} more members")
    
    embed.add_field(name="Confirm", value="React with ✅ to proceed", inline=False)
    
    msg = await ctx.send(embed=embed)
    await msg.add_reaction("✅")
    await msg.add_reaction("❌")
    
    def check(reaction, user):
        return user == ctx.author and str(reaction.emoji) in ["✅", "❌"]
    
    try:
        reaction, _ = await bot.wait_for('reaction_add', timeout=30.0, check=check)
        
        if str(reaction.emoji) == "❌":
            return await ctx.send("Operation cancelled.")
        
        # Perform mass operation
        success_count = 0
        failed_count = 0
        
        for member in targets:
            try:
                if action.lower() == 'add':
                    await member.add_roles(role, reason=f"Mass role operation by {ctx.author}")
                else:
                    await member.remove_roles(role, reason=f"Mass role operation by {ctx.author}")
                success_count += 1
            except Exception:
                failed_count += 1
        
        result_embed = disnake.Embed(
            title="Mass Role Operation Complete",
            color=0x00ff00 if failed_count == 0 else 0xff9900
        )
        
        result_embed.add_field(name="Successful", value=success_count, inline=True)
        result_embed.add_field(name="Failed", value=failed_count, inline=True)
        
        await ctx.send(embed=result_embed)
    
    except asyncio.TimeoutError:
        await ctx.send("Operation timed out.")

@bot.command()
async def cleanup_members(ctx, days: int = 30):
    """Clean up members who haven't been active."""
    if not ctx.author.guild_permissions.kick_members:
        return await ctx.send("You don't have permission to kick members.")
    
    if not 1 <= days <= 365:
        return await ctx.send("Days must be between 1 and 365.")
    
    cutoff_date = disnake.utils.utcnow() - timedelta(days=days)
    
    # Find inactive members
    inactive_members = []
    for member in ctx.guild.members:
        if (member.bot or 
            member == ctx.guild.owner or 
            member.guild_permissions.administrator):
            continue
        
        # Check if member has been active recently
        last_activity = member.joined_at or member.created_at
        
        # This is a simplified check - in practice you might want to track
        # last message times, voice activity, etc.
        if last_activity < cutoff_date:
            inactive_members.append(member)
    
    if not inactive_members:
        return await ctx.send(f"No inactive members found (inactive for {days} days).")
    
    embed = disnake.Embed(
        title="Cleanup Inactive Members",
        description=f"Found {len(inactive_members)} members inactive for {days}+ days",
        color=0xff0000
    )
    
    embed.add_field(
        name="Members to Remove (first 10)",
        value="\n".join([f"• {m.display_name} (joined: <t:{int(m.joined_at.timestamp())}:d>)" for m in inactive_members[:10]]),
        inline=False
    )
    
    if len(inactive_members) > 10:
        embed.set_footer(text=f"... and {len(inactive_members) - 10} more members")
    
    embed.add_field(name="Confirm", value="React with ✅ to proceed with cleanup", inline=False)
    
    msg = await ctx.send(embed=embed)
    await msg.add_reaction("✅")
    await msg.add_reaction("❌")
    
    def check(reaction, user):
        return user == ctx.author and str(reaction.emoji) in ["✅", "❌"]
    
    try:
        reaction, _ = await bot.wait_for('reaction_add', timeout=60.0, check=check)
        
        if str(reaction.emoji) == "❌":
            return await ctx.send("Cleanup cancelled.")
        
        # Perform cleanup
        success_count = 0
        failed_count = 0
        
        for member in inactive_members:
            try:
                await member.kick(reason=f"Inactive for {days}+ days - cleaned up by {ctx.author}")
                success_count += 1
                await asyncio.sleep(1)  # Rate limit protection
            except Exception:
                failed_count += 1
        
        result_embed = disnake.Embed(
            title="Member Cleanup Complete",
            color=0x00ff00 if failed_count == 0 else 0xff9900
        )
        
        result_embed.add_field(name="Removed", value=success_count, inline=True)
        result_embed.add_field(name="Failed", value=failed_count, inline=True)
        
        await ctx.send(embed=result_embed)
    
    except asyncio.TimeoutError:
        await ctx.send("Cleanup operation timed out.")

Install with Tessl CLI

npx tessl i tessl/pypi-disnake

docs

application-commands.md

automod.md

channels-messaging.md

client-bot.md

command-framework.md

error-handling.md

events-gateway.md

guild-management.md

index.md

interactions-ui.md

localization-i18n.md

permissions-security.md

polls.md

users-members.md

voice-audio.md

tile.json