or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-commands.mdautomod.mdchannels-messaging.mdclient-bot.mdcommand-framework.mderror-handling.mdevents-gateway.mdguild-management.mdindex.mdinteractions-ui.mdlocalization-i18n.mdpermissions-security.mdpolls.mdusers-members.mdvoice-audio.md

users-members.mddocs/

0

# Users and Members

1

2

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.

3

4

## Capabilities

5

6

### User Objects

7

8

Basic Discord user representation with profile information and account details.

9

10

```python { .api }

11

class User:

12

def __init__(self): ...

13

14

id: int

15

name: str

16

discriminator: str

17

avatar: Optional[Asset]

18

banner: Optional[Asset]

19

accent_color: Optional[Colour]

20

accent_colour: Optional[Colour]

21

bot: bool

22

system: bool

23

public_flags: PublicUserFlags

24

avatar_decoration: Optional[Asset]

25

clan: Optional[UserClan]

26

27

@property

28

def display_name(self) -> str:

29

"""User's display name (global name or username)."""

30

31

@property

32

def global_name(self) -> Optional[str]:

33

"""User's global display name."""

34

35

@property

36

def mention(self) -> str:

37

"""String to mention the user."""

38

39

@property

40

def display_avatar(self) -> Asset:

41

"""User's display avatar (avatar or default)."""

42

43

@property

44

def default_avatar(self) -> Asset:

45

"""User's default avatar."""

46

47

@property

48

def avatar_decoration_sku_id(self) -> Optional[int]:

49

"""Avatar decoration SKU ID."""

50

51

def mentioned_in(self, message: Message) -> bool:

52

"""

53

Check if user is mentioned in a message.

54

55

Parameters:

56

- message: Message to check

57

58

Returns:

59

True if user is mentioned

60

"""

61

62

async def create_dm(self) -> DMChannel:

63

"""

64

Create a DM channel with this user.

65

66

Returns:

67

DM channel object

68

"""

69

70

def dm_channel(self) -> Optional[DMChannel]:

71

"""

72

Get cached DM channel with this user.

73

74

Returns:

75

DM channel if cached

76

"""

77

78

async def send(

79

self,

80

content: Optional[str] = None,

81

*,

82

tts: bool = False,

83

embed: Optional[Embed] = None,

84

embeds: Optional[List[Embed]] = None,

85

file: Optional[File] = None,

86

files: Optional[List[File]] = None,

87

allowed_mentions: Optional[AllowedMentions] = None,

88

reference: Optional[Union[Message, MessageReference, PartialMessage]] = None,

89

mention_author: Optional[bool] = None,

90

view: Optional[View] = None,

91

components: Optional[Union[ActionRow, List[ActionRow], List[List[Component]], List[Component]]] = None,

92

delete_after: Optional[float] = None,

93

suppress_embeds: bool = False,

94

flags: Optional[MessageFlags] = None

95

) -> Message:

96

"""

97

Send a direct message to this user.

98

99

Parameters:

100

- content: Message text content

101

- tts: Whether message should be read with text-to-speech

102

- embed: Single embed to include

103

- embeds: List of embeds to include (max 10)

104

- file: Single file to attach

105

- files: List of files to attach (max 10)

106

- allowed_mentions: Controls @ mentions in the message

107

- reference: Message to reply to

108

- mention_author: Whether to mention the author when replying

109

- view: UI components view

110

- components: Raw components to include

111

- delete_after: Seconds after which to delete the message

112

- suppress_embeds: Whether to suppress embeds

113

- flags: Message flags

114

115

Returns:

116

The sent message

117

"""

118

119

async def mutual_guilds(self) -> List[Guild]:

120

"""

121

Get guilds shared with the bot.

122

123

Returns:

124

List of mutual guilds

125

"""

126

127

def is_friend(self) -> bool:

128

"""

129

Check if user is friends with the bot.

130

131

Returns:

132

True if friends

133

"""

134

135

def is_blocked(self) -> bool:

136

"""

137

Check if user is blocked by the bot.

138

139

Returns:

140

True if blocked

141

"""

142

143

async def profile(self) -> UserProfile:

144

"""

145

Fetch user's full profile.

146

147

Returns:

148

User profile with additional information

149

"""

150

```

151

152

### Client User

153

154

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

155

156

```python { .api }

157

class ClientUser(User):

158

def __init__(self): ...

159

160

verified: bool

161

locale: Optional[str]

162

mfa_enabled: bool

163

164

async def edit(

165

self,

166

*,

167

username: str = ...,

168

avatar: Optional[bytes] = ...,

169

banner: Optional[bytes] = ...

170

) -> ClientUser:

171

"""

172

Edit the bot's profile.

173

174

Parameters:

175

- username: New username

176

- avatar: New avatar bytes

177

- banner: New banner bytes

178

179

Returns:

180

Updated client user

181

"""

182

```

183

184

### Member Objects

185

186

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

187

188

```python { .api }

189

class Member(User):

190

def __init__(self): ...

191

192

guild: Guild

193

joined_at: Optional[datetime]

194

premium_since: Optional[datetime]

195

roles: List[Role]

196

activities: List[Activity]

197

status: Status

198

raw_status: str

199

mobile_status: Status

200

desktop_status: Status

201

web_status: Status

202

nick: Optional[str]

203

pending: bool

204

timed_out_until: Optional[datetime]

205

flags: MemberFlags

206

avatar: Optional[Asset]

207

banner: Optional[Asset]

208

communication_disabled_until: Optional[datetime]

209

210

@property

211

def display_name(self) -> str:

212

"""Member's display name (nick, global name, or username)."""

213

214

@property

215

def mention(self) -> str:

216

"""String to mention the member."""

217

218

@property

219

def display_avatar(self) -> Asset:

220

"""Member's display avatar (guild avatar, user avatar, or default)."""

221

222

@property

223

def guild_avatar(self) -> Optional[Asset]:

224

"""Member's guild-specific avatar."""

225

226

@property

227

def activity(self) -> Optional[Activity]:

228

"""Member's primary activity."""

229

230

@property

231

def colour(self) -> Colour:

232

"""Member's role color."""

233

234

@property

235

def color(self) -> Colour:

236

"""Member's role color (alias)."""

237

238

@property

239

def top_role(self) -> Role:

240

"""Member's highest role."""

241

242

@property

243

def guild_permissions(self) -> Permissions:

244

"""Member's guild-wide permissions."""

245

246

@property

247

def voice(self) -> Optional[VoiceState]:

248

"""Member's voice state."""

249

250

def permissions_in(self, channel: GuildChannel) -> Permissions:

251

"""

252

Get member's permissions in a specific channel.

253

254

Parameters:

255

- channel: Guild channel

256

257

Returns:

258

Permissions in the channel

259

"""

260

261

async def add_roles(

262

self,

263

*roles: Role,

264

reason: Optional[str] = None,

265

atomic: bool = True

266

) -> None:

267

"""

268

Add roles to the member.

269

270

Parameters:

271

- roles: Roles to add

272

- reason: Audit log reason

273

- atomic: Whether to add all roles in single API call

274

"""

275

276

async def remove_roles(

277

self,

278

*roles: Role,

279

reason: Optional[str] = None,

280

atomic: bool = True

281

) -> None:

282

"""

283

Remove roles from the member.

284

285

Parameters:

286

- roles: Roles to remove

287

- reason: Audit log reason

288

- atomic: Whether to remove all roles in single API call

289

"""

290

291

async def edit(

292

self,

293

*,

294

nick: Optional[str] = ...,

295

mute: bool = ...,

296

deafen: bool = ...,

297

suppress: bool = ...,

298

roles: List[Role] = ...,

299

voice_channel: Optional[VoiceChannel] = ...,

300

reason: Optional[str] = None,

301

timed_out_until: Optional[Union[datetime, float]] = ...,

302

communication_disabled_until: Optional[Union[datetime, float]] = ...,

303

flags: MemberFlags = ...

304

) -> Member:

305

"""

306

Edit the member.

307

308

Parameters:

309

- nick: New nickname (None to remove)

310

- mute: Whether to server mute in voice

311

- deafen: Whether to server deafen in voice

312

- suppress: Whether to suppress in stage channel

313

- roles: New role list (replaces current roles)

314

- voice_channel: Voice channel to move to

315

- reason: Audit log reason

316

- timed_out_until: Timeout duration

317

- communication_disabled_until: Communication timeout

318

- flags: Member flags

319

320

Returns:

321

Updated member

322

"""

323

324

async def timeout(

325

self,

326

duration: Optional[Union[float, datetime, timedelta]] = None,

327

*,

328

reason: Optional[str] = None

329

) -> Member:

330

"""

331

Timeout the member.

332

333

Parameters:

334

- duration: Timeout duration (None to remove timeout)

335

- reason: Audit log reason

336

337

Returns:

338

Updated member

339

"""

340

341

async def kick(self, *, reason: Optional[str] = None) -> None:

342

"""

343

Kick the member from the guild.

344

345

Parameters:

346

- reason: Audit log reason

347

"""

348

349

async def ban(

350

self,

351

*,

352

reason: Optional[str] = None,

353

delete_message_days: int = 1,

354

delete_message_seconds: Optional[int] = None

355

) -> None:

356

"""

357

Ban the member from the guild.

358

359

Parameters:

360

- reason: Audit log reason

361

- delete_message_days: Days of messages to delete (deprecated)

362

- delete_message_seconds: Seconds of messages to delete

363

"""

364

365

async def unban(self, *, reason: Optional[str] = None) -> None:

366

"""

367

Unban the member.

368

369

Parameters:

370

- reason: Audit log reason

371

"""

372

373

async def move_to(self, channel: Optional[VoiceChannel], *, reason: Optional[str] = None) -> None:

374

"""

375

Move member to a voice channel.

376

377

Parameters:

378

- channel: Voice channel to move to (None to disconnect)

379

- reason: Audit log reason

380

"""

381

382

async def request_to_speak(self) -> None:

383

"""Request to speak in a stage channel."""

384

385

async def fetch_message(self, id: int) -> Message:

386

"""

387

Fetch a message sent by this member.

388

389

Parameters:

390

- id: Message ID

391

392

Returns:

393

Message object

394

"""

395

396

def mentioned_in(self, message: Message) -> bool:

397

"""

398

Check if member is mentioned in a message.

399

400

Parameters:

401

- message: Message to check

402

403

Returns:

404

True if member is mentioned

405

"""

406

407

def is_timed_out(self) -> bool:

408

"""

409

Check if member is currently timed out.

410

411

Returns:

412

True if timed out

413

"""

414

415

def is_on_mobile(self) -> bool:

416

"""

417

Check if member is on mobile.

418

419

Returns:

420

True if on mobile

421

"""

422

```

423

424

### Voice States

425

426

Member voice connection and activity information.

427

428

```python { .api }

429

class VoiceState:

430

def __init__(self): ...

431

432

session_id: str

433

channel: Optional[Union[VoiceChannel, StageChannel]]

434

user_id: int

435

member: Optional[Member]

436

deaf: bool

437

mute: bool

438

self_deaf: bool

439

self_mute: bool

440

self_stream: bool

441

self_video: bool

442

suppress: bool

443

requested_to_speak_at: Optional[datetime]

444

445

@property

446

def guild(self) -> Optional[Guild]:

447

"""Guild the voice state is in."""

448

449

@property

450

def user(self) -> Optional[User]:

451

"""User the voice state belongs to."""

452

453

def is_afk(self) -> bool:

454

"""

455

Check if user is in AFK channel.

456

457

Returns:

458

True if in AFK channel

459

"""

460

```

461

462

### User Profiles

463

464

Extended user information available through profile fetching.

465

466

```python { .api }

467

class UserProfile:

468

def __init__(self): ...

469

470

user: User

471

connected_accounts: List[ConnectedAccount]

472

premium_since: Optional[datetime]

473

premium_type: Optional[PremiumType]

474

nitro_subscription: Optional[NitroSubscription]

475

mutual_guilds: List[PartialGuild]

476

mutual_friends: List[User]

477

premium_guild_since: Optional[datetime]

478

legacy_username: Optional[str]

479

480

@property

481

def nitro(self) -> bool:

482

"""Whether user has Nitro subscription."""

483

484

@property

485

def hypesquad(self) -> Optional[HypeSquadHouse]:

486

"""User's HypeSquad house."""

487

```

488

489

### Activity Objects

490

491

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

492

493

```python { .api }

494

class Activity:

495

def __init__(self): ...

496

497

type: ActivityType

498

name: str

499

url: Optional[str]

500

created_at: datetime

501

timestamps: Optional[ActivityTimestamps]

502

application_id: Optional[int]

503

details: Optional[str]

504

state: Optional[str]

505

emoji: Optional[PartialEmoji]

506

party: Optional[ActivityParty]

507

assets: Optional[ActivityAssets]

508

secrets: Optional[ActivitySecrets]

509

instance: bool

510

flags: Optional[ActivityFlags]

511

buttons: List[str]

512

513

@property

514

def start(self) -> Optional[datetime]:

515

"""Activity start time."""

516

517

@property

518

def end(self) -> Optional[datetime]:

519

"""Activity end time."""

520

521

class Game(Activity):

522

"""Gaming activity."""

523

524

def __init__(self, name: str):

525

"""

526

Initialize a game activity.

527

528

Parameters:

529

- name: Game name

530

"""

531

532

class Streaming(Activity):

533

"""Streaming activity."""

534

535

def __init__(self, *, name: str, url: str):

536

"""

537

Initialize a streaming activity.

538

539

Parameters:

540

- name: Stream title

541

- url: Stream URL

542

"""

543

544

@property

545

def twitch_name(self) -> Optional[str]:

546

"""Twitch channel name."""

547

548

class CustomActivity(Activity):

549

"""Custom status activity."""

550

551

def __init__(self, name: str, *, emoji: Optional[Union[str, Emoji, PartialEmoji]] = None):

552

"""

553

Initialize a custom activity.

554

555

Parameters:

556

- name: Status text

557

- emoji: Status emoji

558

"""

559

```

560

561

### Relationships and Connections

562

563

User relationship and external account connection information.

564

565

```python { .api }

566

class Relationship:

567

def __init__(self): ...

568

569

user: User

570

type: RelationshipType

571

nickname: Optional[str]

572

since: Optional[datetime]

573

574

class ConnectedAccount:

575

def __init__(self): ...

576

577

id: str

578

name: str

579

type: str

580

revoked: bool

581

integrations: List[Integration]

582

verified: bool

583

friend_sync: bool

584

show_activity: bool

585

visibility: int

586

```

587

588

### Member Flags and Properties

589

590

Member-specific flags and configuration options.

591

592

```python { .api }

593

class MemberFlags:

594

"""Member flags bitfield."""

595

596

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

597

598

@classmethod

599

def none(cls) -> MemberFlags:

600

"""No flags set."""

601

602

@classmethod

603

def all(cls) -> MemberFlags:

604

"""All flags set."""

605

606

@property

607

def did_rejoin(self) -> bool:

608

"""Whether member rejoined the guild."""

609

610

@property

611

def completed_onboarding(self) -> bool:

612

"""Whether member completed onboarding."""

613

614

@property

615

def bypasses_verification(self) -> bool:

616

"""Whether member bypasses verification."""

617

618

@property

619

def started_onboarding(self) -> bool:

620

"""Whether member started onboarding."""

621

622

class PublicUserFlags:

623

"""Public user flags bitfield."""

624

625

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

626

627

@property

628

def staff(self) -> bool:

629

"""Discord Staff."""

630

631

@property

632

def partner(self) -> bool:

633

"""Discord Partner."""

634

635

@property

636

def hypesquad(self) -> bool:

637

"""HypeSquad Events."""

638

639

@property

640

def bug_hunter(self) -> bool:

641

"""Bug Hunter Level 1."""

642

643

@property

644

def hypesquad_bravery(self) -> bool:

645

"""HypeSquad Bravery."""

646

647

@property

648

def hypesquad_brilliance(self) -> bool:

649

"""HypeSquad Brilliance."""

650

651

@property

652

def hypesquad_balance(self) -> bool:

653

"""HypeSquad Balance."""

654

655

@property

656

def early_supporter(self) -> bool:

657

"""Early Supporter."""

658

659

@property

660

def bug_hunter_level_2(self) -> bool:

661

"""Bug Hunter Level 2."""

662

663

@property

664

def verified_bot(self) -> bool:

665

"""Verified Bot."""

666

667

@property

668

def verified_developer(self) -> bool:

669

"""Verified Bot Developer."""

670

671

@property

672

def certified_moderator(self) -> bool:

673

"""Discord Certified Moderator."""

674

675

@property

676

def bot_http_interactions(self) -> bool:

677

"""Bot uses HTTP interactions."""

678

679

@property

680

def active_developer(self) -> bool:

681

"""Active Developer."""

682

```

683

684

## Usage Examples

685

686

### User Information Commands

687

688

```python

689

import disnake

690

from disnake.ext import commands

691

692

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

693

694

@bot.command()

695

async def userinfo(ctx, user: disnake.User = None):

696

"""Display user information."""

697

if user is None:

698

user = ctx.author

699

700

embed = disnake.Embed(title=f"User Information", color=0x00ff00)

701

embed.set_thumbnail(url=user.display_avatar.url)

702

703

embed.add_field(name="Username", value=f"{user}", inline=True)

704

embed.add_field(name="ID", value=user.id, inline=True)

705

embed.add_field(name="Bot", value="Yes" if user.bot else "No", inline=True)

706

707

if user.global_name:

708

embed.add_field(name="Display Name", value=user.global_name, inline=True)

709

710

embed.add_field(name="Created", value=f"<t:{int(user.created_at.timestamp())}:F>", inline=False)

711

712

# User flags

713

flags = []

714

if user.public_flags.staff:

715

flags.append("Discord Staff")

716

if user.public_flags.partner:

717

flags.append("Discord Partner")

718

if user.public_flags.verified_developer:

719

flags.append("Verified Bot Developer")

720

if user.public_flags.early_supporter:

721

flags.append("Early Supporter")

722

723

if flags:

724

embed.add_field(name="Badges", value=", ".join(flags), inline=False)

725

726

await ctx.send(embed=embed)

727

728

@bot.command()

729

async def memberinfo(ctx, member: disnake.Member = None):

730

"""Display member information."""

731

if member is None:

732

member = ctx.author

733

734

embed = disnake.Embed(title=f"Member Information", color=member.color)

735

embed.set_thumbnail(url=member.display_avatar.url)

736

737

embed.add_field(name="Username", value=f"{member}", inline=True)

738

embed.add_field(name="Display Name", value=member.display_name, inline=True)

739

embed.add_field(name="ID", value=member.id, inline=True)

740

741

embed.add_field(name="Joined Server", value=f"<t:{int(member.joined_at.timestamp())}:F>" if member.joined_at else "Unknown", inline=False)

742

embed.add_field(name="Joined Discord", value=f"<t:{int(member.created_at.timestamp())}:F>", inline=False)

743

744

# Roles (excluding @everyone)

745

roles = [role.mention for role in member.roles[1:]]

746

if roles:

747

embed.add_field(name=f"Roles ({len(roles)})", value=" ".join(roles), inline=False)

748

749

# Status and activity

750

status_emojis = {

751

disnake.Status.online: "๐ŸŸข",

752

disnake.Status.idle: "๐ŸŸก",

753

disnake.Status.dnd: "๐Ÿ”ด",

754

disnake.Status.offline: "โšซ"

755

}

756

757

embed.add_field(name="Status", value=f"{status_emojis.get(member.status, 'โ“')} {member.status.name.title()}", inline=True)

758

759

if member.activity:

760

activity = member.activity

761

activity_type = {

762

disnake.ActivityType.playing: "Playing",

763

disnake.ActivityType.streaming: "Streaming",

764

disnake.ActivityType.listening: "Listening to",

765

disnake.ActivityType.watching: "Watching",

766

disnake.ActivityType.custom: "Custom Status",

767

disnake.ActivityType.competing: "Competing in"

768

}

769

770

embed.add_field(

771

name="Activity",

772

value=f"{activity_type.get(activity.type, 'Unknown')} {activity.name}",

773

inline=True

774

)

775

776

# Boost status

777

if member.premium_since:

778

embed.add_field(name="Boosting Since", value=f"<t:{int(member.premium_since.timestamp())}:F>", inline=True)

779

780

# Timeout status

781

if member.is_timed_out():

782

embed.add_field(name="Timed Out Until", value=f"<t:{int(member.timed_out_until.timestamp())}:F>", inline=False)

783

784

await ctx.send(embed=embed)

785

786

@bot.command()

787

async def avatar(ctx, user: disnake.User = None):

788

"""Display user's avatar."""

789

if user is None:

790

user = ctx.author

791

792

embed = disnake.Embed(title=f"{user}'s Avatar", color=0x00ff00)

793

embed.set_image(url=user.display_avatar.url)

794

795

# Add different format links

796

formats = ['PNG', 'JPEG', 'WEBP']

797

if not user.display_avatar.is_animated():

798

format_links = [f"[{fmt}]({user.display_avatar.replace(format=fmt.lower(), size=1024).url})" for fmt in formats]

799

else:

800

formats.append('GIF')

801

format_links = [f"[{fmt}]({user.display_avatar.replace(format=fmt.lower(), size=1024).url})" for fmt in formats]

802

803

embed.add_field(name="Formats", value=" | ".join(format_links), inline=False)

804

805

await ctx.send(embed=embed)

806

```

807

808

### Member Management

809

810

```python

811

@bot.command()

812

async def nick(ctx, member: disnake.Member, *, nickname: str = None):

813

"""Change a member's nickname."""

814

if not ctx.author.guild_permissions.manage_nicknames:

815

return await ctx.send("You don't have permission to manage nicknames.")

816

817

if member.top_role >= ctx.author.top_role and member != ctx.author:

818

return await ctx.send("You cannot manage this member's nickname.")

819

820

old_nick = member.display_name

821

await member.edit(nick=nickname, reason=f"Changed by {ctx.author}")

822

823

new_nick = nickname or member.name

824

await ctx.send(f"Changed {old_nick}'s nickname to {new_nick}")

825

826

@bot.command()

827

async def timeout(ctx, member: disnake.Member, duration: str, *, reason="No reason provided"):

828

"""Timeout a member."""

829

if not ctx.author.guild_permissions.moderate_members:

830

return await ctx.send("You don't have permission to timeout members.")

831

832

if member.top_role >= ctx.author.top_role:

833

return await ctx.send("You cannot timeout this member.")

834

835

# Parse duration (simple implementation)

836

duration_map = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}

837

838

if duration[-1].lower() in duration_map:

839

try:

840

time_value = int(duration[:-1])

841

time_unit = duration[-1].lower()

842

timeout_seconds = time_value * duration_map[time_unit]

843

844

if timeout_seconds > 2419200: # 28 days max

845

return await ctx.send("Timeout duration cannot exceed 28 days.")

846

847

timeout_until = disnake.utils.utcnow() + timedelta(seconds=timeout_seconds)

848

await member.timeout(timeout_until, reason=reason)

849

850

await ctx.send(f"Timed out {member.mention} for {duration} - {reason}")

851

852

except ValueError:

853

await ctx.send("Invalid duration format. Use format like: 1h, 30m, 2d")

854

else:

855

await ctx.send("Invalid duration format. Use format like: 1h, 30m, 2d")

856

857

@bot.command()

858

async def untimeout(ctx, member: disnake.Member):

859

"""Remove timeout from a member."""

860

if not ctx.author.guild_permissions.moderate_members:

861

return await ctx.send("You don't have permission to manage timeouts.")

862

863

if not member.is_timed_out():

864

return await ctx.send("This member is not timed out.")

865

866

await member.timeout(None, reason=f"Timeout removed by {ctx.author}")

867

await ctx.send(f"Removed timeout from {member.mention}")

868

869

@bot.command()

870

async def move(ctx, member: disnake.Member, channel: disnake.VoiceChannel = None):

871

"""Move a member to a voice channel."""

872

if not ctx.author.guild_permissions.move_members:

873

return await ctx.send("You don't have permission to move members.")

874

875

if not member.voice:

876

return await ctx.send("Member is not in a voice channel.")

877

878

old_channel = member.voice.channel

879

await member.move_to(channel, reason=f"Moved by {ctx.author}")

880

881

if channel:

882

await ctx.send(f"Moved {member.mention} from {old_channel} to {channel}")

883

else:

884

await ctx.send(f"Disconnected {member.mention} from {old_channel}")

885

886

@bot.command()

887

async def mute(ctx, member: disnake.Member, *, reason="No reason provided"):

888

"""Server mute a member."""

889

if not ctx.author.guild_permissions.mute_members:

890

return await ctx.send("You don't have permission to mute members.")

891

892

if not member.voice:

893

return await ctx.send("Member is not in a voice channel.")

894

895

await member.edit(mute=True, reason=reason)

896

await ctx.send(f"Server muted {member.mention} - {reason}")

897

898

@bot.command()

899

async def unmute(ctx, member: disnake.Member):

900

"""Server unmute a member."""

901

if not ctx.author.guild_permissions.mute_members:

902

return await ctx.send("You don't have permission to unmute members.")

903

904

if not member.voice:

905

return await ctx.send("Member is not in a voice channel.")

906

907

await member.edit(mute=False, reason=f"Unmuted by {ctx.author}")

908

await ctx.send(f"Server unmuted {member.mention}")

909

```

910

911

### Status and Activity Tracking

912

913

```python

914

@bot.command()

915

async def status(ctx, member: disnake.Member = None):

916

"""Show detailed status information for a member."""

917

if member is None:

918

member = ctx.author

919

920

embed = disnake.Embed(title=f"{member.display_name}'s Status", color=member.color)

921

embed.set_thumbnail(url=member.display_avatar.url)

922

923

# Overall status

924

status_info = {

925

disnake.Status.online: ("๐ŸŸข", "Online"),

926

disnake.Status.idle: ("๐ŸŸก", "Idle"),

927

disnake.Status.dnd: ("๐Ÿ”ด", "Do Not Disturb"),

928

disnake.Status.offline: ("โšซ", "Offline"),

929

disnake.Status.invisible: ("โšซ", "Invisible")

930

}

931

932

emoji, status_name = status_info.get(member.status, ("โ“", "Unknown"))

933

embed.add_field(name="Overall Status", value=f"{emoji} {status_name}", inline=True)

934

935

# Platform-specific status

936

platforms = []

937

if member.desktop_status != disnake.Status.offline:

938

platforms.append(f"๐Ÿ–ฅ๏ธ Desktop: {member.desktop_status.name.title()}")

939

if member.mobile_status != disnake.Status.offline:

940

platforms.append(f"๐Ÿ“ฑ Mobile: {member.mobile_status.name.title()}")

941

if member.web_status != disnake.Status.offline:

942

platforms.append(f"๐ŸŒ Web: {member.web_status.name.title()}")

943

944

if platforms:

945

embed.add_field(name="Platform Status", value="\n".join(platforms), inline=False)

946

947

# Activities

948

if member.activities:

949

activity_list = []

950

for activity in member.activities:

951

activity_type = {

952

disnake.ActivityType.playing: "๐ŸŽฎ Playing",

953

disnake.ActivityType.streaming: "๐Ÿ”ด Streaming",

954

disnake.ActivityType.listening: "๐ŸŽต Listening to",

955

disnake.ActivityType.watching: "๐Ÿ“บ Watching",

956

disnake.ActivityType.custom: "๐Ÿ’ญ Custom",

957

disnake.ActivityType.competing: "๐Ÿ† Competing in"

958

}

959

960

act_type = activity_type.get(activity.type, "โ“ Unknown")

961

activity_list.append(f"{act_type} {activity.name}")

962

963

# Add details for specific activities

964

if hasattr(activity, 'details') and activity.details:

965

activity_list.append(f" โ”” {activity.details}")

966

if hasattr(activity, 'state') and activity.state:

967

activity_list.append(f" โ”” {activity.state}")

968

969

embed.add_field(name="Activities", value="\n".join(activity_list), inline=False)

970

971

# Voice state

972

if member.voice:

973

voice_info = []

974

voice_info.append(f"Channel: {member.voice.channel.mention}")

975

976

voice_flags = []

977

if member.voice.deaf:

978

voice_flags.append("๐Ÿ”‡ Server Deafened")

979

if member.voice.mute:

980

voice_flags.append("๐Ÿ”‡ Server Muted")

981

if member.voice.self_deaf:

982

voice_flags.append("๐Ÿ”‡ Self Deafened")

983

if member.voice.self_mute:

984

voice_flags.append("๐Ÿ”‡ Self Muted")

985

if member.voice.self_stream:

986

voice_flags.append("๐Ÿ“น Streaming")

987

if member.voice.self_video:

988

voice_flags.append("๐Ÿ“น Camera On")

989

990

if voice_flags:

991

voice_info.extend(voice_flags)

992

993

embed.add_field(name="Voice Status", value="\n".join(voice_info), inline=False)

994

995

await ctx.send(embed=embed)

996

997

@bot.event

998

async def on_member_update(before, after):

999

"""Track member status changes."""

1000

# Only track status changes for important members or in specific guilds

1001

if before.status != after.status:

1002

# Log status changes

1003

print(f"{after} changed status from {before.status} to {after.status}")

1004

1005

if before.activities != after.activities:

1006

# Log activity changes

1007

print(f"{after} changed activities")

1008

1009

@bot.command()

1010

async def whoisplaying(ctx, *, game: str):

1011

"""Find members playing a specific game."""

1012

members_playing = []

1013

1014

for member in ctx.guild.members:

1015

for activity in member.activities:

1016

if (activity.type == disnake.ActivityType.playing and

1017

game.lower() in activity.name.lower()):

1018

members_playing.append(member)

1019

break

1020

1021

if not members_playing:

1022

return await ctx.send(f"No one is currently playing '{game}'")

1023

1024

embed = disnake.Embed(

1025

title=f"Members playing '{game}'",

1026

description="\n".join([f"โ€ข {member.mention}" for member in members_playing[:20]]),

1027

color=0x00ff00

1028

)

1029

1030

if len(members_playing) > 20:

1031

embed.set_footer(text=f"... and {len(members_playing) - 20} more")

1032

1033

await ctx.send(embed=embed)

1034

```

1035

1036

### Advanced Member Operations

1037

1038

```python

1039

@bot.command()

1040

async def massrole(ctx, action: str, role: disnake.Role, *, criteria: str = "all"):

1041

"""Mass role management."""

1042

if not ctx.author.guild_permissions.manage_roles:

1043

return await ctx.send("You don't have permission to manage roles.")

1044

1045

if role >= ctx.author.top_role:

1046

return await ctx.send("You cannot manage this role.")

1047

1048

if action.lower() not in ['add', 'remove']:

1049

return await ctx.send("Action must be 'add' or 'remove'")

1050

1051

# Define member filters

1052

filters = {

1053

'all': lambda m: not m.bot,

1054

'bots': lambda m: m.bot,

1055

'online': lambda m: m.status == disnake.Status.online,

1056

'boosters': lambda m: m.premium_since is not None,

1057

'nobots': lambda m: not m.bot,

1058

'humans': lambda m: not m.bot

1059

}

1060

1061

member_filter = filters.get(criteria.lower(), filters['all'])

1062

1063

# Get members to modify

1064

if action.lower() == 'add':

1065

targets = [m for m in ctx.guild.members if member_filter(m) and role not in m.roles]

1066

else:

1067

targets = [m for m in ctx.guild.members if member_filter(m) and role in m.roles]

1068

1069

if not targets:

1070

return await ctx.send(f"No members found matching criteria '{criteria}' for {action}")

1071

1072

# Confirm action

1073

embed = disnake.Embed(

1074

title="Mass Role Operation",

1075

description=f"**Action:** {action.title()} role {role.mention}\n**Criteria:** {criteria}\n**Affected Members:** {len(targets)}",

1076

color=0xff9900

1077

)

1078

1079

embed.add_field(

1080

name="Preview (first 10)",

1081

value="\n".join([f"โ€ข {m.display_name}" for m in targets[:10]]),

1082

inline=False

1083

)

1084

1085

if len(targets) > 10:

1086

embed.set_footer(text=f"... and {len(targets) - 10} more members")

1087

1088

embed.add_field(name="Confirm", value="React with โœ… to proceed", inline=False)

1089

1090

msg = await ctx.send(embed=embed)

1091

await msg.add_reaction("โœ…")

1092

await msg.add_reaction("โŒ")

1093

1094

def check(reaction, user):

1095

return user == ctx.author and str(reaction.emoji) in ["โœ…", "โŒ"]

1096

1097

try:

1098

reaction, _ = await bot.wait_for('reaction_add', timeout=30.0, check=check)

1099

1100

if str(reaction.emoji) == "โŒ":

1101

return await ctx.send("Operation cancelled.")

1102

1103

# Perform mass operation

1104

success_count = 0

1105

failed_count = 0

1106

1107

for member in targets:

1108

try:

1109

if action.lower() == 'add':

1110

await member.add_roles(role, reason=f"Mass role operation by {ctx.author}")

1111

else:

1112

await member.remove_roles(role, reason=f"Mass role operation by {ctx.author}")

1113

success_count += 1

1114

except Exception:

1115

failed_count += 1

1116

1117

result_embed = disnake.Embed(

1118

title="Mass Role Operation Complete",

1119

color=0x00ff00 if failed_count == 0 else 0xff9900

1120

)

1121

1122

result_embed.add_field(name="Successful", value=success_count, inline=True)

1123

result_embed.add_field(name="Failed", value=failed_count, inline=True)

1124

1125

await ctx.send(embed=result_embed)

1126

1127

except asyncio.TimeoutError:

1128

await ctx.send("Operation timed out.")

1129

1130

@bot.command()

1131

async def cleanup_members(ctx, days: int = 30):

1132

"""Clean up members who haven't been active."""

1133

if not ctx.author.guild_permissions.kick_members:

1134

return await ctx.send("You don't have permission to kick members.")

1135

1136

if not 1 <= days <= 365:

1137

return await ctx.send("Days must be between 1 and 365.")

1138

1139

cutoff_date = disnake.utils.utcnow() - timedelta(days=days)

1140

1141

# Find inactive members

1142

inactive_members = []

1143

for member in ctx.guild.members:

1144

if (member.bot or

1145

member == ctx.guild.owner or

1146

member.guild_permissions.administrator):

1147

continue

1148

1149

# Check if member has been active recently

1150

last_activity = member.joined_at or member.created_at

1151

1152

# This is a simplified check - in practice you might want to track

1153

# last message times, voice activity, etc.

1154

if last_activity < cutoff_date:

1155

inactive_members.append(member)

1156

1157

if not inactive_members:

1158

return await ctx.send(f"No inactive members found (inactive for {days} days).")

1159

1160

embed = disnake.Embed(

1161

title="Cleanup Inactive Members",

1162

description=f"Found {len(inactive_members)} members inactive for {days}+ days",

1163

color=0xff0000

1164

)

1165

1166

embed.add_field(

1167

name="Members to Remove (first 10)",

1168

value="\n".join([f"โ€ข {m.display_name} (joined: <t:{int(m.joined_at.timestamp())}:d>)" for m in inactive_members[:10]]),

1169

inline=False

1170

)

1171

1172

if len(inactive_members) > 10:

1173

embed.set_footer(text=f"... and {len(inactive_members) - 10} more members")

1174

1175

embed.add_field(name="Confirm", value="React with โœ… to proceed with cleanup", inline=False)

1176

1177

msg = await ctx.send(embed=embed)

1178

await msg.add_reaction("โœ…")

1179

await msg.add_reaction("โŒ")

1180

1181

def check(reaction, user):

1182

return user == ctx.author and str(reaction.emoji) in ["โœ…", "โŒ"]

1183

1184

try:

1185

reaction, _ = await bot.wait_for('reaction_add', timeout=60.0, check=check)

1186

1187

if str(reaction.emoji) == "โŒ":

1188

return await ctx.send("Cleanup cancelled.")

1189

1190

# Perform cleanup

1191

success_count = 0

1192

failed_count = 0

1193

1194

for member in inactive_members:

1195

try:

1196

await member.kick(reason=f"Inactive for {days}+ days - cleaned up by {ctx.author}")

1197

success_count += 1

1198

await asyncio.sleep(1) # Rate limit protection

1199

except Exception:

1200

failed_count += 1

1201

1202

result_embed = disnake.Embed(

1203

title="Member Cleanup Complete",

1204

color=0x00ff00 if failed_count == 0 else 0xff9900

1205

)

1206

1207

result_embed.add_field(name="Removed", value=success_count, inline=True)

1208

result_embed.add_field(name="Failed", value=failed_count, inline=True)

1209

1210

await ctx.send(embed=result_embed)

1211

1212

except asyncio.TimeoutError:

1213

await ctx.send("Cleanup operation timed out.")

1214

```