-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot.py
278 lines (227 loc) · 8.87 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
# Original work Copyright (c) 2015 Rapptz (https://github.com/Rapptz/RoboDanny)
# Modified work Copyright (c) 2017 Perry Fraser
#
# Licensed under the MIT License. https://opensource.org/licenses/MIT
#
# This copyright template is copied from @iwearapot#5464
import asyncio
import datetime
import logging
import random
import re
import sys
import traceback
import discord
import exrex
from discord.ext import commands
from discord.ext.commands.view import StringView
import config
from cogs.utils.config import Config
from cogs.utils.context import Context
from cogs.utils.paginator import CannotPaginate
description = "I'm a bot that does stuff"
log = logging.getLogger(__name__)
initial_extensions = [
'cogs.fun',
'cogs.admin',
'cogs.meta',
'cogs.mod',
'cogs.info',
'cogs.memes',
'cogs.search',
'cogs.humanize',
'cogs.jokes',
'cogs.custom',
'cogs.logging',
]
def _prefix(bot, msg):
user_id = bot.user.id
base = [f'<@{user_id}> ', f'<@!{user_id}> ']
if msg.guild is None:
base.extend(['-', ';', 'tor ', ''])
else:
base.extend(bot.prefixes.get(msg.guild.id, ['-']))
# None of these are regexs
base = [p if isinstance(p, list) else [p, False] for p in base]
return base
class TorGenius(commands.Bot):
def __init__(self):
super().__init__(
command_prefix=_prefix,
description=description,
pm_help=None,
help_attrs=dict(hidden=True)
)
_ = self.is_owner(discord.User)
# noinspection SpellCheckingInspection
self.game_list = ['corn', 'k', 'never gonna...', 'serdeff',
'lauye9r v7&^*^*111', 'no', 'no u', 'farts r funny']
self.token = exrex.getone(
r'([NM][a-zA-Z\d]{23}[.][a-zA-Z\d]{6}[.][a-zA-Z\d]{27})'
)
self.lockdown = {}
self.prefixes = Config('prefixes.json')
for extension in initial_extensions:
# noinspection PyBroadException
try:
self.load_extension(extension)
except Exception:
print(f'Failed to load extension {extension}.', file=sys.stderr)
traceback.print_exc()
# convenience prop
@property
def config(self):
return __import__('config')
async def on_command_error(self, ctx, error):
if isinstance(error, commands.NoPrivateMessage):
await ctx.author.send(
'This command cannot be used in private messages.'
)
elif isinstance(error, commands.DisabledCommand):
await ctx.author.send(
'Sorry. This command is disabled and cannot be used.'
)
elif isinstance(error, commands.MissingRequiredArgument):
await ctx.send(error)
elif isinstance(error, commands.TooManyArguments):
await ctx.send('You passed too many parameters for that command.')
elif isinstance(error, commands.CommandInvokeError):
log.warning(f'Command error on command {ctx.command.qualified_name}'
f' from {ctx.author}: \n {error.original.__traceback__}'
f'.See stdout/err for more details.')
print(
f'In {ctx.command.qualified_name}:',
file=sys.stderr
)
traceback.print_tb(error.original.__traceback__)
print(
f'{error.original.__class__.__name__}: {error.original}',
file=sys.stderr
)
elif isinstance(error, CannotPaginate):
await ctx.send(error)
elif isinstance(error, commands.CheckFailure):
if self.lockdown.get(ctx.channel, None):
return
if ctx.command.name == 'calc':
return await ctx.send(f'You are not allowed to use this '
f'command. If you want to do some math, '
f'try `{ctx.prefix}quick <question or '
f'math>`.')
await ctx.send('You are not allowed to use this command.')
def get_guild_prefixes(self, guild):
# top kek (https://github.com/Rapptz/RoboDanny/blob/rewrite/bot.py#L87)
fake_msg = discord.Object(None)
fake_msg.guild = guild
# not sure why lol
# noinspection PyTypeChecker
return _prefix(self, fake_msg)
def get_other_prefixes(self, guild):
"""
This is just so I can get prefixes that aren't the @bot ones
"""
guild_id = guild.id
return self.prefixes.get(guild_id, [';'])
async def set_guild_prefixes(self, guild, prefixes):
if len(prefixes) == 0:
# No prefixes yet
await self.prefixes.put(guild.id, [])
elif len(prefixes) >= 40:
# Why would anyone even do this
# Should be caught in prefix command
raise RuntimeError(
"A server can't have more than 40 custom prefixes."
)
else:
await self.prefixes.put(
guild.id,
# maybe a bad idea not to set this anymore. eh.
sorted(prefixes, reverse=True, key=lambda p: p[0])
)
async def on_ready(self):
print(f'Ready: {self.user} (ID: {self.user.id})')
if not hasattr(self, 'uptime'):
# noinspection PyAttributeOutsideInit
self.uptime = datetime.datetime.now()
game = random.choice(self.game_list)
await self.change_presence(
activity=(discord.Game(name=game))
)
async def get_context(self, message, *, cls=Context):
view = StringView(message.content)
ctx = cls(prefix=None, view=view, bot=self, message=message)
if self._skip_check(message.author.id, self.user.id):
return ctx
prefix = await self.get_prefix(message)
invoked_prefix = prefix
if isinstance(prefix, str):
if not view.skip_string(prefix):
return ctx
elif isinstance(prefix, list) \
and any([isinstance(p, list) for p in prefix]):
# Regex time
for p in prefix:
if isinstance(p, list):
if p[1]:
# regex prefix parsing
reg = re.match(p[0], message.content)
if reg:
if message.content == reg.groups()[0]:
# ignore * prefixes
continue
# Matches, this is the prefix
invoked_prefix = p
# redo the string view with the capture group
view = StringView(reg.groups()[0])
invoker = view.get_word()
ctx.invoked_with = invoker
ctx.prefix = invoked_prefix
ctx.command = self.all_commands.get(invoker)
ctx.view = view
return ctx
else:
# regex has highest priority or something idk
# what I'm doing help
continue
# No prefix found, use the branch below
prefix = [p[0] for p in prefix if not p[1]]
invoked_prefix = discord.utils.find(view.skip_string, prefix)
if invoked_prefix is None:
return ctx
else:
invoked_prefix = discord.utils.find(view.skip_string, prefix)
if invoked_prefix is None:
return ctx
invoker = view.get_word()
ctx.invoked_with = invoker
ctx.prefix = invoked_prefix
ctx.command = self.all_commands.get(invoker)
return ctx
async def process_commands(self, message):
ctx = await self.get_context(message, cls=Context)
if ctx.command is None:
if "just monika" in message.content.lower():
await ctx.send('Just Monika')
elif message.content == 'neat' and await self.is_owner(ctx.author) or message.content == 'sudo neat':
await ctx.send('neat')
return
async with ctx.acquire(ctx, None):
await self.invoke(ctx)
async def get_prefix(self, message):
prefix = ret = self.command_prefix
if callable(prefix):
ret = prefix(self, message)
if asyncio.iscoroutine(ret):
ret = await ret
return ret
async def on_message(self, message):
if message.author.bot:
return
await self.process_commands(message)
def run(self):
super().run(config.token, reconnect=True)
# ur face is a redeclaration
# noinspection PyRedeclaration
@property
def config(self):
return __import__('config')