-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathbot.py
397 lines (283 loc) · 14.7 KB
/
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
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
387
388
389
390
391
392
393
394
395
396
397
from discord.ext import commands
from dotenv import load_dotenv
from bs4 import BeautifulSoup
from forex_python.converter import CurrencyRates, RatesNotAvailableError
from datetime import datetime
from dateutil import relativedelta
from requests import get as request
from qrcode import make as qr_make
import random
import discord
import os
import wikipedia
import embed as emb
# Load discord token (API) from env file
load_dotenv()
DISCORD_TOKEN = os.getenv('DISCORD_TOKEN')
# Change the !help from no category to commands
help_command = commands.DefaultHelpCommand(
no_category='Commands'
)
# Load intents
intents = discord.Intents.default()
intents.message_content = True
# Define discord bot and discord client
bot = commands.Bot(command_prefix='!', intents=intents, help_command=help_command)
# Variables
script_directory = os.path.abspath(os.path.dirname(__file__)) # Get script directory
# Command to send random image from images directory
@bot.command(name='image', help='Send random image to chat')
async def images(ctx):
all_files = os.listdir(f"{script_directory}/images")
allowed_extensions = ('.png', '.jpg', '.jpeg', '.gif')
# All available images with supported extensions
all_images = [file for file in all_files if
file.endswith(allowed_extensions)]
# Choose random image and add path to it
random_image = f"{script_directory}/images/{random.choice(all_images)}"
await ctx.send(file=discord.File(random_image))
# Command to send random text from file text.txt in text directory
@bot.command(name='text', help='Send random text')
async def send_random_text(ctx):
text_file_path = f"{script_directory}/text/text.txt"
with open(text_file_path) as file:
lines = [line for line in file.read().splitlines()]
# Split text inside line list
lines_with_split_text = [line.split(",") for line in lines]
# Choose from random line random text
random_line = random.choice(lines_with_split_text)
random_text = random.choice(random_line)
await emb.send_embed(ctx, title=random_text)
# Command to send wikipedia article based on the user input
@bot.command(name='whatis', help='Send wikipedia article about topic you write')
async def whatis(ctx, *args: str):
if args:
data = " ".join(args)
# Try if article exist
try:
article = wikipedia.summary(data, sentences=2)
await emb.send_embed(ctx, title=data.title(), description=article)
# If article doesn't exist or if exist more articles than 1
except (wikipedia.PageError, wikipedia.DisambiguationError):
articles = wikipedia.search(data, results=5)
# If something found
if articles:
articles = ", ".join(articles)
await emb.send_embed(ctx, title=f'{data.title()} can be : ', description=articles)
# If article doesn't exist
else:
await emb.send_embed(ctx, title="The article doesn't exist", color=0xFF0000)
else:
await emb.send_embed(ctx, title="Please enter a topic to search for", color=0xFF0000)
# Command to make qrcode based on the user input
@bot.command(name='qrcode', help="Make your own qrcode | !qrcode 'what you want in qrcode' ")
async def make_qrcode(ctx, *, data: str = None):
if data:
qr_code = qr_make(data) # Make qrcode
qr_filepath = f"{script_directory}/qr.png" # Where to save qrcode
qr_code.save(qr_filepath) # Save qrcode
await ctx.send(file=discord.File(qr_filepath))
os.remove(qr_filepath) # Delete the qrcode to save space on device
else:
await emb.send_embed(ctx, title='Please write !qrcode "what do you want in qrcode"', color=0xFF0000)
# Command to send news from www.bbc.com
@bot.command(name='news', help="Send top 3 news")
async def send_three_news(ctx):
url = 'https://www.bbc.com'
url_to_news = f'{url}/news/world/'
response = request(url_to_news)
soup = BeautifulSoup(response.text, 'html.parser')
get_promo_news = soup.select("[class~=gs-c-promo-heading]", href=True)
links = []
# Add only 3 news to list links with full url
for counter, news in enumerate(get_promo_news):
news_url = f'{url}{news["href"]}'
if news_url not in links and counter <= 3:
links.append(news_url)
elif counter > 3:
break
links = "\n".join(links)
await ctx.send(f"{links}")
# Command to rock, paper and scissors game
@bot.command(name='rpas', help="Rock Paper and Scissors game | !rpas 'your choice'")
async def rpas_game(ctx, player_choice: str = None):
if player_choice:
choices = ("rock", "paper", "scissors")
bot_choice = random.choice(choices)
if player_choice in choices:
# If tie
if bot_choice == player_choice:
await emb.send_embed(ctx, title="Tie", description=f"You both choose {bot_choice}", color=0x808080)
# If player win
elif bot_choice == "rock" and player_choice == "paper" or \
bot_choice == "scissors" and player_choice == "rock" or \
bot_choice == "paper" and player_choice == "scissors":
await emb.send_embed(ctx,
title="You win :tada:",
description=f"Bot choose {bot_choice}",
color=0x00ff00)
# If bot win
elif bot_choice == "rock" and player_choice == "scissors" or \
bot_choice == "paper" and player_choice == "rock" or \
bot_choice == "scissors" and player_choice == "paper":
await emb.send_embed(ctx, title="Bot win", description=f"Bot choose {bot_choice}", color=0xb41b1b)
else:
await emb.send_embed(ctx, title="Please choose only rock, scissors or paper", color=0xFF0000)
else:
await emb.send_embed(ctx, title="Please write !rpas 'your choice'", color=0xFF0000)
# Command to send random number in user defined range
@bot.command(name='random', help="Send random number | !random from 'number' to 'number' ")
async def choose_random_number(ctx, *arg):
if arg:
try:
# User numbers to integers
start_number, end_number = int(arg[1]), int(arg[3])
# If user write command in correct format
if arg[0] == "from" and arg[2] == "to" and start_number < end_number:
random_number = random.randrange(start_number, end_number + 1)
await emb.send_embed(ctx, title=f'Your random number is {random_number}')
elif start_number >= end_number:
await emb.send_embed(ctx, title="The first number should be smaller than the second", color=0xFF0000)
else:
await emb.send_embed(ctx, title='Write please : !random from "your number" to "your number"',
color=0xFF0000)
except ValueError:
await emb.send_embed(ctx, title="Write numbers please", color=0xFF0000)
except IndexError as e:
if str(e) == "tuple index out of range":
await emb.send_embed(ctx, title='Write please : !random from "your number" to "your number"',
color=0xFF0000)
else:
await emb.send_embed(ctx, title='Write please : !random from "your number" to "your number"',
color=0xFF0000)
# Command to guess the number game
@bot.command(name='gtn', help='Guess the number game')
async def guess_the_number(ctx):
await emb.send_embed(ctx, title="Guess the number between 1 - 100",
description='Write the number in the chat. If you want to exit type "exit"')
random_number = random.randrange(1, 101)
win = False
attempts = 1
while not win:
try:
# Wait for user number guess message
message = await bot.wait_for('message', timeout=15,
check=lambda m: m.author == ctx.author and m.channel.id == ctx.channel.id)
# If user wants to exit the game
if message.content == "exit":
await emb.send_embed(ctx, title="Thank you for playing")
break
# User input to int
user_guess = int(message.content)
if user_guess == random_number:
win = True
await emb.send_embed(ctx,
title="Congratulations",
description=f"You guessed the number on {attempts} try :tada:",
color=0x00ff00)
break
elif user_guess > random_number:
attempts += 1
await emb.send_embed(ctx, title="The number is lower")
continue
elif user_guess < random_number:
attempts += 1
await emb.send_embed(ctx, title='The number is higher')
continue
# If user input something else than number
except ValueError:
await emb.send_embed(ctx, title='Write number please', color=0xFF0000)
continue
# If time is up
except TimeoutError:
await emb.send_embed(ctx, title='Time is up !', color=0xFF0000)
break
# Command to convert currency to another currency based on the user input
@bot.command(name='convert', help='Convert currency to another currency | !convert from currency to currency amount')
async def convert_currency(ctx, from_currency: str = None, to_currency: str = None, amount: str = None):
try:
if from_currency and to_currency and amount:
# Change user input to upper case
from_currency, to_currency = from_currency.upper(), to_currency.upper()
amount = float(amount)
currency_rates = CurrencyRates()
# Convert user input
convert_result = currency_rates.convert(from_currency, to_currency, amount)
# Specified number of decimals
result = round(convert_result, 2)
await emb.send_embed(ctx, title=f"{amount} {from_currency} = {result} {to_currency}")
else:
await emb.send_embed(ctx, title='Please write !convert "from currency" "to currency" "amount"',
color=0xFF0000)
except ValueError:
await emb.send_embed(ctx, title='You entered wrong amount to convert', color=0xFF0000)
except RatesNotAvailableError:
await emb.send_embed(ctx, title='You entered bad currency, or currency is not supported', color=0xFF0000)
# Listen for banned words from the file words.txt in ban words directory
@bot.listen('on_message')
async def check_for_banned_words(msg):
message_content = msg.content.casefold()
words_file_path = f"{script_directory}/ban words/words.txt"
warn_message = f"{msg.author.mention} was warned"
# Get banned words from words.txt
with open(words_file_path) as file:
banned_words_lines = [line for line in file.read().splitlines()]
# Split words with , and add them in one list
banned_words = [line.split(",") for line in banned_words_lines]
banned_words = [word for lines in banned_words for word in lines]
user_banned_message = [word for word in banned_words if word in message_content]
# If user sent bad word
if any(user_banned_message):
await msg.channel.send(warn_message) and await msg.delete()
# Listen for interactions with bot and response
@bot.listen('on_message')
async def chat_with_bot(msg):
message_content = msg.content.casefold()
# All possible chat interactions variables
greetings = ("hi", "hello", "was-sup", "sup")
name_to_react = ("bot", "robot")
how_are_you_react = ("how are you", "how's it going", "what's up", "how are you doing", "how was your day")
how_old_are_you_react = ("how old are you", "what is your age")
user_greeting_msg = [greeting in message_content for greeting in greetings]
user_name_to_react_msg = [name in message_content for name in name_to_react]
user_how_are_you_react_msg = [x in message_content for x in how_are_you_react]
user_how_old_msg = [x in message_content for x in how_old_are_you_react]
user_bad_mood_msg = ("bad", "not good")
user_good_mood_msg = ("good", "well", "very good", "okay", "really good")
random_greeting = random.choice(greetings)
random_greeting = random_greeting.title()
# If the user greets the bot
if any(user_greeting_msg) and any(user_name_to_react_msg):
await msg.channel.send(f"{random_greeting} {msg.author.name} :wave:")
# If the user asks how the bot is doing
if any(name_to_react) and any(user_how_are_you_react_msg):
await msg.channel.send(f"I am good, and you ?")
# Wait for user message how he is doing
response = await bot.wait_for('message', timeout=30,
check=lambda m: m.author == msg.author and m.channel.id == msg.channel.id)
if response.content in user_bad_mood_msg:
await msg.channel.send(
f"Oh, I'm sorry about that :confused:\n"
f"If you want, you can play games with me type !help for more information :blush:")
elif response.content in user_good_mood_msg:
await msg.channel.send(f"I'm glad to hear that :relaxed:")
# If user asks how old is bot
if any(user_name_to_react_msg) and any(user_how_old_msg):
bot_created = datetime(year=2022, month=8, day=5)
current_date = datetime.utcnow()
bot_created, current_date = bot_created.date(), current_date.date()
age = relativedelta.relativedelta(current_date, bot_created)
await msg.channel.send(
f"I was created in {bot_created}\nSo i'm technically {age.years} years {age.months} months "
f"{age.days} days old :smile:")
# If command not found
@bot.event
async def on_command_error(ctx, error):
if isinstance(error, commands.CommandNotFound):
await emb.send_embed(ctx,
title="Command not found !",
description="If you want to check all available commands write !help.",
color=0xFF0000)
# Run bot
if __name__ == "__main__":
bot.run(DISCORD_TOKEN)