-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdiscord_bot.py
205 lines (173 loc) · 7.42 KB
/
discord_bot.py
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
import discord
from Translator import Translator
from Content import Content
import time
import os
import time
translator = Translator()
supported_langs = translator.speech_langs
client = discord.Client()
README = "TODO\n"
COMMAND_PREFIX = '-bl'
CONFIG = {"lang": "Spanish", "voice_mode": "female"}
COMMANDS = {COMMAND_PREFIX: 0, 'join': 0, 'leave': 0, 'play': 0, 'translate': 1, 'list_quizzes': 0, 'quiz': 1, 'help': 0, '?': 0} # A dictionary of commands and the number of arguments taken by each command
Content = Content(translator, CONFIG["lang"])
def parse_command_args(message):
"""
This function separates out the command, arguments, and data from a user entered command
:param message: The command message the user entered
:return: command, A string: the command specified by the user,
arg_list, A list of strings representing the arguments passed by the user based on the number of arguments in COMMANDS,
data, A string: the data after the arguments passed by the user
"""
args = str(message.content).strip().lower().split(" ")
arg_list = []
args.pop(0) # removes command prefix
command = args.pop(0) # second arg in args is always command
num_args = COMMANDS[command]
i = 0
while i < num_args:
arg_list.append(args.pop(i))
i += 1
data = ' '.join(args) # create data/sentence from leftover stuff in args
print("command: ", command, "args: ", arg_list, "data: ", data)
return command, arg_list, data
@client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
def list_quizes():
"""Returns a string of available quizzes"""
s = ""
s += "To take a quiz, do -bl quiz [Name of Quiz] example: -bl quiz occupations\n"
s += "``` Quiz List:\n"
s += "1) Occupations\n"
s += "```"
# Write this with real code
return s
async def talk(text):
"""
Outputs audio to the discord bot in the detected language of the input text
:param text: A string, the message to say in any supported language
:return: None
"""
try:
message_in_english = translator.translate("en", text)
print(translator.detected_lang)
detected_lang_code = ""
for lang_code in supported_langs.values():
if lang_code[0:2] == translator.detected_lang:
detected_lang_code = lang_code
break
print(detected_lang_code)
voice_client = client.voice_clients[0]
translator.speak(detected_lang_code, text, CONFIG["voice_mode"])
encoded_audio = discord.FFmpegOpusAudio("./audio_data/temp/output.ogg")
voice_client.play(encoded_audio)
while voice_client.is_playing():
time.sleep(1)
os.remove("./audio_data/temp/output.ogg")
except IndexError:
print("Voice client not connected, translating without audio")
async def disconnect_vc(connected_voice_client):
"""
Disconnects a specified voice client from a voice channel
:param connected_voice_client: The currently connected voice client
:return: None
"""
try:
await connected_voice_client.disconnect()
except discord.errors.ClientException:
print("Cannot disconnect: The specified voice client is not connected or does not exist")
async def connect_vc(message):
"""
Connects the bot voice client to the voice channel of the message's author
:param message: The message sent including a command that would require the bot to join a voice channel
:return: The newly joined voice client
"""
try:
channel = message.author.voice.channel
return await channel.connect()
except discord.errors.ClientException:
print("Bot already connected to a channel")
except AttributeError:
print("User not connected to a channel")
@client.event
async def on_message(message):
async def say(message_to_say):
await message.channel.send(message_to_say)
if message.author == client.user:
return
if message.content.startswith(COMMAND_PREFIX): # If a user has entered a command
command, args, data = parse_command_args(message)
print("command: ", command, "args: ", args, "data: ", data)
if command == "join":
await connect_vc(message)
elif command == 'leave':
voice_client = client.voice_clients[0]
await disconnect_vc(voice_client)
elif command == 'play':
voice_client = client.voice_clients[0]
encoded_audio = discord.FFmpegOpusAudio("./audio_data/output.mp3")
voice_client.play(encoded_audio)
elif command == 'translate':
lang = args[0]
if lang not in supported_langs.keys():
data = args.pop(0) + " " + data
lang = CONFIG["lang"]
text = translator.translate(supported_langs[lang][0:2], data)
await say("Your message translated into " + lang + " is:\n```" + text + "```")
try:
voice_client = client.voice_clients[0]
translator.speak(supported_langs[lang], text, CONFIG["voice_mode"])
encoded_audio = discord.FFmpegOpusAudio( "./audio_data/temp/output.ogg" )
voice_client.play(encoded_audio)
while voice_client.is_playing():
time.sleep(1)
os.remove("./audio_data/temp/output.ogg")
except IndexError:
print("Voice client not connected, translating without audio")
# TODO: Command to output config
# TODO: Command to update config
elif command == 'help' or command == '?':
file_object = open("./command_list.txt", "r")
s = "List of possible commands:\n```"
for line in file_object:
s += line
s += "```"
await say(s)
elif command == 'list_quizzes':
await connect_vc(message)
await say(list_quizes())
elif command == 'quiz':
"""
Allows the user to take a quiz. Needs to get the quiz name,
then the id from a dict. Then, create a Content object, and then get
the specific Quiz. Then, the bot should speak verbally the question
and allow the user the type to answer. The Quiz object will tell if its
correct and then the bot can relay that info. If the quiz is done, the score
shoud be displayed.
"""
quiz_dict = {}
quiz_dict["occupations"] = 1
id = None
if args[0] not in quiz_dict.keys():
await say("Sorry, I don't have that quiz :(\n")
return
else:
id = quiz_dict[args[0]]
quiz = Content.get_quiz(id)
num_qs = quiz.num_qs()
for i in range(num_qs):
question = quiz.ask()
await say(question)
await talk(question)
answer = await client.wait_for("message", timeout=60)
was_correct, right_answer = quiz.answer(translator, answer.content)
if was_correct:
await say("You got that correct!")
else:
await say("Unfortunately, that answer was wrong.\n")
final_score = quiz.percent()
await say("You got a " + str(final_score) + "%!\n")
quiz.reset()
client.run('ODM2ODAyNjAwMjg0MDYxNzA1.YIjTJg.QyT9gAK6eLW2WROE1b7fKea2qbw')