-
Notifications
You must be signed in to change notification settings - Fork 0
/
red.py
2057 lines (1879 loc) · 77.4 KB
/
red.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
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
################################
######## Red - Discord bot #####
################################
# made by Twentysix
#
#
import discord
import logging
import time
import datetime
import requests
import aiohttp
import traceback
import re
import youtube_dl
import os
import asyncio
import glob
from os import path
from random import choice, randint, shuffle
import dataIO #IO settings, proverbs, etc
import economy #Credits
import youtubeparser
from sys import modules
#settings = {"PREFIX" : "!"} #prevents boot error
def loadHelp():
global help, audio_help, meme_help, admin_help, trivia_help
help = """**Commands list:**
{0}flip - Flip a coin
{0}rps [rock or paper o scissors] - Play rock paper scissors
{0}proverb
{0}choose option1 or option2 or option3 (...) - Random choice
{0}8 [question] - Ask 8 ball
{0}sw - Start/stop the stopwatch
{0}avatar [name or mention] - Shows user's avatar
{0}trivia start - Start a trivia session
{0}trivia stop - Stop a trivia session
{0}twitch [stream] - Check if stream is online
{0}twitchalert [stream] - Whenever the stream is online the bot will send an alert in the channel (admin only)
{0}stoptwitchalert [stream] - Stop sending alerts about the specified stream in the channel (admin only)
{0}roll [number] - Random number between 0 and [number]
{0}gif [text] - GIF search
{0}imdb - Retrieves a movie's information from IMDB using its title
{0}urban [text] - Search definitions in the urban dictionary
{0}meme [ID;Text1;Text2] - Create a meme
{0}imdb [search terms] - Search on IMDB
{0}customcommands - Custom commands' list
{0}addcom [command] [text] - Add a custom command
{0}editcom [command] [text] - Edit a custom command
{0}delcom [command] - Delete a custom command
{0}meme help - Memes help
{0}audio help - Audio related commands
{0}economy - Economy explanation, if available
{0}trivia - Trivia commands and lists
""".format(settings["PREFIX"])
audio_help = """
**General audio help commands:**
{0}next or {0}skip - Next song
{0}prev - Previous song
{0}pause - Pause song
{0}resume - Resume song
{0}repeat or {0}replay - Replay current song
{0}title or {0}song - Current song's title + link
{0}youtube [link] - Play a youtube video in a voice channel
{0}sing - Make Red sing
{0}stop - Stop any voice channel activity
{0}volume [0-1] - Sets the volume
{0}downloadmode - Disables/enables download mode (admin only)
**Playlist commands:**
{0}play [playlist_name] - Play chosen playlist
{0}playlists - Playlists' list
{0}shuffle - Mix music list
{0}addplaylist [name] [link] - Add a youtube playlist. Link format example: https://www.youtube.com/playlist?list=PLe8jmEHFkvsaDOOWcREvkgFoj6MD0pXXX
{0}delplaylist [name] - Delete a youtube playlist. Limited to author and admins.
{0}getplaylist - Receive the current playlist through DM. This also works with favorites.
**Local commands:**
{0}local [playlist_name] - Play chosen local playlist
{0}locallist or {0}local or {0}locals - Local playlists' list
**Favorites:**
{0}addfavorite - Add song to your favorites
{0}delfavorite - Remove song from your favorites
{0}playfavorites - Play your favorites
**You can submit your own playlist by doing the following:**
1) Make a txt file. Name must be only letters, numbers and underscores. It will be your playlist's name, so choose wisely.
2) One youtube link each line.
3) Send me the txt. If any line is incorrect I will reject it.
4) Listen to it with {0}play [playlist_name]!
""".format(settings["PREFIX"])
meme_help = """
Usage example:
One-Does-Not-Simply Template ID: 61579
{0}meme 61579;Test;Test
Memes list:
ID Name
61579 One Does Not Simply
438680 Batman Slapping Robin
61532 The Most Interesting Man In The World
101470 Ancient Aliens
61520 Futurama Fry
347390 X, X Everywhere
5496396 Leonardo Dicaprio Cheers
61539 First World Problems
61546 Brace Yourselves X is Coming
16464531 But Thats None Of My Business
61582 Creepy Condescending Wonka
61585 Bad Luck Brian
563423 That Would Be Great
61544 Success Kid
405658 Grumpy Cat
101288 Third World Skeptical Kid
8072285 Doge
100947 Matrix Morpheus
1509839 Captain Picard Facepalm
61533 X All The Y
1035805 Boardroom Meeting Suggestion
245898 Picard Wtf
21735 The Rock Driving
259680 Am I The Only One Around Here
14230520 Black Girl Wat
40945639 Dr Evil Laser
235589 Evil Toddler
61580 Too Damn High
61516 Philosoraptor
6235864 Finding Neverland
9440985 Face You Make Robert Downey Jr
101287 Third World Success Kid
100955 Confession Bear
444501 The lie detector determined that was a lie. The fact that you X determined that was a lie. Maury Povich.
97984 Disaster Girl
442575 Aint Nobody Got Time For That
109765 Ill Just Wait Here
124212 Say That Again I Dare You
28251713 Oprah You Get A
61556 Grandma Finds The Internet
101440 10 Guy
101711 Skeptical Baby
101716 Yo Dawg Heard You
101511 Dont You Squidward
For more memes: `https://imgflip.com/memetemplates`
Choose a meme, click on "Blank Template" then add the ID
""".format(settings["PREFIX"])
admin_help = """
**Admin commands:**
{0}addwords [word1 word2 (...)] [phrase/with/many/words] - Add words to message filter
{0}removewords [word1 word2 (...)] [phrase/with/many/words] - Remove words from message filter
{0}addregex [regex] - Add regular expression to message filter
{0}removeregex [regex] - Remove regular expression from message filter
{0}shutdown - Shutdown the bot
{0}join [invite] - Join another server
{0}leaveserver - Leave server
{0}shush - Ignore the current channel
{0}talk - Stop ignoring the current channel
{0}reload - Reload most files. Useful in case of manual edits
{0}name [name] - Change the bot's name
{0}cleanup [number] - Delete the last [number] messages
{0}cleanup [name/mention] [number] - Delete the last [number] of messages by [name]
{0}blacklist [name/mention] - Add user to Red's blacklist
{0}forgive [name/mention] - Removes user from Red's blacklist
{0}setting [setting] [value] - Modify setting
""".format(settings["PREFIX"])
trivia_help = """
**Trivia commands:**
{0}trivia - Trivia questions lists and help
{0}trivia [name] - Starts trivia session with specified list
{0}trivia random - Starts trivia session with random list
{0}trivia stop - Stop trivia session
""".format(settings["PREFIX"])
youtube_dl_options = {
'format': 'bestaudio/best',
'extractaudio': True,
'audioformat': "mp3",
'outtmpl': '%(id)s',
'noplaylist': True,
'nocheckcertificate': True,
'ignoreerrors': True,
'quiet': True,
'no_warnings': True,
'outtmpl': "cache/%(id)s"}
client = discord.Client()
if not discord.opus.is_loaded():
discord.opus.load_opus('libopus-0.dll')
@client.async_event
async def on_message(message):
global trivia_sessions
p = settings["PREFIX"]
await gameSwitcher.changeGame()
if message.author.id in blacklisted_users and not isMemberAdmin(message):
return False
if message.channel.is_private and message.attachments != []:
await transferPlaylist(message)
if not message.channel.is_private and message.author.id != client.user.id:
if settings["FILTER"] and not isMemberAdmin(message):
if await checkFilter(message) or await checkRegex(message):
return False #exits without checking for commands
if message.channel.id in shush_list and message.content == p + "talk":
await talk(message)
if message.channel.id not in shush_list:
if message.content == client.user.name.upper() or message.content == client.user.name.upper() + "?":
await client.send_message(message.channel, "`" + choice(greetings_caps) + "`")
elif message.content.lower() == client.user.name.lower() + "?":
await client.send_message(message.channel, "`" + choice(greetings) + "`")
elif message.content == client.user.mention + " ?" or message.content == client.user.mention + "?":
await client.send_message(message.channel, "`" + choice(greetings) + "`")
elif message.content == p + "flip":
await client.send_message(message.channel, "*flips a coin and... " + choice(["HEADS!*", "TAILS!*"]))
elif message.content.startswith(p + "rps"):
await rpsgame(message)
elif message.content == p + "proverb":
await client.send_message(message.channel, "`" + choice(proverbs) + "`")
elif message.content == p + "help":
await client.send_message(message.author, help)
await client.send_message(message.channel, "{} `Check your DMs for the command list.`".format(message.author.mention))
elif message.content.startswith(p + 'choose'):
await randomchoice(message)
elif message.content.startswith(p + '8 ') and message.content.endswith("?") and len(message.content) > 5:
await client.send_message(message.channel, "{}: ".format(message.author.mention) + "`" + choice(ball) + "`")
elif message.content.startswith(p + 'roll'):
await roll(message)
elif message.content.startswith(p + 'addcom'):
await addcom(message)
elif message.content.startswith(p + 'editcom'):
await editcom(message)
elif message.content.startswith(p + 'delcom'):
await delcom(message)
elif message.content == p + "customcommands":
await listCustomCommands(message)
elif message.content.startswith(p + 'sw'):
await stopwatch(message)
elif message.content.startswith(p + 'id'):
await client.send_message(message.channel, "{} `Your id is {}`".format(message.author.mention, message.author.id))
elif message.content.startswith(p + 'twitchalert'):
await addTwitchAlert(message)
elif message.content.startswith(p + 'stoptwitchalert'):
await removeTwitchAlert(message)
elif message.content.startswith(p + 'twitch'):
await twitchCheck(message)
elif message.content.startswith(p + 'image'):
#image(message)
pass
elif message.content.startswith(p + 'gif'):
await gif(message)
elif message.content.startswith(p + 'imdb'):
await imdb(message)
elif message.content.startswith(p + 'urban'):
await urban(message)
elif message.content.startswith(p + 'uptime'):
await uptime(message)
elif message.content.startswith(p + 'avatar'):
await avatar(message)
elif message.content == p + 'meme help' or message.content == p + 'memes':
await client.send_message(message.author, meme_help)
await client.send_message(message.channel, "{} `Check your DMs for " + p +"meme help.`".format(message.author.mention))
elif message.content.startswith (p + 'meme'):
await memes(message)
elif message.content.startswith (p + 'lmgtfy'):
await lmgtfy(message)
################## music #######################
elif message.content == p + "sing":
await playPlaylist(message, sing=True)
elif message.content.startswith(p + 'youtube'):
await playVideo(message)
elif message.content.startswith(p + 'play '):
await playPlaylist(message)
elif message.content.startswith(p + 'local '):
await playLocal(message)
elif message.content == p + "local" or message.content == p + "locallist" or message.content == p + "locals":
await listLocal(message)
await client.send_message(message.channel, "{} `Check your DMs for the local playlists list.`".format(message.author.mention))
elif message.content == p + "stop":
await leaveVoice()
elif message.content == p + "playlist" or message.content == p + "playlists":
await listPlaylists(message)
await client.send_message(message.channel, "{} `Check your DMs for the playlists list.`".format(message.author.mention))
elif message.content == p + "skip" or message.content == p + "next":
if currentPlaylist: currentPlaylist.nextSong(currentPlaylist.getNextSong())
elif message.content == p + "prev" or message.content == p + "previous":
if currentPlaylist: currentPlaylist.nextSong(currentPlaylist.getPreviousSong())
elif message.content == p + "repeat" or message.content == p + "replay":
if currentPlaylist: currentPlaylist.nextSong(currentPlaylist.current)
elif message.content == p + "pause":
if currentPlaylist: currentPlaylist.pause()
elif message.content == p + "resume":
if currentPlaylist: currentPlaylist.resume()
elif message.content == p + "shuffle":
if currentPlaylist: currentPlaylist.shuffle()
elif message.content == p + "song" or message.content == p + "title" :
if currentPlaylist: await getSongTitle(message)
elif message.content == p + "audio help":
await client.send_message(message.author, audio_help)
await client.send_message(message.channel, "{} `Check your DMs for the audio help.`".format(message.author.mention))
elif message.content.startswith(p + "addplaylist"):
await addPlaylist(message)
elif message.content.startswith(p + "delplaylist"):
await delPlaylist(message)
elif message.content == p + "addfavorite":
await addToFavorites(message)
elif message.content == p + "delfavorite":
await removeFromFavorites(message)
elif message.content == p + "playfavorites":
await playFavorites(message)
elif message.content == p + "getplaylist":
await sendPlaylist(message)
elif message.content.startswith(p + "volume"):
await setVolume(message)
elif message.content == p + "downloadmode":
await downloadMode(message)
elif message.content == p + "endpoll":
await endPoll(message)
elif message.content.startswith(p + "poll"):
await startPoll(message)
################################################
elif message.content == p + "trivia":
await triviaList(message)
elif message.content.startswith(p + "trivia"):
if checkAuth("Trivia", message, settings):
if message.content == p + "trivia stop":
if getTriviabyChannel(message.channel):
await getTriviabyChannel(message.channel).endGame()
await client.send_message(message.channel, "`Trivia stopped.`")
else:
await client.send_message(message.channel, "`There's no trivia session ongoing in this channel.`")
elif not getTriviabyChannel(message.channel):
t = Trivia(message)
trivia_sessions.append(t)
await t.loadQuestions(message.content)
else:
await client.send_message(message.channel, "`A trivia session is already ongoing in this channel.`")
else:
await client.send_message(message.channel, "`Trivia is currently admin-only.`")
######## Admin commands #######################
elif message.content.startswith(p + 'addwords'):
await addBadWords(message)
elif message.content.startswith(p + 'removewords'):
await removeBadWords(message)
elif message.content.startswith(p + 'addregex ') and len(message.content) > 11:
await addRegex(message)
elif message.content.startswith(p + 'removeregex ') and len(message.content) > 14:
await removeRegex(message)
elif message.content == p + "shutdown":
await shutdown(message)
elif message.content.startswith(p + 'join'):
await join(message)
elif message.content == p + "leaveserver":
await leave(message)
elif message.content == p + "shush":
await shush(message)
elif message.content == p + "talk": #prevents !talk custom command
pass
elif message.content == p + "reload":
await reloadSettings(message)
elif message.content.startswith(p + "name"):
await changeName(message)
elif message.content.startswith(p + "cleanup"):
await cleanup(message)
elif message.content == p + "admin help":
if isMemberAdmin(message):
await client.send_message(message.author, admin_help)
else:
await client.send_message(message.channel, "`Admin status required.`")
elif message.content.startswith(p + "debug"):
await debug(message)
elif message.content.startswith(p + "exec"):
await execFunc(message)
elif message.content.startswith(p + "blacklist"):
await blacklist(message, "add")
elif message.content.startswith(p + "forgive"):
await blacklist(message, "remove")
elif message.content.startswith(p + "setting"):
await modifySettings(message)
###################################
elif getTriviabyChannel(message.channel): #check if trivia is ongoing in the channel
trvsession = getTriviabyChannel(message.channel)
await trvsession.checkAnswer(message)
elif "economy" in modules:
await economy.checkCommands(message)
if getPollByChannel(message):
getPollByChannel(message).checkAnswer(message)
if message.content.startswith(p) and len(message.content) > 2 and settings["CUSTOMCOMMANDS"]:
await customCommand(message)
@client.async_event
async def on_ready():
logger.info("I'm online " + "(" + client.user.id + ")")
print("THIS VERSION IS OBSOLETE AND NO LONGER BEING SUPPORTED.")
print("USE THE CURRENT ONE: https://github.com/Twentysix26/Red-DiscordBot/")
await gameSwitcher.changeGame(now=True)
# cns = threading.Thread(target=console, args=[])
# cns.start() # console, WIP
@client.async_event
def on_message_delete(message):
# WIP. Need to check for permissions
#await client.send_message(message.channel, "{} `I have deleted your message.`".format(message.author.mention))
pass
@client.async_event
async def on_message_edit(before, message):
if message.author.id != client.user.id and settings["FILTER"] and not isMemberAdmin(message) and not message.channel.is_private:
await checkFilter(message)
await checkRegex(message)
def loggerSetup():
#api wrapper
logger = logging.getLogger('discord')
logger.setLevel(logging.WARNING)
handler = logging.FileHandler(filename='wrapper.log', encoding='utf-8', mode='a')
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s', datefmt="[%d/%m/%Y %H:%M]"))
logger.addHandler(handler)
#Red
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s', datefmt="[%d/%m/%Y %H:%M]"))
logger.addHandler(handler)
file_handler = logging.FileHandler(filename="red.log", mode='a')
file_formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s', datefmt="[%d/%m/%Y %H:%M]")
file_handler.setFormatter(file_formatter)
logger.addHandler(file_handler)
return logger
class Trivia():
def __init__(self, message):
self.gaveAnswer = ["I know this one! {}!", "Easy: {}.", "Oh really? It's {} of course."]
self.currentQ = None # {"QUESTION" : "String", "ANSWERS" : []}
self.questionList = ""
self.channel = message.channel
logger.info("Trivia started in channel " + self.channel.id)
self.scoreList = {}
self.status = None
self.timer = None
self.count = 0
async def loadQuestions(self, msg):
msg = msg.split(" ")
if len(msg) == 2:
_, qlist = msg
if qlist == "random":
chosenList = choice(glob.glob("trivia/*.txt"))
self.questionList = self.loadList(chosenList)
self.status = "new question"
self.timeout = time.perf_counter()
if self.questionList: await self.newQuestion()
else:
if os.path.isfile("trivia/" + qlist + ".txt"):
self.questionList = self.loadList("trivia/" + qlist + ".txt")
self.status = "new question"
self.timeout = time.perf_counter()
if self.questionList: await self.newQuestion()
else:
await client.send_message(self.channel, "`There is no list with that name.`")
await self.stopTrivia()
else:
await client.send_message(self.channel, "`" + settings["PREFIX"] + "trivia [list name]`")
async def stopTrivia(self):
global trivia_sessions
self.status = "stop"
trivia_sessions.remove(self)
logger.info("Trivia stopped in channel " + self.channel.id)
async def endGame(self):
global trivia_sessions
self.status = "stop"
if self.scoreList:
await self.sendTable()
trivia_sessions.remove(self)
logger.info("Trivia stopped in channel " + self.channel.id)
def loadList(self, qlist):
with open(qlist, "r", encoding="utf-8") as f:
qlist = f.readlines()
parsedList = []
for line in qlist:
if "`" in line and len(line) > 4:
line = line.replace("\n", "")
line = line.split("`")
question = line[0]
answers = []
for l in line[1:]:
answers.append(l.lower())
if len(line) >= 2:
line = {"QUESTION" : question, "ANSWERS": answers} #string, list
parsedList.append(line)
if parsedList != []:
return parsedList
else:
self.stopTrivia()
return None
async def newQuestion(self):
for score in self.scoreList.values():
if score == settings["TRIVIA_MAX_SCORE"]:
await self.endGame()
return True
if self.questionList == []:
await self.endGame()
return True
self.currentQ = choice(self.questionList)
self.questionList.remove(self.currentQ)
self.status = "waiting for answer"
self.count += 1
self.timer = int(time.perf_counter())
await client.send_message(self.channel, "**Question number {}!**\n\n{}".format(str(self.count), self.currentQ["QUESTION"]))
while self.status != "correct answer" and abs(self.timer - int(time.perf_counter())) <= settings["TRIVIA_DELAY"]:
if abs(self.timeout - int(time.perf_counter())) >= settings["TRIVIA_TIMEOUT"]:
await client.send_message(self.channel, "Guys...? Well, I guess I'll stop then.")
await self.stopTrivia()
return True
await asyncio.sleep(1) #Waiting for an answer or for the time limit
if self.status == "correct answer":
self.status = "new question"
await asyncio.sleep(3)
if not self.status == "stop":
await self.newQuestion()
elif self.status == "stop":
return True
else:
msg = choice(self.gaveAnswer).format(self.currentQ["ANSWERS"][0])
if settings["TRIVIA_BOT_PLAYS"]:
msg += " **+1** for me!"
self.addPoint(client.user.name)
self.currentQ["ANSWERS"] = []
await client.send_message(self.channel, msg)
await client.send_typing(self.channel)
await asyncio.sleep(3)
if not self.status == "stop":
await self.newQuestion()
async def sendTable(self):
self.scoreList = sorted(self.scoreList.items(), reverse=True, key=lambda x: x[1]) # orders score from lower to higher
t = "```Scores: \n\n"
for score in self.scoreList:
t += score[0] # name
t += "\t"
t += str(score[1]) # score
t += "\n"
t += "```"
await client.send_message(self.channel, t)
async def checkAnswer(self, message):
self.timeout = time.perf_counter()
for answer in self.currentQ["ANSWERS"]:
if answer in message.content.lower():
self.currentQ["ANSWERS"] = []
self.status = "correct answer"
self.addPoint(message.author.name)
await client.send_message(self.channel, "You got it {}! **+1** to you!".format(message.author.name))
await client.send_typing(self.channel)
return True
def addPoint(self, user):
if user in self.scoreList:
self.scoreList[user] += 1
else:
self.scoreList[user] = 1
def getTriviaQuestion(self):
q = choice(list(trivia_questions.keys()))
return q, trivia_questions[q] # question, answer
class botPlays():
def __init__(self):
self.games = dataIO.fileIO("json/games.json", "load")
self.lastChanged = int(time.perf_counter())
self.delay = 300
async def changeGame(self, now=False):
if abs(self.lastChanged - int(time.perf_counter())) >= self.delay or now:
self.lastChanged = int(time.perf_counter())
await client.change_status(discord.Game(name=choice(self.games)))
class Playlist():
def __init__(self, filename=None): #a playlist with a single song is just there to make !addfavorite work with !youtube command
self.filename = filename
self.current = 0
self.stop = False
self.lastAction = 999
self.currentTitle = ""
self.type = filename["type"]
if filename["type"] == "playlist":
self.playlist = dataIO.fileIO("playlists/" + filename["filename"] + ".txt", "load")["playlist"]
elif filename["type"] == "favorites":
self.playlist = dataIO.fileIO("favorites/" + filename["filename"] + ".txt", "load")
elif filename["type"] == "local":
self.playlist = filename["filename"]
elif filename["type"] == "singleSong":
self.playlist = [filename["filename"]]
self.playSingleSong(self.playlist[0])
else:
raise("Invalid playlist call.")
if filename["type"] != "singleSong":
self.nextSong(0)
def nextSong(self, nextTrack, lastError=False):
global musicPlayer
if not self.passedTime() < 1 and not self.stop: #direct control
if musicPlayer: musicPlayer.stop()
self.lastAction = int(time.perf_counter())
try:
if isPlaylistValid([self.playlist[nextTrack]]): #Checks if it's a valid youtube link
if settings["DOWNLOADMODE"]:
path = self.getVideo(self.playlist[nextTrack])
try:
logger.info("Starting track...")
musicPlayer = client.voice.create_ffmpeg_player("cache/" + path, options='''-filter:a "volume={}"'''.format(settings["VOLUME"]))
musicPlayer.start()
except:
logger.warning("Something went wrong with track " + self.playlist[self.current])
if not lastError: #prevents error loop
self.lastAction = 999
self.nextSong(self.getNextSong(), lastError=True)
else: #Stream mode. Buggy.
musicPlayer = client.voice.create_ytdl_player(self.playlist[nextTrack], options=youtube_dl_options)
musicPlayer.start()
else: # must be a local playlist then
musicPlayer = client.voice.create_ffmpeg_player(self.playlist[nextTrack], options='''-filter:a "volume={}"'''.format(settings["VOLUME"]))
musicPlayer.start()
except Exception as e:
logger.warning("Something went wrong with track " + self.playlist[self.current])
if not lastError: #prevents error loop
self.lastAction = 999
self.nextSong(self.getNextSong(), lastError=True)
def getVideo(self, url):
try:
yt = youtube_dl.YoutubeDL(youtube_dl_options)
v = yt.extract_info(url, download=False)
if not os.path.isfile("cache/" + v["id"]):
logger.info("Track not in cache, downloading...")
v = yt.extract_info(url, download=True)
self.currentTitle = v["title"]
return v["id"]
except Exception as e:
logger.error(e)
return False
def playSingleSong(self, url):
global musicPlayer
if settings["DOWNLOADMODE"]:
v = self.getVideo(url)
if musicPlayer:
if musicPlayer.is_playing():
musicPlayer.stop()
if v:
musicPlayer = client.voice.create_ffmpeg_player("cache/" + v, options='''-filter:a "volume={}"'''.format(settings["VOLUME"]))
musicPlayer.start()
else:
if musicPlayer:
if musicPlayer.is_playing():
musicPlayer.stop()
musicPlayer = client.voice.create_ytdl_player(self.playlist[0], options=youtube_dl_options)
musicPlayer.start()
async def songSwitcher(self):
while not self.stop:
if musicPlayer.is_done() and not self.stop:
self.nextSong(self.getNextSong())
await asyncio.sleep(0.5)
def passedTime(self):
return abs(self.lastAction - int(time.perf_counter()))
def getPreviousSong(self):
try:
song = self.playlist[self.current-1]
self.current -= 1
return self.current
except: #if the current song was the first song, returns the last in the playlist
song = self.playlist[len(self.current)-1]
self.current -= 1
return self.current
def getNextSong(self):
try:
song = self.playlist[self.current+1]
self.current += 1
return self.current
except: #if the current song was the last song, returns the first in the playlist
song = self.playlist[0]
self.current = 0
return self.current
def pause(self):
if musicPlayer.is_playing() and not self.stop:
musicPlayer.pause()
def resume(self):
if not self.stop:
musicPlayer.resume()
def shuffle(self):
if not self.stop:
shuffle(self.playlist)
class Poll():
def __init__(self, message):
self.channel = message.channel
self.author = message.author.id
msg = message.content[6:]
msg = msg.split(";")
if len(msg) < 2: # Needs at least one question and 2 choices
self.valid = False
return None
else:
self.valid = True
self.already_voted = []
self.question = msg[0]
msg.remove(self.question)
self.answers = {}
i = 1
for answer in msg: # {id : {answer, votes}}
self.answers[i] = {"ANSWER" : answer, "VOTES" : 0}
i += 1
async def start(self):
msg = "**POLL STARTED!**\n\n{}\n\n".format(self.question)
for id, data in self.answers.items():
msg += "{}. *{}*\n".format(id, data["ANSWER"])
msg += "\nType the number to vote!"
await client.send_message(self.channel, msg)
await asyncio.sleep(settings["POLL_DURATION"])
if self.valid:
await self.endPoll()
async def endPoll(self):
global poll_sessions
self.valid = False
msg = "**POLL ENDED!**\n\n{}\n\n".format(self.question)
for data in self.answers.values():
msg += "*{}* - {} votes\n".format(data["ANSWER"], str(data["VOTES"]))
await client.send_message(self.channel, msg)
poll_sessions.remove(self)
def checkAnswer(self, message):
try:
i = int(message.content)
if i in self.answers.keys():
if message.author.id not in self.already_voted:
data = self.answers[i]
data["VOTES"] += 1
self.answers[i] = data
self.already_voted.append(message.author.id)
except ValueError:
pass
async def startPoll(message):
global poll_sessions
if not getPollByChannel(message):
p = Poll(message)
if p.valid:
poll_sessions.append(p)
await p.start()
else:
await client.send_message(message.channel, "`" + settings["PREFIX"] + "poll question;option1;option2 (...)`")
else:
await client.send_message(message.channel, "`A poll is already ongoing in this channel.`")
async def endPoll(message):
global poll_sessions
if getPollByChannel(message):
p = getPollByChannel(message)
if p.author == message.author.id or isMemberAdmin(message):
await getPollByChannel(message).endPoll()
else:
await client.send_message(message.channel, "`Only admins and the author can stop the poll.`")
else:
await client.send_message(message.channel, "`There's no poll ongoing in this channel.`")
def getPollByChannel(message):
for poll in poll_sessions:
if poll.channel == message.channel:
return poll
return False
async def addcom(message):
if checkAuth("ModifyCommands", message, settings):
msg = message.content.split()
if len(msg) > 2:
msg = message.content[8:] # removes !addcom
newcmd = msg[:msg.find(" ")] # extracts custom command
customtext = msg[msg.find(" ") + 1:] # extracts [text]
if len(newcmd) > 1 and newcmd.find(" ") == -1:
if not message.channel.server.id in commands:
commands[message.channel.server.id] = {}
cmdlist = commands[message.channel.server.id]
if newcmd not in cmdlist:
cmdlist[newcmd] = customtext
commands[message.channel.server.id] = cmdlist
dataIO.fileIO("json/commands.json", "save", commands)
logger.info("Saved commands database.")
await client.send_message(message.channel, "`Custom command successfully added.`")
else:
await client.send_message(message.channel, "`This command already exists. Use " + settings["PREFIX"] + "editcom [command] [text]`")
else:
await client.send_message(message.channel, "`" + settings["PREFIX"] + "addcom [command] [text]`")
else:
await client.send_message(message.channel, "`You don't have permissions to edit custom commands.`")
async def editcom(message):
if checkAuth("ModifyCommands", message, settings):
msg = message.content.split()
if len(msg) > 2:
msg = message.content[9:] # removes !editcom
cmd = msg[:msg.find(" ")] # extracts custom command
customtext = msg[msg.find(" ") + 1:] # extracts [text]
if message.channel.server.id in commands:
cmdlist = commands[message.channel.server.id]
if cmd in cmdlist:
cmdlist[cmd] = customtext
commands[message.channel.server.id] = cmdlist
dataIO.fileIO("json/commands.json", "save", commands)
logger.info("Saved commands database.")
await client.send_message(message.channel, "`Custom command successfully edited.`")
else:
await client.send_message(message.channel, "`That command doesn't exist. Use " + settings["PREFIX"] + "addcom [command] [text]`")
else:
await client.send_message(message.channel, "`There are no custom commands in this server. Use " + settings["PREFIX"] + "addcom [command] [text]`")
else:
await client.send_message(message.channel, "`" + settings["PREFIX"] + "editcom [command] [text]`")
else:
await client.send_message(message.channel, "`You don't have permissions to edit custom commands.`")
async def delcom(message):
if checkAuth("ModifyCommands", message, settings):
msg = message.content.split()
if len(msg) == 2:
if message.channel.server.id in commands:
cmdlist = commands[message.channel.server.id]
if msg[1] in cmdlist:
cmdlist.pop(msg[1], None)
commands[message.channel.server.id] = cmdlist
dataIO.fileIO("json/commands.json", "save", commands)
logger.info("Saved commands database.")
await client.send_message(message.channel, "`Custom command successfully deleted.`")
else:
await client.send_message(message.channel, "`That command doesn't exist.`")
else:
await client.send_message(message.channel, "`There are no custom commands in this server. Use " + settings["PREFIX"] + "addcom [command] [text]`")
else:
await client.send_message(message.channel, "`" + settings["PREFIX"] + "delcom [command]`")
else:
await client.send_message(message.channel, "`You don't have permissions to edit custom commands.`")
async def listCustomCommands(message):
msg = "Custom commands: \n\n```"
if message.channel.server.id in commands:
cmds = commands[message.channel.server.id].keys()
if cmds:
for i, d in enumerate(cmds):
if i % 4 == 0 and i != 0:
msg = msg + d + "\n"
else:
msg = msg + d + "\t"
msg += "```"
await client.send_message(message.author, msg)
else:
await client.send_message(message.author, "There are no custom commands.")
else:
await client.send_message(message.author, "There are no custom commands.")
def checkAuth(cmd, message, settings): #checks if those settings are on. If they are, it checks if the user is a owner
if cmd == "ModifyCommands":
if settings["EDIT_CC_ADMIN_ONLY"]:
if isMemberAdmin(message):
return True
else:
return False
else:
return True
elif cmd == "Trivia":
if settings["TRIVIA_ADMIN_ONLY"]:
if isMemberAdmin(message):
return True
else:
return False
else:
return True
else:
logger.error("Invalid call to checkAuth")
return False
async def rpsgame(message):
rps = {"rock" : ":moyai:",
"paper": ":page_facing_up:",
"scissors":":scissors:"
}
msg = message.content.lower().split(" ")
if len(msg) == 2:
_, userchoice = msg
if userchoice in rps.keys():
botchoice = choice(list(rps.keys()))
msgs = {
"win": " You win {}!".format(message.author.mention),
"square": " We're square {}!".format(message.author.mention),
"lose": " You lose {}!".format(message.author.mention)
}
if userchoice == botchoice:
await client.send_message(message.channel, rps[botchoice] + msgs["square"])
elif userchoice == "rock" and botchoice == "paper":
await client.send_message(message.channel, rps[botchoice] + msgs["lose"])
elif userchoice == "rock" and botchoice == "scissors":
await client.send_message(message.channel, rps[botchoice] + msgs["win"])
elif userchoice == "paper" and botchoice == "rock":
await client.send_message(message.channel, rps[botchoice] + msgs["win"])
elif userchoice == "paper" and botchoice == "scissors":
await client.send_message(message.channel, rps[botchoice] + msgs["lose"])
elif userchoice == "scissors" and botchoice == "rock":
await client.send_message(message.channel, rps[botchoice] + msgs["lose"])
elif userchoice == "scissors" and botchoice == "paper":
await client.send_message(message.channel, rps[botchoice] + msgs["win"])
else:
await client.send_message(message.channel, "`" + settings["PREFIX"] + "rps [rock or paper or scissors]`")
else:
await client.send_message(message.channel, "`" + settings["PREFIX"] + "rps [rock or paper or scissors]`")
async def randomchoice(message):
sentences = ["Mmm... I think I'll choose ", "I choose ", "I prefer ", "This one is best: ", "This: "]
msg = message.content[8:] # removes !choose
msg = msg.split(" or ")
if len(msg) == 1:
await client.send_message(message.channel, "`" + settings["PREFIX"] + "choose option1 or option2 or option3 (...)`")
elif len(msg) >= 2:
await client.send_message(message.channel, "`" + choice(sentences) + choice(msg) + "`")
else:
await client.send_message(message.channel, "`The options must be at least two.`")
async def stopwatch(message):
global stopwatches
if message.author.id in stopwatches:
tmp = abs(stopwatches[message.author.id] - int(time.perf_counter()))
tmp = str(datetime.timedelta(seconds=tmp))
await client.send_message(message.channel, "`Stopwatch stopped! Time: " + str(tmp) + " `")
stopwatches.pop(message.author.id, None)
else:
stopwatches[message.author.id] = int(time.perf_counter())
await client.send_message(message.channel, "`Stopwatch started! Use " + settings["PREFIX"] + "sw to stop it.`")
"""
async def image(message): # API's dead.
msg = message.content.split()
if len(msg) > 1:
if len(msg[1]) > 1 and len([msg[1]]) < 20:
try:
msg.remove(msg[0])
msg = "+".join(msg)
search = "http://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=" + msg + "&start=0"
result = requests.get(search).json()
url = result["responseData"]["results"][0]["url"]
await client.send_message(message.channel, url)
except:
await client.send_message(message.channel, "Error.")
else:
await client.send_message(message.channel, "Invalid search.")
else:
await client.send_message(message.channel, "!image [text]")
"""
async def imdb(message): # Method added by BananaWaffles.
msg = message.content.split()
if apis["MYAPIFILMS_TOKEN"] == "TOKENHERE":
await client.send_message(message.channel, "`This command wasn't configured properly. If you're the owner, edit json/apis.json`")
return False
if len(msg) > 1: