1
0
Fork 0

Init commit

This commit is contained in:
Ethanell 2020-04-08 17:11:23 +02:00
commit 8143d59c76
10 changed files with 404 additions and 0 deletions

138
.gitignore vendored Normal file
View file

@ -0,0 +1,138 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# Bot configuration
config.json
# JetBrains Stuff
.idea
# Bot logs
logs

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Ethanell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

2
README.md Normal file
View file

@ -0,0 +1,2 @@
# BotBDE
A discord bot for my BDE server

8
bot_bde/__init__.py Normal file
View file

@ -0,0 +1,8 @@
from bot_bde.config import config
from discord.ext import commands
bot = commands.Bot(command_prefix=config.get("prefix"))
import extensions
bot.run(config.get("token"))

20
bot_bde/config.py Normal file
View file

@ -0,0 +1,20 @@
from bot_bde.logger import logger
from os.path import isfile
from json import load
logger = logger.getChild("Config")
if not isfile("config.json"):
logger.critical("Config file not found !")
exit(1)
config = {}
with open("config.json") as conf:
logger.info("Loading configuration")
try:
config.update(load(conf))
except Exception as e:
logger.critical(f"Fail to load configuration: {e}")
exit(1)
else:
logger.info("Configuration load successful")

20
bot_bde/logger.py Normal file
View file

@ -0,0 +1,20 @@
import logging
from logging import handlers
from os import mkdir
from os.path import isdir
if not isdir("../logs"):
mkdir("../logs")
log_format = "{%(levelname)s}[%(asctime)s]: %(name)s | %(message)s"
logging.basicConfig(
format=log_format,
level=logging.INFO
)
logger = logging.getLogger("BotBDE")
handler = handlers.TimedRotatingFileHandler("../logs/current.log", when="d", interval=1)
handler.suffix = "%Y-%m-%d"
handler.style = log_format
handler.setFormatter(logging.Formatter(log_format))
logger.addHandler(handler)

1
config_exemple.json Normal file
View file

@ -0,0 +1 @@
{"prefix": "!", "token": "GOOD_BOT_TOKEN", "admin_id": "GOOD_USER_ID"}

4
extensions/__init__.py Normal file
View file

@ -0,0 +1,4 @@
from bot_bde import bot
bot.load_extension("extensions.help")
bot.load_extension("extensions.speak")

32
extensions/help.py Normal file
View file

@ -0,0 +1,32 @@
from discord.ext import commands
from bot_bde.logger import logger
extension_name = "help"
logger = logger.getChild(extension_name)
@commands.command("help")
async def help_cmd(ctx):
await ctx.send("Help !")
def setup(bot):
logger.info(f"Loading...")
try:
bot.help_command = None
bot.add_command(help_cmd)
except Exception as e:
logger.error(f"Error loading: {e}")
else:
logger.info(f"Load successful")
def teardown(bot):
logger.info(f"Unloading...")
try:
bot.remove_command("help")
except Exception as e:
logger.error(f"Error unloading: {e}")
else:
logger.info(f"Unload successful")

158
extensions/speak.py Normal file
View file

@ -0,0 +1,158 @@
from discord.ext import commands
from discord import Member, VoiceState, Embed
from bot_bde.logger import logger
extension_name = "speak"
logger = logger.getChild(extension_name)
class Speak(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.strict = False
self.voice_chan = None
self.waiting = []
self.lastSpeaker = None
@commands.group("speak", pass_context=True)
async def speak(self, ctx: commands.Context):
if ctx.invoked_subcommand is None:
if ctx.author.voice is None or ctx.author.voice.channel is None:
await ctx.send("Your not in a voice channel !")
elif self.voice_chan is None:
await ctx.send("Voice channel not set !")
elif ctx.author.voice.channel.id != self.voice_chan:
await ctx.send("Your not in the good voice channel !")
elif ctx.author.id in self.waiting:
await ctx.message.add_reaction("\u274C")
else:
self.waiting.append(ctx.author.id)
await ctx.message.add_reaction("\U0001f44d")
@speak.group("remove", pass_context=True)
async def speak_remove(self, ctx: commands.Context):
if len(ctx.message.mentions) != 0:
if self.voice_chan and ctx.guild.get_channel(self.voice_chan).permissions_for(ctx.author).mute_members:
for speaker in ctx.message.mentions:
self.waiting.remove(speaker.id)
await ctx.message.add_reaction("\U0001f44d")
else:
await ctx.message.add_reaction("\u274C")
elif ctx.author.id in self.waiting:
self.waiting.remove(ctx.author.id)
await ctx.message.add_reaction("\U0001f44d")
else:
await ctx.message.add_reaction("\u274C")
@speak.group("list", pass_context=True)
async def speak_list(self, ctx: commands.Context):
if ctx.author.voice.channel is None or not self.voice_chan:
await ctx.message.add_reaction("\u274C")
else:
embed = Embed(title="Waiting list")
for i, speaker in enumerate(self.waiting):
embed.add_field(name=f"{i+1}", value=ctx.guild.get_member(speaker).display_name, inline=True)
await ctx.send(embed=embed)
@speak.group("next", pass_context=True)
async def speak_next(self, ctx: commands.Context):
if not self.voice_chan or not ctx.guild.get_channel(self.voice_chan).permissions_for(ctx.author).mute_members:
await ctx.message.add_reaction("\u274C")
else:
if self.lastSpeaker:
self.waiting.remove(self.lastSpeaker)
if self.strict:
await ctx.guild.get_member(self.lastSpeaker).edit(mute=True)
if len(self.waiting) != 0:
user : Member = ctx.guild.get_member(self.waiting[0])
self.lastSpeaker = self.waiting[0]
await ctx.send(f"It's {user.mention} turn")
if self.strict:
await user.edit(mute=False)
else:
self.lastSpeaker = None
await ctx.send("Nobody left !")
@speak.group("help", pass_context=True)
async def speak_help(self, ctx: commands.Context):
await ctx.send("help")
@speak.group("setup", pass_context=True)
async def speak_setup(self, ctx: commands.Context, *args):
if not ctx.author.voice.channel.permissions_for(ctx.author).mute_members:
await ctx.message.add_reaction("\u274C")
else:
if len(args) != 0 and args[0] == "strict":
self.strict = True
for client in ctx.author.voice.channel.members:
if client != ctx.author and not client.bot:
await client.edit(mute=True)
self.voice_chan = ctx.author.voice.channel.id
await ctx.message.add_reaction("\U0001f44d")
@speak.group("clear", pass_context=True)
async def speak_clear(self, ctx: commands.Context):
if not self.voice_chan or not ctx.guild.get_channel(self.voice_chan).permissions_for(ctx.author).mute_members:
await ctx.message.add_reaction("\u274C")
else:
self.waiting = []
self.lastSpeaker = None
await self.speak_unmute(ctx)
self.strict = False
self.voice_chan = None
await ctx.message.add_reaction("\U0001f44d")
@speak.group("mute", pass_context=True)
async def speak_mute(self, ctx: commands.Context):
if not self.voice_chan or not ctx.guild.get_channel(self.voice_chan).permissions_for(ctx.author).mute_members or not self.voice_chan:
await ctx.message.add_reaction("\u274C")
else:
for client in ctx.author.voice.channel.members:
if client != ctx.author and not client.bot:
await client.edit(mute=True)
await ctx.message.add_reaction("\U0001f44d")
@speak.group("unmute", pass_context=True)
async def speak_unmute(self, ctx: commands.Context):
if not self.voice_chan or not ctx.guild.get_channel(self.voice_chan).permissions_for(ctx.author).mute_members or not self.voice_chan:
await ctx.message.add_reaction("\u274C")
else:
for client in ctx.author.voice.channel.members:
if client != ctx.author and not client.bot:
await client.edit(mute=False)
await ctx.message.add_reaction("\U0001f44d")
@commands.Cog.listener()
async def on_voice_state_update(self, member: Member, before: VoiceState, after: VoiceState):
if (before is None or before.channel is None or before.channel.id != self.voice_chan) and\
(after is not None and after.channel is not None and after.channel.id == self.voice_chan and self.strict):
await member.edit(mute=True)
elif (before is not None or before.channel is not None and before.channel.id == self.voice_chan) and\
(after is None or after.channel is None or after.channel.id != self.voice_chan):
await member.edit(mute=False)
@commands.Cog.listener()
async def on_command_error(self, ctx: commands.Context, error):
await ctx.send("An error occurred !")
raise error
def setup(bot):
logger.info(f"Loading...")
try:
bot.add_cog(Speak(bot))
except Exception as e:
logger.error(f"Error loading: {e}")
else:
logger.info(f"Load successful")
def teardown(bot):
logger.info(f"Unloading...")
try:
bot.remove_cog("Speak")
except Exception as e:
logger.error(f"Error unloading: {e}")
else:
logger.info(f"Unload successful")