Initial commit
This commit is contained in:
parent
12db31cd73
commit
7ff0153c9d
13
Pipfile
Normal file
13
Pipfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
packaging = "*"
|
||||||
|
discord-py = {extras = ["voice"],git = "https://github.com/Rapptz/discord.py",ref = "84c1eac62a775a37b03bd0971b221b0c50724630"}
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.7"
|
50
Pipfile.lock
generated
Normal file
50
Pipfile.lock
generated
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "3acaf69a4f810e9def8839c2fb3e6ed5f70b0c37439fecd98c30ac32b0809995"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.7"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"discord-py": {
|
||||||
|
"extras": [
|
||||||
|
"voice"
|
||||||
|
],
|
||||||
|
"git": "https://github.com/Rapptz/discord.py",
|
||||||
|
"ref": "84c1eac62a775a37b03bd0971b221b0c50724630"
|
||||||
|
},
|
||||||
|
"packaging": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af",
|
||||||
|
"sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==19.0"
|
||||||
|
},
|
||||||
|
"pyparsing": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a",
|
||||||
|
"sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03"
|
||||||
|
],
|
||||||
|
"version": "==2.4.0"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||||
|
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
||||||
|
],
|
||||||
|
"version": "==1.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
28
errors.py
Normal file
28
errors.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
class LBIException(Exception):
|
||||||
|
"""
|
||||||
|
Base exception class for LBI
|
||||||
|
|
||||||
|
All other exceptions are subclasses
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleException(LBIException):
|
||||||
|
"""
|
||||||
|
Base exception class for all module errors
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleNotInstalled(ModuleException):
|
||||||
|
"""
|
||||||
|
Raised when a module is not found in module directory
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IncompatibleModule(ModuleException):
|
||||||
|
"""
|
||||||
|
Raised when a module is not compatible with bot version
|
||||||
|
"""
|
||||||
|
pass
|
626
main.py
Normal file
626
main.py
Normal file
@ -0,0 +1,626 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from packaging.version import Version
|
||||||
|
|
||||||
|
from errors import IncompatibleModule
|
||||||
|
from modules.base import BaseClass
|
||||||
|
|
||||||
|
__version__ = "0.1.0"
|
||||||
|
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
name: str
|
||||||
|
|
||||||
|
def __init__(self, name: str):
|
||||||
|
"""
|
||||||
|
Init module
|
||||||
|
|
||||||
|
:param name: Module name
|
||||||
|
:type name: str
|
||||||
|
"""
|
||||||
|
self.name = name
|
||||||
|
MODULES.update({self.name: self})
|
||||||
|
|
||||||
|
@property
|
||||||
|
def exists(self) -> bool:
|
||||||
|
"""
|
||||||
|
Check if module exists
|
||||||
|
|
||||||
|
:return: True if module is present in modules folders
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
if not os.path.isdir(os.path.join("modules", self.name)):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def complete(self) -> bool:
|
||||||
|
"""
|
||||||
|
Check if module is complete
|
||||||
|
|
||||||
|
:return: True if module is compatible
|
||||||
|
:rtype: Boolean
|
||||||
|
"""
|
||||||
|
# Check if version.json exists
|
||||||
|
if not os.path.exists(os.path.join("modules", self.name, "version.json")):
|
||||||
|
return False
|
||||||
|
with open(os.path.join("modules", self.name, "version.json")) as file:
|
||||||
|
versions = json.load(file)
|
||||||
|
if "version" not in versions.keys():
|
||||||
|
return False
|
||||||
|
if "dependencies" not in versions.keys():
|
||||||
|
return False
|
||||||
|
if "bot_version" not in versions.keys():
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def version(self) -> Version:
|
||||||
|
"""
|
||||||
|
Returns module version
|
||||||
|
|
||||||
|
:return: current module version
|
||||||
|
:rtype: Version
|
||||||
|
"""
|
||||||
|
with open(os.path.join("modules", self.name, "version.json")) as file:
|
||||||
|
versions = json.load(file)
|
||||||
|
return Version(versions["version"])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bot_version(self) -> dict:
|
||||||
|
"""
|
||||||
|
returns the min and max version of the bot that is compatible with the module
|
||||||
|
|
||||||
|
:return: Min and max version for bot
|
||||||
|
:rtype: dict
|
||||||
|
:raises IncompatibleModule: If bot_version is not properly formated (there must be min and max keys)
|
||||||
|
"""
|
||||||
|
with open(os.path.join("modules", self.name, "version.json")) as file:
|
||||||
|
versions = json.load(file)
|
||||||
|
try:
|
||||||
|
return {"min": Version(versions["bot_version"]["min"]),
|
||||||
|
"max": Version(versions["bot_version"]["max"])}
|
||||||
|
except KeyError:
|
||||||
|
raise IncompatibleModule(f"Module {self.name} is not compatible with bot (version.json does not "
|
||||||
|
f"contain bot_version.max or bot_version.min item)")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dependencies(self) -> dict:
|
||||||
|
"""
|
||||||
|
return list of dependencies version
|
||||||
|
|
||||||
|
:return: list of dependencies version
|
||||||
|
:rtype: dict
|
||||||
|
:raises IncompatibleModule: If bot_version is not properly formated (there must be min and max keys for each
|
||||||
|
dependencies)
|
||||||
|
"""
|
||||||
|
with open(os.path.join("modules", self.name, "version.json")) as file:
|
||||||
|
versions = json.load(file)
|
||||||
|
try:
|
||||||
|
deps = {}
|
||||||
|
for name, dep in versions["dependencies"].items():
|
||||||
|
dep_ver = {"min": Version(dep["min"]),
|
||||||
|
"max": Version(dep["max"])}
|
||||||
|
deps.update({name: dep_ver})
|
||||||
|
return deps
|
||||||
|
except KeyError:
|
||||||
|
raise IncompatibleModule(f"Module {self.name} is not compatible with bot (version.json does not "
|
||||||
|
f"contain dependencies.modulename.max or dependencies.modulename.min item)")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def compatible(self) -> bool:
|
||||||
|
"""
|
||||||
|
Check if module is compatible with current installation
|
||||||
|
|
||||||
|
:return: True if all dependencies are okays
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
# Check bot version
|
||||||
|
bot_ver = Version(__version__)
|
||||||
|
if bot_ver < self.bot_version["min"]:
|
||||||
|
return False
|
||||||
|
if bot_ver > self.bot_version["max"]:
|
||||||
|
return False
|
||||||
|
for name, dep in self.dependencies.items():
|
||||||
|
if name not in MODULES.keys():
|
||||||
|
Module(name)
|
||||||
|
if MODULES[name].version < dep["min"]:
|
||||||
|
return False
|
||||||
|
if MODULES[name].version > dep["max"]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
MODULES: Dict[str, Module] = {}
|
||||||
|
|
||||||
|
|
||||||
|
def setup_logging(default_path='config/log_config.json', default_level=logging.INFO, env_key='LBI_LOG_CONFIG'):
|
||||||
|
"""Setup logging configuration
|
||||||
|
"""
|
||||||
|
path = default_path
|
||||||
|
value = os.getenv(env_key, None)
|
||||||
|
if value:
|
||||||
|
path = value
|
||||||
|
if os.path.exists(path):
|
||||||
|
with open(path, 'rt') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
logging.config.dictConfig(config)
|
||||||
|
else:
|
||||||
|
logging.basicConfig(level=default_level)
|
||||||
|
|
||||||
|
|
||||||
|
def modules_edit(func):
|
||||||
|
def wrapper(self, *args, **kwargs):
|
||||||
|
print(func.__name__, ":", self.reloading)
|
||||||
|
if self.reloading:
|
||||||
|
return func(self, *args, **kwargs)
|
||||||
|
else:
|
||||||
|
self.reloading = True
|
||||||
|
a = func(self, *args, **kwargs)
|
||||||
|
self.reloading = False
|
||||||
|
return a
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def event(func):
|
||||||
|
def wrapper(self, *args, **kwargs):
|
||||||
|
if self.reloading:
|
||||||
|
return lambda: None
|
||||||
|
else:
|
||||||
|
return func(self, *args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
setup_logging()
|
||||||
|
|
||||||
|
log_discord = logging.getLogger('discord')
|
||||||
|
log_LBI = logging.getLogger('LBI')
|
||||||
|
|
||||||
|
debug = log_LBI.debug
|
||||||
|
info = log_LBI.info
|
||||||
|
warning = log_LBI.warning
|
||||||
|
error = log_LBI.error
|
||||||
|
critical = log_LBI.critical
|
||||||
|
|
||||||
|
|
||||||
|
def load_modules_info():
|
||||||
|
for mod in os.listdir("modules"):
|
||||||
|
Module(mod)
|
||||||
|
|
||||||
|
|
||||||
|
class LBI(discord.Client):
|
||||||
|
base_path = "storage"
|
||||||
|
debug = log_LBI.debug
|
||||||
|
info = log_LBI.info
|
||||||
|
warning = log_LBI.warning
|
||||||
|
error = log_LBI.error
|
||||||
|
critical = log_LBI.critical
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.reloading = False
|
||||||
|
self.id = ClientById(self)
|
||||||
|
self.ready = False
|
||||||
|
# Content: {"module_name": {"module": imported module, "class": initialized class}}
|
||||||
|
self.modules = {}
|
||||||
|
self.config = {
|
||||||
|
"modules": ["modules"],
|
||||||
|
"prefix": "%",
|
||||||
|
}
|
||||||
|
self.owners = [281166473102098433, 318866596502306816]
|
||||||
|
self.load_config()
|
||||||
|
self.load_modules()
|
||||||
|
|
||||||
|
def load_config(self, config_file="config/config.json"):
|
||||||
|
if os.path.exists(config_file):
|
||||||
|
with open(config_file, 'rt') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
self.config.update(config)
|
||||||
|
info("Config successfully loaded.")
|
||||||
|
else:
|
||||||
|
with open(config_file, 'w') as f:
|
||||||
|
json.dump(self.config, f)
|
||||||
|
info("Config successfully created.")
|
||||||
|
|
||||||
|
def save_config(self, config_file="config/config.json"):
|
||||||
|
with open(config_file, "w") as f:
|
||||||
|
json.dump(self.config, f)
|
||||||
|
info("Config successfully saved.")
|
||||||
|
|
||||||
|
@modules_edit
|
||||||
|
def load_modules(self):
|
||||||
|
info("Starts to load modules...")
|
||||||
|
e = {}
|
||||||
|
for module in self.config["modules"]:
|
||||||
|
e.update({module: self.load_module(module)})
|
||||||
|
info("Finished to load all modules.")
|
||||||
|
return e
|
||||||
|
|
||||||
|
@modules_edit
|
||||||
|
def load_module(self, module):
|
||||||
|
"""
|
||||||
|
|
||||||
|
Status codes:
|
||||||
|
- 0: Module loaded
|
||||||
|
- 1: Module not in modules folder
|
||||||
|
- 2: Module incomplete
|
||||||
|
- 3: Module incompatible
|
||||||
|
|
||||||
|
:param module: Module name
|
||||||
|
:return: Status code
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Check module compatibility
|
||||||
|
load_modules_info()
|
||||||
|
if not MODULES.get(module):
|
||||||
|
return 1
|
||||||
|
if not MODULES[module].exists:
|
||||||
|
return 1
|
||||||
|
if not MODULES[module].complete:
|
||||||
|
return 2
|
||||||
|
if not MODULES[module].compatible:
|
||||||
|
return 3
|
||||||
|
deps = MODULES[module].dependencies
|
||||||
|
for dep in deps.keys():
|
||||||
|
if dep not in self.modules.keys():
|
||||||
|
self.load_module(dep)
|
||||||
|
try:
|
||||||
|
info("Start loading module {module}...".format(module=module))
|
||||||
|
imported = importlib.import_module('modules.' + module)
|
||||||
|
importlib.reload(imported)
|
||||||
|
initialized_class = imported.MainClass(self)
|
||||||
|
self.modules.update({module: {"imported": imported, "initialized_class": initialized_class}})
|
||||||
|
info("Module {module} successfully imported.".format(module=module))
|
||||||
|
initialized_class.on_load()
|
||||||
|
if module not in self.config["modules"]:
|
||||||
|
self.config["modules"].append(module)
|
||||||
|
self.save_config()
|
||||||
|
except AttributeError as e:
|
||||||
|
error("Module {module} doesn't have MainClass.".format(module=module))
|
||||||
|
return e
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@modules_edit
|
||||||
|
def unload_module(self, module):
|
||||||
|
info("Start unload module {module}...".format(module=module))
|
||||||
|
try:
|
||||||
|
if module in self.config["modules"]:
|
||||||
|
self.config["modules"].remove(module)
|
||||||
|
self.save_config()
|
||||||
|
self.unload_all()
|
||||||
|
self.load_modules()
|
||||||
|
except KeyError as e:
|
||||||
|
error("Module {module} not loaded.").format(module=module)
|
||||||
|
return e
|
||||||
|
|
||||||
|
@modules_edit
|
||||||
|
def reload(self):
|
||||||
|
del self.modules
|
||||||
|
self.load_modules()
|
||||||
|
|
||||||
|
@modules_edit
|
||||||
|
def unload_all(self):
|
||||||
|
del self.modules
|
||||||
|
self.modules = {}
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_ready(self):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_ready()
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_socket_raw_receive(self, message):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_socket_raw_receive(message)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_socket_raw_send(self, payload):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_socket_raw_send(payload)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_typing(self, channel, user, when):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_typing(channel, user, when)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_message(self, message):
|
||||||
|
print(message.content)
|
||||||
|
try:
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"]._on_message(message)
|
||||||
|
except RuntimeError:
|
||||||
|
info("Liste des modules changée pendant l'execution d'un on_message")
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_message_delete(self, message):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_message_delete(message)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_raw_message_delete(self, payload):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_raw_message_delete(payload)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_raw_bulk_message_delete(self, payload):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_raw_bulk_message_delete(payload)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_message_edit(self, before, after):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_message_edit(before, after)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_raw_message_edit(self, payload):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_raw_message_edit(payload)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_reaction_add(self, reaction, user):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_reaction_add(reaction, user)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_raw_reaction_add(self, payload):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_raw_reaction_add(payload)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_reaction_remove(self, reaction, user):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_reaction_remove(reaction, user)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_raw_reaction_remove(self, payload):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_raw_reaction_remove(payload)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_reaction_clear(self, message, reactions):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_reaction_clear(message, reactions)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_raw_reaction_clear(self, payload):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_raw_reaction_clear(payload)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_private_channel_delete(self, channel):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_private_channel_delete(channel)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_private_channel_create(self, channel):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_private_channel_create(channel)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_private_channel_update(self, before, after):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_private_channel_update(before, after)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_private_channel_pins_update(self, channel, last_pin):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_private_channel_pins_update(channel, last_pin)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_channel_delete(self, channel):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_channel_delete(channel)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_channel_create(self, channel):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_channel_create(channel)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_channel_update(self, before, after):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_channel_update(before, after)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_channel_pins_update(self, channel, last_pin):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_channel_pins_update(channel, last_pin)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_member_join(self, member):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_member_join(member)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_member_remove(self, member):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_member_remove(member)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_member_update(self, before, after):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_member_update(before, after)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_join(self, guild):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_join(guild)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_remove(self, guild):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_remove(guild)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_update(self, before, after):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_update(before, after)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_role_create(self, role):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_role_create(role)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_role_delete(self, role):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_role_delete(role)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_role_update(self, before, after):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_role_update(before, after)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_emojis_update(self, guild, before, after):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_emojis_update(guild, before, after)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_available(self, guild):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_available(guild)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_unavailable(self, guild):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_unavailable(guild)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_voice_state_update(self, member, before, after):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_voice_state_update(member, before, after)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_member_ban(self, guild, user):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_member_ban(guild, user)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_member_unban(self, guild, user):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_member_unban(guild, user)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_group_join(self, channel, user):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_group_join(channel, user)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_group_remove(self, channel, user):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_group_remove(channel, user)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_relationship_add(self, relationship):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_relationship_add(relationship)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_relationship_remove(self, relationship):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_relationship_remove(relationship)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_relationship_update(self, before, after):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_relationship_update(before, after)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_connect(self):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_connect()
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_shard_ready(self):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_shard_ready()
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_resumed(self):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_resumed()
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_error(self, event_, *args, **kwargs):
|
||||||
|
print(event_, *args, **kwargs)
|
||||||
|
print(traceback.format_exc())
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_error(event_, *args, **kwargs)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_guild_integrations_update(self, guild):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_guild_integrations_update(guild)
|
||||||
|
|
||||||
|
@event
|
||||||
|
async def on_webhooks_update(self, channel):
|
||||||
|
for module in self.modules.values():
|
||||||
|
await module["initialized_class"].on_webhooks_update(channel)
|
||||||
|
|
||||||
|
|
||||||
|
class ClientById:
|
||||||
|
client: LBI
|
||||||
|
|
||||||
|
def __init__(self, client_):
|
||||||
|
self.client = client_
|
||||||
|
|
||||||
|
async def fetch_message(self, id_, *args, **kwargs):
|
||||||
|
"""Find a message by id
|
||||||
|
|
||||||
|
:param id_: Id of message to find
|
||||||
|
:type id_: int
|
||||||
|
|
||||||
|
:raises discord.NotFound: This exception is raised when a message is not found (or not accessible by bot)
|
||||||
|
|
||||||
|
:rtype: discord.Message
|
||||||
|
:return: discord.Message instance if message is found.
|
||||||
|
"""
|
||||||
|
msg = None
|
||||||
|
for channel in self.client.get_all_channels():
|
||||||
|
try:
|
||||||
|
return await channel.fetch_message(id_, *args, **kwargs)
|
||||||
|
except discord.NotFound:
|
||||||
|
continue
|
||||||
|
if msg is None:
|
||||||
|
raise discord.NotFound(None, "Message not found")
|
||||||
|
|
||||||
|
async def edit_message(self, id_, *args, **kwargs):
|
||||||
|
"""Edit message by id_
|
||||||
|
|
||||||
|
:param id_: Id of the message to edit
|
||||||
|
:type id_: int"""
|
||||||
|
message = await self.fetch_message(id_)
|
||||||
|
return await message.edit(**kwargs)
|
||||||
|
|
||||||
|
async def remove_reaction(self, id_message, *args, **kwargs):
|
||||||
|
"""Remove reaction from message by id
|
||||||
|
|
||||||
|
:param id_message: Id of message
|
||||||
|
:type id_message: int"""
|
||||||
|
message = await self.fetch_message(id_message)
|
||||||
|
return await message.remove_reaction(*args, **kwargs)
|
||||||
|
|
||||||
|
async def send_message(self, id_, *args, **kwargs):
|
||||||
|
"""Send message by channel id
|
||||||
|
|
||||||
|
:param id_: Id of channel where to send message
|
||||||
|
:type id_: int"""
|
||||||
|
channel = self.client.get_channel(id_)
|
||||||
|
return channel.send(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
client = LBI()
|
||||||
|
client.run('NTUwMDkxOTAyMDY2ODg0NjA4.XKpsPQ.T5emitHQDrt7SxfUNgY1awzX-OY', max_messages=500000)
|
0
modules/__init__.py
Normal file
0
modules/__init__.py
Normal file
408
modules/base/__init__.py
Normal file
408
modules/base/__init__.py
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
"""Base class for module, never use directly !!!"""
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
import discord
|
||||||
|
|
||||||
|
|
||||||
|
class Storage:
|
||||||
|
def __init__(self, base_path, client):
|
||||||
|
self.client = client
|
||||||
|
self.base_path = base_path
|
||||||
|
try:
|
||||||
|
os.makedirs(base_path)
|
||||||
|
except FileExistsError:
|
||||||
|
self.client.info("Le dossier {dossier} a déjà été créé.".format(dossier=self.base_path))
|
||||||
|
|
||||||
|
def mkdir(self, directory):
|
||||||
|
try:
|
||||||
|
os.makedirs(self.path(directory))
|
||||||
|
except FileExistsError:
|
||||||
|
self.client.info("Le dossier {dossier} a déjà été créé.".format(dossier=directory))
|
||||||
|
|
||||||
|
def mkzip(self, files, name):
|
||||||
|
with zipfile.ZipFile(self.path(files), 'w', zipfile.ZIP_DEFLATED) as zip_file:
|
||||||
|
for file in files:
|
||||||
|
zip_file.write(self.path(file), compress_type=zipfile.ZIP_DEFLATED)
|
||||||
|
return name
|
||||||
|
|
||||||
|
def open(self, filename, *args, **kwargs):
|
||||||
|
return open(self.path(filename), *args, **kwargs)
|
||||||
|
|
||||||
|
def path(self, filename):
|
||||||
|
return os.path.join(self.base_path, filename)
|
||||||
|
|
||||||
|
def exists(self, filename):
|
||||||
|
return os.path.exists(self.path(filename))
|
||||||
|
|
||||||
|
|
||||||
|
class BaseClass:
|
||||||
|
"""Base class for all modules, Override it to make submodules"""
|
||||||
|
name = ""
|
||||||
|
help = {
|
||||||
|
"description": "",
|
||||||
|
"commands": {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
help_active = False
|
||||||
|
color = 0x000000
|
||||||
|
command_text = None
|
||||||
|
authorized_roles = []
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
"""Initialize module class
|
||||||
|
|
||||||
|
Initialize module class, always call it to set self.client when you override it.
|
||||||
|
|
||||||
|
:param client: client instance
|
||||||
|
:type client: NikolaTesla"""
|
||||||
|
self.client = client
|
||||||
|
if not os.path.isdir(os.path.join("storage", self.name)):
|
||||||
|
os.makedirs(os.path.join("storage", self.name))
|
||||||
|
self.storage = Storage(os.path.join(self.client.base_path, self.name), client)
|
||||||
|
|
||||||
|
async def send_help(self, channel):
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="[{nom}] - Aide".format(nom=self.name),
|
||||||
|
description=self.help["description"].format(prefix=self.client.config['prefix']),
|
||||||
|
color=self.color
|
||||||
|
)
|
||||||
|
for command, description in self.help["commands"].items():
|
||||||
|
embed.add_field(name=command.format(prefix=self.client.config['prefix'], command=self.command_text),
|
||||||
|
value=description.format(prefix=self.client.config['prefix'], command=self.command_text),
|
||||||
|
inline=False)
|
||||||
|
await channel.send(embed=embed)
|
||||||
|
|
||||||
|
async def auth(self, user, role_list):
|
||||||
|
if type(role_list) == list:
|
||||||
|
if user.id in self.client.owners:
|
||||||
|
return True
|
||||||
|
for guild in self.client.guilds:
|
||||||
|
if guild.get_member(user.id):
|
||||||
|
for role_id in role_list:
|
||||||
|
if role_id in [r.id for r in guild.get_member(user.id).roles]:
|
||||||
|
return True
|
||||||
|
elif type(role_list) == str:
|
||||||
|
module_name = role_list
|
||||||
|
if user.id in self.client.owners:
|
||||||
|
return True
|
||||||
|
authorized_roles = self.client.modules[module_name]["class"].authorized_roles
|
||||||
|
if len(authorized_roles):
|
||||||
|
for guild in self.client.guilds:
|
||||||
|
if guild.get_member(user.id):
|
||||||
|
for role_id in authorized_roles:
|
||||||
|
if role_id in [r.id for r in guild.get_member(user.id).roles]:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def parse_command(self, message):
|
||||||
|
"""Parse a command_text from received message and execute function
|
||||||
|
%git update
|
||||||
|
com_update(m..)
|
||||||
|
Parse message like `{prefix}{command_text} subcommand` and call class method `com_{subcommand}`.
|
||||||
|
|
||||||
|
:param message: message to parse
|
||||||
|
:type message: discord.Message"""
|
||||||
|
if message.content.startswith(self.client.config["prefix"] + (self.command_text if self.command_text else "")):
|
||||||
|
|
||||||
|
content = message.content.lstrip(
|
||||||
|
self.client.config["prefix"] + (self.command_text if self.command_text else ""))
|
||||||
|
sub_command, args, kwargs = self._parse_command_content(content)
|
||||||
|
sub_command = "com_" + sub_command
|
||||||
|
if sub_command in dir(self):
|
||||||
|
await self.__getattribute__(sub_command)(message, args, kwargs)
|
||||||
|
else:
|
||||||
|
await self.command(message, [sub_command[4:]] + args, kwargs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _parse_command_content(content):
|
||||||
|
"""Parse string
|
||||||
|
|
||||||
|
Parse string like `subcommand argument "argument with spaces" -o -shortwaytopassoncharacteroption --longoption
|
||||||
|
-o "option with argument"`. You can override this function to change parsing.
|
||||||
|
|
||||||
|
:param content: content to parse
|
||||||
|
:type content: str
|
||||||
|
|
||||||
|
:return: parsed arguments: [subcommand, [arg1, arg2, ...], [(option1, arg1), (option2, arg2), ...]]
|
||||||
|
:rtype: list[str, list, list]"""
|
||||||
|
if not len(content.split()):
|
||||||
|
return "", [], []
|
||||||
|
# Sub_command
|
||||||
|
sub_command = content.split()[0]
|
||||||
|
args_ = []
|
||||||
|
kwargs = []
|
||||||
|
if len(content.split()) > 1:
|
||||||
|
# Take the other part of command_text
|
||||||
|
content = content.split(" ", 1)[1].replace("\"", "\"\"")
|
||||||
|
# Splitting around quotes
|
||||||
|
quotes = [element.split("\" ") for element in content.split(" \"")]
|
||||||
|
# Split all sub chains but brute chains and flat the resulting list
|
||||||
|
args = [item.split() if item[0] != "\"" else [item, ] for sublist in quotes for item in sublist]
|
||||||
|
# Second plating
|
||||||
|
args = [item for sublist in args for item in sublist]
|
||||||
|
# args_ are arguments, kwargs are options with arguments
|
||||||
|
i = 0
|
||||||
|
while i < len(args):
|
||||||
|
if args[i].startswith("\""):
|
||||||
|
args_.append(args[i][1:-1])
|
||||||
|
elif args[i].startswith("--"):
|
||||||
|
if i + 1 >= len(args):
|
||||||
|
kwargs.append((args[i].lstrip("-"), None))
|
||||||
|
break
|
||||||
|
if args[i + 1][0] != "-":
|
||||||
|
kwargs.append((args[i].lstrip("-"), args[i + 1].strip("\"")))
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
kwargs.append((args[i].lstrip("-"), None))
|
||||||
|
elif args[i].startswith("-"):
|
||||||
|
if len(args[i]) == 2:
|
||||||
|
if i + 1 >= len(args):
|
||||||
|
break
|
||||||
|
if args[i + 1][0] != "-":
|
||||||
|
kwargs.append((args[i].lstrip("-"), args[i + 1].strip("\"")))
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
kwargs.append((args[i].lstrip("-"), None))
|
||||||
|
else:
|
||||||
|
kwargs.extend([(arg, None) for arg in args[i][1:]])
|
||||||
|
else:
|
||||||
|
args_.append(args[i])
|
||||||
|
i += 1
|
||||||
|
return sub_command, args_, kwargs
|
||||||
|
|
||||||
|
async def _on_message(self, message):
|
||||||
|
"""Override this function to deactivate command_text parsing"""
|
||||||
|
await self.parse_command(message)
|
||||||
|
await self.on_message(message)
|
||||||
|
|
||||||
|
async def command(self, message, args, kwargs):
|
||||||
|
"""Override this function to handle all messages starting with `{prefix}{command_text}`
|
||||||
|
|
||||||
|
Function which is executed for all command_text doesn't match with a `com_{subcommand}` function"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def save_object(self, object_instance, object_name):
|
||||||
|
"""Save object into pickle file"""
|
||||||
|
with self.storage.open(object_name, "wb") as f:
|
||||||
|
pickler = pickle.Pickler(f)
|
||||||
|
pickler.dump(object_instance)
|
||||||
|
|
||||||
|
def load_object(self, object_name):
|
||||||
|
"""Load object from pickle file"""
|
||||||
|
if self.save_exists(object_name):
|
||||||
|
with self.storage.open(object_name, "rb") as f:
|
||||||
|
unpickler = pickle.Unpickler(f)
|
||||||
|
return unpickler.load()
|
||||||
|
|
||||||
|
def save_exists(self, object_name):
|
||||||
|
"""Check if pickle file exists"""
|
||||||
|
return self.storage.exists(object_name)
|
||||||
|
|
||||||
|
def on_load(self):
|
||||||
|
"""This function is called when module is loaded"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_socket_raw_receive(self, message):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_socket_raw_send(self, payload):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_typing(self, channel, user, when):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_message(self, message):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_message_delete(self, message):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_raw_message_delete(self, payload):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_raw_bulk_message_delete(self, payload):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_message_edit(self, before, after):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_raw_message_edit(self, payload):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_reaction_add(self, reaction, user):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_raw_reaction_add(self, payload):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_reaction_remove(self, reaction, user):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_raw_reaction_remove(self, payload):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_reaction_clear(self, message, reactions):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_raw_reaction_clear(self, payload):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_private_channel_delete(self, channel):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_private_channel_create(self, channel):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_private_channel_update(self, before, after):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_private_channel_pins_update(self, channel, last_pin):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_channel_delete(self, channel):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_channel_create(self, channel):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_channel_update(self, before, after):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_channel_pins_update(self, channel, last_pin):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_member_join(self, member):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_member_remove(self, member):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_member_update(self, before, after):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_join(self, guild):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_remove(self, guild):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_update(self, before, after):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_role_create(self, role):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_role_delete(self, role):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_role_update(self, before, after):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_emojis_update(self, guild, before, after):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_available(self, guild):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_unavailable(self, guild):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_voice_state_update(self, member, before, after):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_member_ban(self, guild, user):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_member_unban(self, guild, user):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_group_join(self, channel, user):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_group_remove(self, channel, user):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_relationship_add(self, relationship):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_relationship_remove(self, relationship):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_relationship_update(self, before, after):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_ready(self):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_connect(self):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_shard_ready(self):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_resumed(self):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_error(self, event, *args, **kwargs):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_guild_integrations_update(self, guild):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def on_webhooks_update(self, channel):
|
||||||
|
"""Override this function to handle this event."""
|
||||||
|
pass
|
10
modules/base/version.json
Normal file
10
modules/base/version.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"version":"0.1.0",
|
||||||
|
"dependencies": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"bot_version": {
|
||||||
|
"min": "0.1.0",
|
||||||
|
"max": "0.1.0"
|
||||||
|
}
|
||||||
|
}
|
88
modules/errors/__init__.py
Normal file
88
modules/errors/__init__.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import asyncio
|
||||||
|
import random
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import discord
|
||||||
|
|
||||||
|
from modules.base import BaseClass
|
||||||
|
|
||||||
|
|
||||||
|
class MainClass(BaseClass):
|
||||||
|
name = "errors"
|
||||||
|
description = "Error handling"
|
||||||
|
interactive = True
|
||||||
|
super_users_list = [431043517217898496]
|
||||||
|
color = 0xdb1348
|
||||||
|
help = {
|
||||||
|
"description": "Montre toutes les erreurs du bot dans discord.",
|
||||||
|
"commands": {
|
||||||
|
"`{prefix}{command}`": "Renvoie une erreur de test.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
command_text = "unicorn"
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
super().__init__(client)
|
||||||
|
self.errorsDeque = None
|
||||||
|
self.development_chan_id = []
|
||||||
|
self.memes = [
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
self.icon = ""
|
||||||
|
|
||||||
|
async def on_ready(self):
|
||||||
|
if self.save_exists('errorsDeque'):
|
||||||
|
self.errorsDeque = self.load_object('errorsDeque')
|
||||||
|
else:
|
||||||
|
self.errorsDeque = collections.deque()
|
||||||
|
for i in range(len(self.errorsDeque)):
|
||||||
|
try:
|
||||||
|
messagelst = self.errorsDeque.popleft()
|
||||||
|
channel = self.client.get_channel(messagelst[0])
|
||||||
|
delete_message = await channel.fetch_message(messagelst[1])
|
||||||
|
await delete_message.delete()
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
self.save_object(self.errorsDeque, 'errorsDeque')
|
||||||
|
|
||||||
|
async def command(self, message, args, kwargs):
|
||||||
|
raise Exception("Si cette erreur apparait, alors tout est normal")
|
||||||
|
|
||||||
|
async def on_error(self, event, *args, **kwargs):
|
||||||
|
embed = discord.Embed(title="Aïe :/", description="```PYTHON\n{0}```".format(traceback.format_exc()),
|
||||||
|
color=self.color).set_image(url=random.choice(self.memes))
|
||||||
|
message_list = None
|
||||||
|
try:
|
||||||
|
message = await args[0].channel.send(
|
||||||
|
embed=embed.set_footer(text="Ce message va s'autodétruire dans une minute.", icon_url=self.icon))
|
||||||
|
message_list = [message.channel.id, message.id]
|
||||||
|
self.errorsDeque.append(message_list)
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
message = args[1].channel.send(
|
||||||
|
embed=embed.set_footer(text="Ce message va s'autodétruire dans une minute.", icon_url=self.icon))
|
||||||
|
message_list = [message.channel.id, message.id]
|
||||||
|
self.errorsDeque.append(message_list)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
for chanid in self.development_chan_id:
|
||||||
|
try:
|
||||||
|
await self.client.get_channel(chanid).send(
|
||||||
|
embed=embed.set_footer(text="Ce message ne s'autodétruira pas.", icon_url=self.icon))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.save_object(self.errorsDeque, 'errorsDeque')
|
||||||
|
await asyncio.sleep(60)
|
||||||
|
try:
|
||||||
|
channel = self.client.get_channel(message_list[0])
|
||||||
|
delete_message = await channel.fetch_message(message_list[1])
|
||||||
|
await delete_message.delete()
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
self.errorsDeque.remove(message_list)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
self.save_object(self.errorsDeque, 'errorsDeque')
|
13
modules/errors/version.json
Normal file
13
modules/errors/version.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": "0.1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"base": {
|
||||||
|
"min": "0.1.0",
|
||||||
|
"max": "0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bot_version": {
|
||||||
|
"min": "0.1.0",
|
||||||
|
"max": "0.1.0"
|
||||||
|
}
|
||||||
|
}
|
115
modules/modules/__init__.py
Normal file
115
modules/modules/__init__.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import discord
|
||||||
|
|
||||||
|
from modules.base import BaseClass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MainClass(BaseClass):
|
||||||
|
name = "modules"
|
||||||
|
|
||||||
|
command_text = "modules"
|
||||||
|
color = 0x000000
|
||||||
|
help = {
|
||||||
|
"description": "Manage bot modules.",
|
||||||
|
"commands": {
|
||||||
|
"`{prefix}{command} list`": "List of available modules.",
|
||||||
|
"`{prefix}{command} enable <module>`": "Enable module `<module>`.",
|
||||||
|
"`{prefix}{command} disable <module>`": "Disable module `<module>`.",
|
||||||
|
"`{prefix}{command} reload <module>`":"Reload module `<module>`",
|
||||||
|
"`{prefix}{command} web_list`": "List all available modules from repository",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, client):
|
||||||
|
super().__init__(client)
|
||||||
|
self.storage.mkdir("modules")
|
||||||
|
|
||||||
|
def get_all_modules(self):
|
||||||
|
all_items = os.listdir("modules")
|
||||||
|
modules = []
|
||||||
|
for item in all_items:
|
||||||
|
if item not in ["__init__.py", "base", "__pycache__", "dummy"]:
|
||||||
|
if os.path.isfile(os.path.join("modules", item)):
|
||||||
|
modules.append(item[:-3])
|
||||||
|
else:
|
||||||
|
modules.append(item)
|
||||||
|
return set(modules)
|
||||||
|
|
||||||
|
async def com_enable(self, message, args, kwargs):
|
||||||
|
args = args[1:]
|
||||||
|
if len(args) == 0:
|
||||||
|
await message.channel.send("You must specify at least one module.")
|
||||||
|
return
|
||||||
|
if len(args) == 1 and args[0] == "*":
|
||||||
|
for module in self.get_all_modules():
|
||||||
|
e = self.client.load_module(module)
|
||||||
|
if e:
|
||||||
|
await message.channel.send("An error occurred during the loading of the module {module}."
|
||||||
|
.format(module=module))
|
||||||
|
await self.com_list(message, args, kwargs)
|
||||||
|
return
|
||||||
|
for arg in args:
|
||||||
|
e = self.client.load_module(arg)
|
||||||
|
if e:
|
||||||
|
await message.channel.send("An error occurred during the loading of the module {module}."
|
||||||
|
.format(module=arg))
|
||||||
|
await self.com_list(message, args, kwargs)
|
||||||
|
|
||||||
|
async def com_reload(self, message, args, kwargs):
|
||||||
|
args = args[1:]
|
||||||
|
if len(args) == 0:
|
||||||
|
await message.channel.send("You must specify at least one module.")
|
||||||
|
return
|
||||||
|
if len(args) == 1 and args[0] == "*":
|
||||||
|
for module in self.get_all_modules():
|
||||||
|
e = self.client.unload_module(module)
|
||||||
|
if e:
|
||||||
|
await message.channel.send("An error occurred during the loading of the module {module}."
|
||||||
|
.format(module=module))
|
||||||
|
await self.com_list(message, args, kwargs)
|
||||||
|
return
|
||||||
|
for arg in args:
|
||||||
|
print(arg)
|
||||||
|
e = self.client.unload_module(arg)
|
||||||
|
if e:
|
||||||
|
await message.channel.send("An error occurred during the loading of the module {module}."
|
||||||
|
.format(module=arg))
|
||||||
|
await self.com_list(message, [], [])
|
||||||
|
|
||||||
|
async def com_disable(self, message, args, kwargs):
|
||||||
|
args = args[1:]
|
||||||
|
if len(args) == 0:
|
||||||
|
await message.channel.send("You must specify at least one module.")
|
||||||
|
return
|
||||||
|
if len(args) == 1 and args[0] == "*":
|
||||||
|
for module in self.get_all_modules():
|
||||||
|
e = self.client.unload_module(module)
|
||||||
|
if e:
|
||||||
|
await message.channel.send("An error occurred during the loading of the module {module}."
|
||||||
|
.format(module=module))
|
||||||
|
await self.com_list(message, args, kwargs)
|
||||||
|
return
|
||||||
|
for arg in args:
|
||||||
|
print(arg)
|
||||||
|
e = self.client.unload_module(arg)
|
||||||
|
if e:
|
||||||
|
await message.channel.send("An error occurred during the loading of the module {module}."
|
||||||
|
.format(module=arg))
|
||||||
|
await self.com_list(message, [], [])
|
||||||
|
|
||||||
|
async def com_list(self, message, args, kwargs):
|
||||||
|
list_files = self.get_all_modules()
|
||||||
|
activated = set(self.client.config["modules"])
|
||||||
|
activated_string = "\n+ " + "\n+ ".join(activated)
|
||||||
|
deactivated_string = "- " + "\n- ".join(list_files.difference(activated))
|
||||||
|
embed = discord.Embed(title="[Modules] - Liste des modules",
|
||||||
|
description="```diff\n{activated}\n{deactivated}```".format(
|
||||||
|
activated=activated_string,
|
||||||
|
deactivated=deactivated_string)
|
||||||
|
)
|
||||||
|
await message.channel.send(embed=embed)
|
||||||
|
|
||||||
|
async def com_web_list(self, message, args, kwargs):
|
||||||
|
pass
|
13
modules/modules/version.json
Normal file
13
modules/modules/version.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": "0.1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"base": {
|
||||||
|
"min": "0.1.0",
|
||||||
|
"max": "0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bot_version": {
|
||||||
|
"min": "0.1.0",
|
||||||
|
"max": "0.1.0"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user