-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathmassmove.py
More file actions
209 lines (178 loc) · 9.07 KB
/
Copy pathmassmove.py
File metadata and controls
209 lines (178 loc) · 9.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import discord
from discord.ext import commands
import asyncio
CONTROL_PANEL_ID = 635919393179828226
EMOJI = '🟢'
def perms_to_move():
async def predicate(ctx):
if ctx.author.guild_permissions.move_members:
return True
else:
await ctx.send(f"Sorry you don't have permissions for that, {ctx.author.mention}")
return commands.check(predicate)
class MassMove(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.control_panel = None
self.message_to_channel = {}
@commands.Cog.listener()
async def on_ready(self):
print(f"[!] MassMove initializing...")
await self.init_control_panel()
print(f"[!] MassMove initialization complete!")
@commands.Cog.listener()
async def on_guild_channel_update(self, before, after):
# TODO: Update control panel when channels are created, deleted, and moved
if before.id in self.message_to_channel.values() and before.name != after.name:
if self.control_panel:
for mid,cid in self.message_to_channel.items():
if before.id == cid:
msg = await self.control_panel.fetch_message(mid)
if msg:
await msg.edit(embed = discord.Embed(title = f'**{after.name}**'))
else:
self.error('Control panel message not found!')
return
else:
self.error('Unknown error in "on_guild_channel_update"')
######################################## HELPER FUNCTIONS ############################################
# TODO: Switch to built-in logger if when expanding functionality
def error(self, msg):
print(f"[!] Error: {msg}")
def _any_null(self, *args):
for a in args:
if a is None:
return True
return False
def _get_channel(self, server, chname : str) -> discord.channel.VoiceChannel:
'''Helper function that returns Channel object from name snippet'''
for channel in server.channels:
if type(channel) is discord.channel.VoiceChannel and chname.lower() in channel.name.lower():
return channel
return None
async def _mbr_helper(self, server, role_name : str, src_channel, dst_channel) -> None:
'''Based off mbr. Integrated for use in .mcc
Moves all members from src to dst if member has role_name in role.name
'''
role = self._get_role(server, role_name)
if role:
all_members = src_channel.members
for member in all_members:
if role in member.roles:
await member.move_to(dst_channel)
def _get_role(self, server, role_name : str) -> discord.Role:
'''Helper function that returns Role object from name snippet'''
for role in server.roles:
if role_name.lower() in role.name.lower():
return role
return None
######################################## END OF HELPER FUNCTIONS ############################################
async def init_control_panel(self) -> None:
'''Init mass move'''
self.control_panel = self.bot.get_channel(CONTROL_PANEL_ID)
if not self.control_panel:
self.error(f"Control Panel not found : {CONTROL_PANEL_ID}")
return
channels = [ch for ch in self.control_panel.guild.channels if isinstance(ch, discord.channel.VoiceChannel)]
await self.control_panel.purge(limit=None)
for channel in sorted(channels, key = lambda ch: ch.position):
name = "**"+channel.name+"**"
message = await self.control_panel.send(embed = discord.Embed(title = name))
await message.add_reaction(EMOJI)
self.message_to_channel[message.id] = channel.id
@commands.command()
@perms_to_move()
async def resetmm(self, ctx):
'''If you make any Discord changes while the bot is running (such as adding or moving around channels),
simply use this command to reload the control panel.
'''
await self.init_control_panel()
@commands.command()
@perms_to_move()
async def mg(self, ctx, game, chname):
''' "Move game": Moves everyone playing "game" to channel with chname in channel name '''
server = ctx.guild
all_members = server.members
move_channel = self._get_channel(server, chname)
#Moves all people to specified channel if they have game in their currently playing game
for member in all_members:
if(member.voice != None and member.voice.channel and not member.voice.afk and game.lower() in str(member.game).lower()):
await member.move_to(move_channel)
await ctx.send(f"Mass moved everyone playing {game} to {str(move_channel)}")
@commands.command()
@perms_to_move()
async def mah(self, ctx):
''' "Move-All-Here" : Moves everyone to your current voice channel '''
server = ctx.guild
author = ctx.author
all_members = server.members
if author.voice:
move_channel = author.voice.channel
else:
await ctx.send(f"You have to be in a Voice Channel to use this command, {ctx.author.mention}")
return
#Moves all people to author's channel
for member in all_members:
if(member.voice and not member.voice.afk and member != author):
await member.move_to(move_channel)
await ctx.send(f"Mass moved everyone to {str(move_channel)}")
await ctx.message.delete()
@commands.command()
async def mcc(self, ctx, src_name : str, dst_name : str, *role_names):
''' "Move-Channel-to-Channel" : .mcc (SRC CHANNEL) (DEST CHANNEL) [ROLES TO MOVE] - Moves everyone from SRC to DEST. If roles are included, only users with the specified roles will be moved '''
server = ctx.message.guild
src_channel = self._get_channel(server, src_name)
dst_channel = self._get_channel(server, dst_name)
if len(role_names) == 0:
if self._any_null(src_channel, dst_channel):
null_names = [name for obj, name in [(src_channel, src_name), (dst_channel, dst_name)] if obj is None]
await ctx.send(f"Sorry, {' and '.join(null_names)} could not be found.")
return
lst = [member.move_to(dst_channel) for member in src_channel.members]
await asyncio.gather(*lst)
else:
for role_name in role_names:
await self._mbr_helper(server, role_name, src_channel, dst_channel)
@commands.command()
async def mbr(self, ctx, role_name: str, dst_name: str):
''' "Move-By-Role" : .mbr (ROLE_NAME) (DEST CHANNEL) - Moves everyone with ROLE_NAME to DEST CHANNEL '''
server = ctx.message.guild
dst_channel = self._get_channel(server, dst_name)
got_role = self._get_role(server, role_name)
all_members = server.members
if self._any_null(dst_channel, got_role):
null_names = [name for obj, name in [(dst_channel, dst_name), (got_role, role_name)] if obj is None]
await ctx.send(f"Sorry, {' and '.join(null_names)} could not be found.")
return
for member in all_members:
if(member.voice is not None and member.voice.channel != dst_channel and not member.voice.afk):
for role in member.roles:
if role == got_role:
await member.move_to(dst_channel)
def reaction_add_check(self, reaction, user):
requirements = \
(
user != self.bot.user,
reaction.emoji == EMOJI,
reaction.message.guild.get_member(user.id).guild_permissions.move_members,
reaction.message.channel == self.control_panel,
reaction.message.id in self.message_to_channel
)
return all(requirements)
@commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
if self.reaction_add_check(reaction, user):
def check(r,u):
return r.emoji == EMOJI and u == user and r.message.id in self.message_to_channel
try:
next_reaction, _ = await self.bot.wait_for('reaction_add', check = check, timeout = 3)
dst_channel = self.bot.get_channel(self.message_to_channel[next_reaction.message.id])
except asyncio.TimeoutError:
await reaction.message.remove_reaction(EMOJI, user)
return
src_channel = self.bot.get_channel(self.message_to_channel[reaction.message.id])
members_to_move = [member.move_to(dst_channel) for member in src_channel.members]
await asyncio.gather(*members_to_move)
await reaction.message.remove_reaction(EMOJI, user)
await next_reaction.message.remove_reaction(EMOJI, user)
print(f"{user.display_name}/{user.name} moved everyone from {src_channel.name} to {dst_channel.name}")