-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbot.py
More file actions
221 lines (174 loc) · 7.41 KB
/
bot.py
File metadata and controls
221 lines (174 loc) · 7.41 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
# -*- coding: utf-8 -*-
"""
This software is licensed under the License (MIT) located at
https://github.com/ephreal/rollbot/Licence
Please see the license for any restrictions or rights granted to you by the
License.
"""
import os
import traceback
import json
import re
from datetime import datetime
from discord import Game, Intents
from discord.ext import commands
from utils.message_builder import on_join_builder
from utils.db import db_migration_handler
from utils.handlers import db_handler
def build_bot(prefix, restrict_rolling, description, catapi_key=None):
# Subscribing to all intents since I don't ever expect my bot to be large
# enough to require verification
intents = Intents.all()
# Removing the presences intents since it's not really necessary *AND*
# causes me a bit of slowdown.
intents.presences = False
BOT = commands.Bot(command_prefix=prefix, description=description, intents=intents)
@BOT.event
async def on_member_join(member):
guild = member.guild.id
if await BOT.db_handler.guilds.get_greeting_status(guild):
message = await BOT.db_handler.guilds.get_greeting(guild)
message = await on_join_builder(member, message)
await member.send(embed=message)
@BOT.event
async def on_ready():
"""
Post setup hook.
Initializes any necessary variables and sets the played game to
a message on how to get help.
"""
# Initialize needed variables
# initialize music players dict
BOT.players = {}
# Uptime statistic
BOT.boot_time = datetime.now()
# Whether or not rolling is restricted to rolling channels only
BOT.restrict_rolling = restrict_rolling
# Add in the database handlers
await database_migrations()
BOT.db_handler = db_handler.DBHandler()
BOT.catapi_key = catapi_key
# Load all cogs
print("Startup complete, loading Cogs....")
await load_cogs()
print("Cog loading complete.")
print("Connected to server and awaiting commands.")
# Set help message
help_message = Game(name=f"message '{prefix}help' for help")
if not hasattr(BOT, 'appinfo'):
BOT.appinfo = await BOT.application_info()
await BOT.change_presence(activity=help_message)
with open("utils/json/excuses.json", "r") as f:
BOT.excuses = json.loads(f.read())['excuses']
async def database_migrations():
"""
Ensures that the bot updates to the most recent database schema
"""
handler = db_migration_handler.DBMigrationHandler()
handler.prepare_next_migration()
choice = "n"
if handler.current_version != -1:
print("There are updates available for the bot database.")
print(f"Issues if not upgraded: {handler.migration.breaks}")
choice = input("Would you like to upgrade? y/n\n")
if choice.lower() == "y":
while handler.current_version != -1:
print("\n-----------------------------------------------")
print(f"Updating to version {handler.migration.version}")
print(f"Description: {handler.migration.description}")
print(f"Issues if not updated: {handler.migration.breaks}")
print("-----------------------------------------------\n")
handler.migrate()
handler.prepare_next_migration()
@BOT.event
async def on_message(message):
"""
Generic operations on user message. For example, adding to analytics to
see if users are active on the guild.
"""
if message.author.bot:
return
if message.content.startswith(f"{BOT.command_prefix*2}"):
return
if message.content.startswith(prefix):
await BOT.process_commands(message)
command = message.content.split()
command = command[0].replace(BOT.command_prefix, "")
await BOT.db_handler.metrics.update_commands(command, 1)
commands = re.findall("{%(.*?)%}", message.content)
if commands:
for command in commands:
command = command.strip()
if not command.startswith(BOT.command_prefix):
command = BOT.command_prefix + command
message.content = command
await BOT.process_commands(message)
@BOT.event
async def on_message_edit(before, after):
"""
Checks to see if the edited message starts with the bot command
prefix. If the edited message starts with the command prefix, this will
then attempt to run the command.
"""
if after.content.startswith(f"{BOT.command_prefix*2}"):
return
if after.content.startswith(prefix):
await BOT.process_commands(after)
command = after.content.split()
command = command[0].replace(BOT.command_prefix, "")
await BOT.db_handler.metrics.update_commands(command, 1)
@BOT.event
async def on_command_error(ctx, error):
if isinstance(error, commands.CommandNotFound):
handler = BOT.db_handler.tags
cmd = "".join(ctx.message.content)[1:]
await BOT.db_handler.metrics.update_commands(cmd, -1)
# Try get a normal tag
content = await handler.fetch_tag(ctx.author.id, cmd)
if content:
return await ctx.send(content)
# Try get a guild tag
content = await handler.fetch_guild_tag(ctx.guild.id, cmd)
if content:
return await ctx.send(content)
else:
await ctx.channel.send("https://http.cat/404.jpg")
else:
await ctx.send(error)
async def load_cogs(unload_first=False):
"""
Handles loading all cogs in for the bot.
"""
cogs = [cog for cog in os.listdir('cogs')
if os.path.isfile(f"cogs/{cog}")]
cogs = [cog.replace(".py", "") for cog in cogs]
for extension in cogs:
try:
print(f"Loading {extension}...")
await BOT.load_extension(f"cogs.{extension}")
print(f"Loaded {extension}")
except AttributeError as e:
print(f"Cog {extension} is malformed. Do you have a setup"
"function?")
traceback.print_tb(e.__traceback__)
except ModuleNotFoundError:
print(f"Could not find {extension}. Please make sure it "
"exists.")
except OSError as lib_error:
print("Opus is probably not installed")
print(f"{lib_error}")
except commands.errors.ExtensionAlreadyLoaded:
print(f"The cog {extension} is already loaded.\n"
"Skipping the load process for this cog.")
except SyntaxError as e:
print(f"The cog {extension} has a syntax error.")
traceback.print_tb(e.__traceback__)
except commands.errors.NoEntryPoint as e:
print(f"Cog {extension} has no setup function.")
traceback.print_tb(e.__traceback__)
return BOT
if __name__ == "__main__":
import sys
print("The bot must be ran through main.py")
print("Please run 'python main.py' instead")
sys.exit()