-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmathfansdiscordbot.py
More file actions
386 lines (326 loc) · 13.5 KB
/
mathfansdiscordbot.py
File metadata and controls
386 lines (326 loc) · 13.5 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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
#import packages
import discord #must install discord.py to use this module
import os
from datetime import datetime
from discord.ext import commands #must install discord.py to use this module
from pathlib import Path, PureWindowsPath
#command prefix
client = commands.Bot(command_prefix='!')
# Change Per Server Deployment
token = 'bot_token'
instructor = 'instructor_ID'
current_voice_channel = 0
#dynamically get channel
def get_channel(channel_str):
for guild in client.guilds:
for channel in guild.channels:
if channel.name == channel_str:
return channel
#dynamically get guild
def get_guild(guild_str):
for guild in client.guilds:
if guild.name == guild_str:
return guild
# Default values
user_queue = []
question_mode = 'single'
lesson_mode = None
# Subroutine to change lesson_mode
def change_lesson_mode(bool):
global lesson_mode
lesson_mode = bool
# Subroutine to change question_mode
def change_question_mode(str):
global question_mode
question_mode = str
# Bot activity + load up notifier
@client.event
async def on_ready():
await client.change_presence(
activity=discord.Activity(
name='with Numbers', type=discord.ActivityType.playing))
print('Bot is ready.')
# change active voice channel
@client.command()
async def change_channel(ctx, channel_id):
global current_voice_channel
if ctx.message.author.id != instructor:
await ctx.send('Missing Permissions. Please check !help')
return
else:
current_voice_channel = int(channel_id)
await ctx.send(f'Current voice channel set to {channel_id}')
# update instructor id
@client.command()
async def change_instructor(ctx, id):
global instructor
if ctx.message.author.id != instructor:
await ctx.send('Missing Permissions. Please check !help')
return
else:
instructor = int(id)
await ctx.send(f'Instuctor ID set to {id}')
# Checks for new member join and mutes them.
@client.event
async def on_voice_state_update(member, before, after):
guild_obj = get_guild(member.guild.name)
# checks if in lesson mode
if lesson_mode:
if before.channel is None and after.channel is not None:
if member.id != instructor:
await guild_obj.get_member(member.id).edit(mute=True)
# sub routine for done/forcedone to prompt next user
@client.command()
async def next(ctx):
guild_obj = get_guild(ctx.guild.name)
# checks user permissions
if ctx.message.author.id != instructor:
await ctx.send('Missing Permissions. Please check !help')
return
# checks if queue has Users
if not user_queue:
await ctx.send('Queue Empty')
return
member = guild_obj.get_member(user_queue[0].id)
# unmute user in voice channel
if member in guild_obj.get_channel(current_voice_channel).members:
print(member.voice.mute)
if not member.voice.mute:
await forcedone(ctx)
if lesson_mode == 'auto':
return
if not user_queue:
await ctx.send('Queue Empty')
return
member = guild_obj.get_member(user_queue[0].id)
await guild_obj.get_member(member.id).edit(mute=False)
await ctx.send(f'{member.display_name} speak permissions set to True')
await ctx.send(f'{member.display_name} is now asking his/her question')
return
# if member is not found, pop and retry
else:
user_queue.pop(0)
await ctx.send(
f'Unable to find {member.display_name} in voice channel, skipping to next user')
await next(ctx)
return
# commands to change question_mode
@client.command()
async def queue_auto(ctx):
# checks user permissions
if ctx.message.author.id != instructor:
await ctx.send('Missing Permissions. Please check !help')
return
global question_mode
question_mode = 'auto'
await ctx.message.add_reaction("✅")
@client.command()
async def queue_single(ctx):
# checks user permissions
if ctx.message.author.id != instructor:
await ctx.send('Missing Permissions. Please check !help')
return
global question_mode
question_mode = 'single'
await ctx.message.add_reaction("✅")
# allows current user to end their question
@client.command()
async def done(ctx):
guild_obj = get_guild(ctx.guild.name)
if not lesson_mode:
await ctx.send('Class is not in session.')
return
# if user queue empty
if not user_queue:
await ctx.send('No math fans in line!')
# if user who is currently talking wants to stop
elif ctx.message.author == user_queue[0]:
user_popped = user_queue.pop(0)
member = guild_obj.get_member(user_popped.id)
# if user in voice channel, mute
if ctx.author in guild_obj.get_channel(current_voice_channel).members:
await guild_obj.get_member(member.id).edit(mute=True)
await ctx.send(f'{member.display_name} muted')
await ctx.author.edit(mute=True)
await ctx.send(
f'{user_popped.display_name} is no longer in line and is now muted.')
await ctx.send(
f'There are {len(user_queue)} math fans in line.')
# [Auto Mode] next user into their question
if question_mode == 'auto':
await next(ctx)
# if user isnt currently the person talking
else:
await ctx.send('You are not currently talking')
# allows instructor to toggle next user
@client.command()
async def force_done(ctx):
guild_obj = get_guild(ctx.guild.name)
if ctx.message.author.id != instructor:
await ctx.send('Missing Permissions. Please check !help')
return
if not user_queue:
await ctx.send('No math fans in line!')
else:
user_popped = user_queue.pop(0)
member = guild_obj.get_member(user_popped.id)
# if user in voice channel, unmute
if member in guild_obj.get_channel(current_voice_channel).members:
await guild_obj.get_member(member.id).edit(mute=True)
await ctx.send(f'{member.display_name} muted')
await ctx.send(
f'{user_popped.display_name} is no longer in line and is now muted.')
await ctx.send(
f'There are {len(user_queue)} math fans in line.')
# shows queue
@client.command()
async def queue(ctx):
if user_queue:
for member in user_queue:
queuelist = []
queuelist.append(member.name)
await ctx.send(f'Current Queue: {queuelist}')
else:
await ctx.send('Queue is empty!')
# queues user to ask a question
@client.command()
async def talk(ctx):
guild_obj = get_guild(ctx.guild.name)
if not lesson_mode:
await ctx.send('Class is not in session.')
return
# dynamically fetch guild object and member
member = guild_obj.get_member(ctx.author.id)
# if user already in line, do nothing
if ctx.author in user_queue:
await ctx.send(f'{ctx.author.display_name} already in line')
return
# if user queue empty
if not user_queue:
user_queue.append(ctx.author)
await ctx.send(f'{ctx.author.display_name} has been added to the queue')
if question_mode == 'auto':
# unmute member if in the voice channel, unmute
if member in guild_obj.get_channel(current_voice_channel).members:
await guild_obj.get_member(member.id).edit(mute=False)
await ctx.send(f'{member.display_name} unmuted')
await ctx.send(f'No math fans in line. {ctx.author.display_name} unmuted.')
else:
user_queue.append(ctx.author)
await ctx.send(
f'{ctx.author.display_name} there are {len(user_queue) - 1} math fans ahead of you in line.')
# starts class
@client.command()
async def start(ctx):
if current_voice_channel == 0:
await ctx.send('Please set current voice channel')
return
guild_obj = get_guild(ctx.guild.name)
if ctx.message.author.id != instructor:
await ctx.send('Missing Permissions. Please check !help')
return
# sets lesson mode
change_lesson_mode(True)
# mute all members in the voice channel
for member in guild_obj.get_channel(current_voice_channel).members:
if member.id != instructor:
await guild_obj.get_member(member.id).edit(mute=True)
await ctx.send('Lesson Started! All users muted')
# ends class
@client.command()
async def end(ctx):
guild_obj = get_guild(ctx.guild.name)
if ctx.message.author.id != instructor:
await ctx.send('Missing Permissions. Please check !help')
return
# sets lesson mode
change_lesson_mode(False)
# unmute all members in the voice channel
for member in guild_obj.get_channel(current_voice_channel).members:
await guild_obj.get_member(member.id).edit(mute=False)
await ctx.send('All users unmuted')
# command to count attendence
@client.command()
async def attendance(ctx, *, student_name):
time_now = datetime.now()
normpath = os.path.normpath(os.getcwd())
data_folder = Path(normpath)
attendance_path = data_folder / 'Attendance' / f'attendance_{ctx.guild.name}_{datetime.now().date()}.txt'
attendance_path = PureWindowsPath(attendance_path)
attendance_file = open(attendance_path, 'a')
attendance_file.write(f'{time_now.time()} {student_name}\n')
attendance_file.close()
await ctx.message.add_reaction("✅")
# poll command for creating new polls
@client.command()
async def poll(ctx, *, input_string):
input_list = input_string.split('? ')
if len(input_list) != 2:
await ctx.send('Formatting for polls should be: `!poll <question>? <option1>:<option2>`')
return
input_question = input_list[0] + '?'
answers = input_list[1].split(':')
emoji_list = ["🐌", "🐇", "🐘", "🐖", "🐏", "🐍", "🐬"]
output_list = [f"Poll: {input_question}\n"]
if len(answers) > 7:
await ctx.send('Too many answers, please reduce the number of answers.')
return
for indx, val in enumerate(answers):
output_list.append(emoji_list[indx] + f" - {val}\n")
output_string = ''.join([str(elem) for elem in output_list])
msg = await ctx.send(output_string)
for indx, val in enumerate(answers):
await msg.add_reaction(emoji_list[indx])
await ctx.message.delete()
# change default help commands
client.remove_command('help')
@client.command()
async def help(ctx):
await bothelp(ctx)
# clears user queue for questions
@client.command()
async def clear_queue(ctx):
guild_obj = get_guild(ctx.guild.name)
if ctx.message.author.id != instructor:
await ctx.send('Missing Permissions. Please check !help')
return
global user_queue
user_queue = []
await ctx.send('Queue has been cleared.')
# mutes everyone if cleared while unmuted
for member in guild_obj.get_channel(current_voice_channel).members:
if member.id != instructor:
await guild_obj.get_member(member.id).edit(mute=True)
# bothelp command with refrence for users
@client.command()
async def bot_help(ctx):
if ctx.message.author.id == instructor:
instructor_embed = discord.Embed(
title='Instructor Comands',
description='Commands for Instructors',
color=discord.Colour.purple()
)
instructor_embed.set_thumbnail(url='https://i.imgur.com/v8CwNn0.png')
instructor_embed.add_field(name='!start', value='start class, will mute users in voice chat', inline=False)
instructor_embed.add_field(name='!end', value='ends class, will unmutes all users in voice chat', inline=False)
instructor_embed.add_field(name='!qauto', value='changes questions to cycle automatically', inline=False)
instructor_embed.add_field(name='!qsingle', value='changes questions to cycle one at a time', inline=False)
instructor_embed.add_field(name='!next', value='cycles to the next student in line', inline=False)
instructor_embed.add_field(name='!clearqueue', value='clears voice queue for questions', inline=False)
instructor_embed.add_field(name='!changechannel <channel_id>', value='changes current voice channel', inline=False)
instructor_embed.add_field(name='!changeinstructor <instructor_id>', value='changes current instructor', inline=False)
await ctx.send(embed=instructor_embed)
else:
embed = discord.Embed(
title='Student Commands',
description='Commands for Students',
color=discord.Colour.blue()
)
embed.set_thumbnail(url='https://i.imgur.com/v8CwNn0.png')
embed.add_field(name='!attendance {student name}', value='logs the student to the attendance log', inline=False)
embed.add_field(name='!talk', value='adds the user to the voice queue', inline=False)
embed.add_field(name='!done', value='removes the user from the voice queue', inline=False)
embed.add_field(name='!queue', value='shows current queue to ask questions', inline=False)
embed.add_field(name='!poll', value='creates a reaction poll with format [`!poll <question>? <option1>:<option2>`]', inline=False)
await ctx.send(embed=embed)
client.run(token)