-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbot.py
More file actions
174 lines (145 loc) · 8.54 KB
/
bot.py
File metadata and controls
174 lines (145 loc) · 8.54 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
# -*- coding: utf-8 -*-
""""
Discord bot written in python using disnake library.
Copyright (C) 2022 - Oscar Van Slijpe
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging.handlers
import os
import platform
import traceback
import tracemalloc
from typing import List
tracemalloc.start()
import disnake
from disnake import ApplicationCommandInteraction
from disnake.ext.commands import InteractionBot
class Bot(InteractionBot):
BEP_image = "https://i.imgur.com/BHgic3o.png"
ULB_image = "https://i.imgur.com/0VLBhVJ.png"
def __init__(self, logger, logFormatter):
self.logger = logger
self.logFormatter = logFormatter
self.test_mode = bool(os.getenv("TEST_GUILD"))
self.cog_not_loaded: List[str] = []
intents = disnake.Intents.default()
intents.members = True
if self.test_mode:
logging.info("Starting in test mod...")
super().__init__(intents=intents, test_guilds=[int(os.getenv("TEST_GUILD"))])
else:
logging.info("Starting in prod mod...")
super().__init__(intents=intents)
self.load_commands()
def tracebackEx(self, ex):
if type(ex) == str:
return "No valid traceback."
ex_traceback = ex.__traceback__
if ex_traceback is None:
ex_traceback = ex.__traceback__
tb_lines = [line.rstrip("\n") for line in traceback.format_exception(ex.__class__, ex, ex_traceback)]
return "".join(tb_lines)
async def on_ready(self) -> None:
"""
The code in this even is executed when the bot is ready
"""
self.log_channel = self.get_channel(int(os.getenv("LOG_CHANNEL")))
if not self.log_channel:
self.log_channel = self.owner.dm_channel
logging.info("-" * 50)
logging.info(f"| Logged in as {self.user.name}")
logging.info(f"| disnake API version: {disnake.__version__}")
logging.info(f"| Python version: {platform.python_version()}")
logging.info(f"| Running on: {platform.system()} {platform.release()} ({os.name})")
logging.info(f"| Owner : {self.owner}")
logging.info(f"| Cogs loaded : " + ", ".join([f"{cog}" for cog in self.cogs.keys()]))
if self.cog_not_loaded:
logging.info("| /!\ Cogs not loaded (see error above): " + ", ".join(self.cog_not_loaded))
logging.info(f"| Bot Ready !")
logging.info("-" * 50)
def load_commands(self) -> None:
for extension in os.listdir(f"./cogs"):
if extension.endswith(".py"):
if extension == ("Admin.py") and not os.getenv("ADMIN_GUILD_ID"):
logging.warning("Admin extension skipped because no admin guild set")
continue
try:
self.load_extension(f"cogs.{extension[:-3]}")
logging.info(f"Loaded extension '{extension[:-3]}'")
except Exception as e:
exception = f"{type(e).__name__}: {e}"
logging.warning(
f"Failed to load extension {extension[:-3]}: {exception}\n{self.tracebackEx(exception)}"
)
self.cog_not_loaded.append(extension)
async def send_error_log(self, tb: str):
n = len(tb) // 4050
#Logs need to be diveded into multiple embed due to size limitation
# TODO Check if we can use a list of embeds and one message
# TODO Make it dynamic base on the message size from the lib (check library version, maybe need to upgrade)
for i in range(n):
await self.log_channel.send(embed=disnake.Embed(description=f"```python\n{tb[4050*i:4050*(i+1)]}```"))
await self.log_channel.send(embed=disnake.Embed(description=f"```python\n{tb[4050*n:]}```"))
async def send_cmd_error_log(self, interaction: ApplicationCommandInteraction, error: Exception):
tb = self.tracebackEx(error)
logging.error(
f"{error} raised on command /{interaction.application_command.name} from {interaction.guild.name+'#'+interaction.channel.name if interaction.guild else 'DM'} by {interaction.author.name}.\n{tb}"
)
#Send error msg to the user
await interaction.send(
content=self.owner.mention,
embed=disnake.Embed(
title=":x: __**ERROR**__ :x:",
description=f"Une erreur s'est produite lors de la commande **/{interaction.application_command.name}**\n{self.owner.mention} a été prévenu et corrigera ce bug au plus vite !",
color=disnake.Colour.red(),
),
delete_after=10,
)
#Send logs to admins
await self.log_channel.send(
embed=disnake.Embed(title=f":x: __** ERROR**__ :x:", description=f"```{error}```").add_field(
name=f"Raised on command :",
value=f"**/{interaction.application_command.name}:{interaction.id}** from {interaction.guild.name+'#'+interaction.channel.name if interaction.guild else 'DM'} by {interaction.author.mention} at {interaction.created_at} with options\n```{interaction.filled_options}```"
+ (f" and target\n``'{interaction.target}``'." if interaction.target else "."),
)
)
await self.send_error_log(tb)
async def on_slash_command(self, interaction: disnake.ApplicationCommandInteraction) -> None:
logging.trace(
f"[Bot] Slash command '{interaction.application_command.name}:{interaction.id}' from '{interaction.guild.name+'#'+interaction.channel.name if interaction.guild else 'DM'}' by '{interaction.author.name}' started..."
)
async def on_user_command(self, interaction: disnake.UserCommandInteraction) -> None:
logging.trace(
f"[Bot] User command '{interaction.application_command.name}:{interaction.id}' from '{interaction.guild.name+'#'+interaction.channel.name if interaction.guild else 'DM'}' by '{interaction.author.name}' started..."
)
async def on_message_command(self, interaction: disnake.MessageCommandInteraction) -> None:
logging.trace(
f"[Bot] Message command '{interaction.application_command.name}:{interaction.id}' from '{interaction.guild.name+'#'+interaction.channel.name if interaction.guild else 'DM'}' by '{interaction.author.name}' started..."
)
async def on_slash_command_error(self, interaction: ApplicationCommandInteraction, error: Exception) -> None:
await self.send_cmd_error_log(interaction, error)
async def on_user_command_error(self, interaction: disnake.UserCommandInteraction, error: Exception) -> None:
await self.send_cmd_error_log(interaction, error)
async def on_message_command_error(self, interaction: disnake.MessageCommandInteraction, error: Exception) -> None:
await self.send_cmd_error_log(interaction, error)
async def on_slash_command_completion(self, interaction: disnake.ApplicationCommandInteraction) -> None:
logging.trace(
f"[Bot] Slash command '{interaction.application_command.name}:{interaction.id}' from '{interaction.guild.name+'#'+interaction.channel.name if interaction.guild else 'DM'}' by '{interaction.author.name}' at '{interaction.created_at}' ended normally"
)
async def on_user_command_completion(self, interaction: disnake.UserCommandInteraction) -> None:
logging.trace(
f"[Bot] User command '{interaction.application_command.name}:{interaction.id}' from '{interaction.guild.name+'#'+interaction.channel.name if interaction.guild else 'DM'}' by '{interaction.author.name}' at '{interaction.created_at}' ended normally"
)
async def on_message_command_completion(self, interaction: disnake.MessageCommandInteraction) -> None:
logging.trace(
f"[Bot] Message command '{interaction.application_command.name}:{interaction.id}' from '{interaction.guild.name+'#'+interaction.channel.name if interaction.guild else 'DM'}' by '{interaction.author.name}' at '{interaction.created_at}' ended normally"
)