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
```