Refactor bot and use cogs

This commit is contained in:
DasMoorhuhn 2024-02-17 22:35:14 +01:00
parent 423fba750f
commit c9848adde6
12 changed files with 249 additions and 174 deletions

View File

@ -1,6 +1,6 @@
FROM python:3.12-alpine
WORKDIR /app
WORKDIR /src
COPY requirements.txt requirements.txt
RUN /usr/local/bin/python -m pip install --upgrade pip
@ -12,4 +12,4 @@ COPY ./src/ .
RUN mkdir -p ./data/log
RUN mkdir -p ./data/config
CMD [ "python3.12", "main.py" ]
CMD [ "python3.12", "bot.py" ]

14
create_invite_link.py Normal file
View File

@ -0,0 +1,14 @@
import sys
permissions = "274877966400"
scope = "bot+applications.commands"
# client_id = 961747147135524874
try: client_id = sys.argv[1]
except:
print("Put the client id from the discord bot behind this command")
exit(1)
url = f"https://discord.com/api/oauth2/authorize?client_id={client_id}&permissions={permissions}&scope={scope}"
print(url)

View File

@ -6,6 +6,6 @@ services:
restart: unless-stopped
build: .
volumes:
- ./data/log:/app/data/log
- ./data/config:/app/data/config
- ./secret.json:/app/secret.json
- ./data/log:/src/data/log
- ./data/config:/src/data/config
- ./secret.json:/src/secret.json

0
src/__init__.py Normal file
View File

View File

@ -1,9 +1,27 @@
import requests
import json
import datetime
import time
from models.xkcdComic import Comic
class DateTimeHelper:
@staticmethod
def get_time_now():
date_now = datetime.datetime.now()
return str(date_now).split(" ")[0]
@staticmethod
def get_unix_time():
return time.time()
@staticmethod
def get_date():
date_now = datetime.datetime.now()
return str(date_now).split(" ")
class ProgrammerExcuses:
def __init__(self) -> None:
self.url = "http://programmingexcuses.com"

54
src/bot.py Normal file
View File

@ -0,0 +1,54 @@
import logging
import asyncio
import os
import secret_handler
import discord
from discord import app_commands
from discord import Interaction
from discord.ext import commands
import addons
from client import Client
bot_info = {'version': '1.1.0', 'date': '20.02.2024'}
logger = logging.getLogger('discord')
logger.setLevel(logging.DEBUG)
logging.getLogger('discord.http').setLevel(logging.INFO)
handler = logging.FileHandler(filename='data/log/discord.log', encoding='utf-8', mode='a')
# dt_fmt = '%Y-%m-%d %H:%M:%S'
# formatter = logging.Formatter('[{asctime}] [{levelname:<8}] {name}: {message}', dt_fmt, style='{')
formatter = logging.Formatter('%(asctime)s|%(levelname)s|%(name)s|:%(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
bot = Client(intents=discord.Intents.all(), command_prefix="!", log=logger, bot_info=bot_info)
async def load_cogs():
for filename in os.listdir("./cogs"):
if filename.endswith("py") and filename != "__init__.py":
await bot.load_extension(f"cogs.{filename[:-3]}")
@bot.event
async def on_ready():
logger.info(f"Logged in as: {bot.user.name} with ID {bot.user.id}")
await load_cogs()
await asyncio.sleep(1)
synced = await bot.tree.sync()
logger.info(f"Synced {len(synced)} command(s)")
@bot.event
async def on_app_command_error(interaction: Interaction, error):
if isinstance(error, app_commands.MissingPermissions):
await interaction.response.send_message(content="Du hast keine Adminrechte", ephemeral=True)
else:
raise error
bot.run(secret_handler.get_bot_token())

22
src/client.py Normal file
View File

@ -0,0 +1,22 @@
from discord import Intents
from discord.ext import commands
import addons
class Client(commands.Bot):
"""Custom bot class"""
def __init__(self, command_prefix, *, intents: Intents, log, bot_info):
super().__init__(command_prefix, intents=intents)
self.log = log
self.addons = addons
self.start_time:float = self.addons.DateTimeHelper.get_unix_time()
self.version:str = bot_info['version']
self.date:str = bot_info['date']
async def startup(self):
await self.wait_until_ready()
def get_uptime(self):
"""Returns the uptime in seconds"""
time_now = self.addons.DateTimeHelper.get_unix_time()
return int(round(time_now - self.start_time, 0))

0
src/cogs/__init__.py Normal file
View File

View File

@ -0,0 +1,31 @@
import discord
from discord import app_commands
from discord import Interaction
from discord.ext import commands
from discord.ext.commands import Cog
import sys
sys.path.append('..')
from src.client import Client as Bot
class ProgrammingExcuses(Cog):
def __init__(self, bot:Bot):
self.bot = bot
self.log = bot.log
self.programmer_excuses = bot.addons.ProgrammerExcuses()
@commands.Cog.listener()
async def on_ready(self):
self.log.info("Done: excuse")
@app_commands.command(name="excuse", description="Excuse")
async def excuse(self, interaction: Interaction):
self.log.info("Command: excuse")
await interaction.response.send_message(self.programmer_excuses.get_excuse())
async def setup(bot:Bot):
await bot.add_cog(ProgrammingExcuses(bot))
bot.log.info(f"Loaded excuses")

59
src/cogs/help_commands.py Normal file
View File

@ -0,0 +1,59 @@
import discord
from discord import app_commands
from discord import Interaction
from discord import Embed
from discord import Color
from discord.ext import commands
from discord.ext.commands import Cog
import sys
sys.path.append('..')
from src.client import Client as Bot
class HelpCommands(Cog):
def __init__(self, bot:Bot):
self.bot = bot
self.log = bot.log
self.programmer_excuses = bot.addons.ProgrammerExcuses()
self.date_time_helper = bot.addons.DateTimeHelper
@commands.Cog.listener()
async def on_ready(self):
self.log.info("Done: help, info")
@app_commands.command(name="help", description="List of all Commands")
async def help(self, interaction: Interaction):
self.log.info("Command: help")
command_list_string = ""
command_list_string += "`/info` : Get infos about the server and the Bot\n"
command_list_string += "`/help` : Get this view\n"
command_list_string += "`/get-random-comic`: Get a randowm XCCD comic\n"
command_list_string += "`/get-latest-comic`: Get latest comic from XKCD\n"
command_list_string += "`/excuse` : Get a random excuse from programmingexcuses"
embed = Embed(title=f"Help", description="List of commands", color=Color.blue())
embed.add_field(name="Commands", value=command_list_string, inline=True)
await interaction.response.send_message(embed=embed)
@app_commands.command(name="info", description="Get info about this bot")
async def info(self, interaction: Interaction):
self.log.info("Command: info")
bot_string = ""
bot_string += f"Uptime : {self.bot.get_uptime()}s\n"
bot_string += f"Version : {self.bot.version} from {self.bot.date}\n"
bot_string += f"Developer : dasmoorhuhn\n"
bot_string += f"Sourcecode: https://gitlab.com/DasMoorhuhn/tux-discord-bot"
embed = Embed(title=f"Info", description="about this Bot",
color=Color.blue())
embed.add_field(name="Bot", value=bot_string, inline=False)
await interaction.response.send_message(embed=embed)
async def setup(bot:Bot):
await bot.add_cog(HelpCommands(bot))
bot.log.info(f"Loaded help")

46
src/cogs/xkcd_commands.py Normal file
View File

@ -0,0 +1,46 @@
import discord
from discord import app_commands
from discord import Interaction
from discord import Embed
from discord import Color
from discord.ext import commands
from discord.ext.commands import Cog
import sys
sys.path.append('..')
from src.client import Client as Bot
class XkcdCommands(Cog):
def __init__(self, bot: Bot):
self.bot = bot
self.log = bot.log
self.xkcd = bot.addons.XKCD()
@commands.Cog.listener()
async def on_ready(self):
self.log.info("Done: get-latest-comic, get-random-comic")
@app_commands.command(name="get-latest-comic", description="test slash command")
async def get_latest_comic(self, interaction: Interaction):
self.log.info("Command: get-latest-comic")
comic = self.xkcd.get_last_comic()
embed = Embed(title=comic.title, color=Color.blue(), url=f"{self.xkcd.url}/{comic.num}")
embed.set_image(url=comic.img)
await interaction.response.send_message(embed=embed)
@app_commands.command(name='get-random-comic', description='Get a random comic from XKCD')
async def get_random_comic(self, interaction: Interaction):
self.log.info("Command: get-random-comic")
comic = self.xkcd.get_random_comic()
embed = Embed(title=comic.title, color=Color.blue(), url=f"{self.xkcd.url}/{comic.num}")
embed.set_image(url=comic.img)
await interaction.response.send_message(embed=embed)
async def setup(bot):
await bot.add_cog(XkcdCommands(bot))
bot.log.info(f"Loaded XKCD")

View File

@ -1,169 +0,0 @@
import time as t
import asyncio
import logging
import datetime
import secret_handler
from addons import ProgrammerExcuses
from addons import XKCD
from models.xkcdComic import Comic
import discord
from discord import Status
from discord import app_commands
from discord import Interaction
from discord import Embed
from discord import Guild
from discord import Color
from discord.activity import Game
botVersion = "1.0.24"
botDate = "16.02.2024"
secret = secret_handler.get_bot_token()
# Init Logger
logger = logging.getLogger('discord')
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(filename='data/log/discord.log', encoding='utf-8', mode='a')
handler.setFormatter(logging.Formatter('%(asctime)s|%(levelname)s|%(name)s|:%(message)s'))
logger.addHandler(handler)
# Init Addons
programmer_excuses = ProgrammerExcuses()
xkcd = XKCD()
class Client(discord.Client):
async def startup(self):
await self.wait_until_ready()
def get_date_time():
date_now = datetime.datetime.now()
date_now = str(date_now).split(" ")
unix = t.time()
time = date_now[1]
time = time.split(".")
time = time[0]
date_now = date_now[0]
return date_now, time, unix
start_time = get_date_time()[2]
bot = Client(intents=discord.Intents.all())
tree = app_commands.CommandTree(client=bot)
async def change_presence(interval_in_seconds=120):
while True:
await bot.change_presence(activity=Game(name="with penguins"), status=Status.online)
await asyncio.sleep(interval_in_seconds)
count_guilds = 0
async for guild in bot.fetch_guilds():
count_guilds += 1
await bot.change_presence(activity=Game(name=f"on {count_guilds} Servers"), status=Status.online)
await asyncio.sleep(interval_in_seconds)
@bot.event
async def on_ready():
start_time = get_date_time()[2]
logger.info(f"Logged in as: {bot.user.name} with ID {bot.user.id}")
await bot.loop.create_task(change_presence())
await bot.change_presence(activity=Game(name="with penguins"), status=Status.online)
await tree.sync()
@bot.event
async def on_guild_join(guild: Guild):
logger.info("Added to Guild")
await guild.system_channel.send("Hii^^")
@tree.command(name='excuse', description='Get a random excuse from programmingexcuses')
async def slash(interaction: Interaction):
logger.info("Command: excuse")
await interaction.response.send_message(programmer_excuses.get_excuse())
@tree.command(name='get-latest-comic', description='Get latest comic from XKCD')
async def slash(interaction: Interaction):
logger.info("Command: get-latest-comic")
comic = xkcd.get_last_comic()
embed = discord.Embed(title=comic.title, color=Color.blue(), url=f"{xkcd.url}/{comic.num}")
embed.set_image(url=comic.img)
await interaction.response.send_message(embed=embed)
@tree.command(name='get-random-comic', description='Get a random comic from XKCD')
async def slash(interaction: Interaction):
logger.info("Command: get-random-comic")
comic = xkcd.get_random_comic()
embed = discord.Embed(title=comic.title, color=Color.blue(), url=f"{xkcd.url}/{comic.num}")
embed.set_image(url=comic.img)
await interaction.response.send_message(embed=embed)
# @tree.command(name='programmer-humor', description='Get a random Post from r/ProgrammerHumor')
# async def slash(interaction: Interaction):
# post = redditProgrammerHumor.getRandomPost()
# await interaction.response.send_message("hi")
@tree.command(name="info", description="get info about this bot")
async def slash(interaction: Interaction):
logger.info("Command: info")
time_now = get_date_time()[2]
uptime = time_now - start_time
bot_string = ""
bot_string += f"Uptime : {int(round(uptime, 0))}s\n"
bot_string += f"Version : {botVersion} from {botDate}\n"
bot_string += f"Developer : dasmoorhuhn\n"
bot_string += f"Sourcecode: https://gitlab.com/DasMoorhuhn/tux-discord-bot"
embed = discord.Embed(title=f"Info", description="about this Bot", timestamp=datetime.datetime.utcnow(),
color=Color.blue())
# embed.set_thumbnail(url=interaction.guild.icon)
embed.add_field(name="Bot", value=bot_string, inline=False)
await interaction.response.send_message(embed=embed)
@tree.command(name="help", description="List of all Commands")
async def slash(interaction: Interaction):
logger.info("Command: help")
command_list_string = ""
command_list_string += "`/info` : Get infos about the server and the Bot\n"
command_list_string += "`/help` : Get this view\n"
command_list_string += "`/get-random-comic`: Get a randowm XCCD comic\n"
command_list_string += "`/get-latest-comic`: Get latest comic from XKCD\n"
command_list_string += "`/excuse` : Get a random excuse from programmingexcuses"
embed = discord.Embed(title=f"Help", description="List of commands", color=Color.blue())
# embed.set_thumbnail(url=interaction.guild.icon)
embed.add_field(name="Commands", value=command_list_string, inline=True)
await interaction.response.send_message(embed=embed)
@tree.error
async def on_app_command_error(interaction: Interaction, error):
if isinstance(error, app_commands.MissingPermissions):
await interaction.response.send_message(content="Du hast keine Adminrechte", ephemeral=True)
else:
raise error
# Prevent Gateway Heartbeat Block
try:
bot.run(token=secret_handler.get_bot_token())
except Exception as err:
raise err
finally:
logger.info("Stopped")