Merge branch 'refactor' into 'main'

refactoring

See merge request DasMoorhuhn/tux-discord-bot!3
This commit is contained in:
DasMoorhuhn 2024-02-16 00:40:30 +00:00
commit f9c9e66b94
8 changed files with 159 additions and 237 deletions

5
.gitignore vendored
View File

@ -1,2 +1,5 @@
secret.txt secret*
data data
.venv
.idea

View File

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

View File

@ -2,10 +2,10 @@ version: '3'
services: services:
app: app:
container_name: TuxDiscordBot container_name: TuxDiscordBot
image: 'dasmoorhuhn/tux-discord-bot:beta' image: 'docker.lan:5000/tux-discord-bot'
restart: unless-stopped restart: unless-stopped
build: . build: .
volumes: volumes:
- ./data/log:/app/data/log - ./data/log:/app/data/log
- ./data/config:/app/data/config - ./data/config:/app/data/config
- ./secret.txt:/app/secret.txt - ./secret.json:/app/secret.json

View File

@ -5,66 +5,43 @@ from models.xkcdComic import Comic
class ProgrammerExcuses: class ProgrammerExcuses:
def __init__(self) -> None: def __init__(self) -> None:
self.__url = "http://programmingexcuses.com" self.url = "http://programmingexcuses.com"
def getExcuse(self): def get_excuse(self):
page = requests.get(url=self.__url) page = requests.get(url=self.url)
content = page.content.decode().split("\n") content = page.content.decode().split("\n")
for html in content: for html in content:
if 'href="/"' in html: if 'href="/"' in html:
start_index = html.find('3;">') start_index = html.find('3;">')
end_index = html.find("</a></center>") end_index = html.find("</a></center>")
return html[start_index+4:end_index] return html[start_index + 4:end_index]
class XKCD: class XKCD:
def __init__(self) -> None: def __init__(self) -> None:
self.url = "https://xkcd.com" self.url = "https://xkcd.com"
self.__api = "info.0.json" self.api = "info.0.json"
def getRandomComic(self): def get_random_comic(self):
response = requests.get(url=f"https://c.xkcd.com/random/comic") response = requests.get(url=f"https://c.xkcd.com/random/comic")
for line in response.text.split("\n"): for line in response.text.split("\n"):
if '<meta property="og:url"' in line: if '<meta property="og:url"' in line:
line = line.split('"') line = line.split('"')
for cell in line: for cell in line:
if "https" in cell: if "https" in cell:
return self.getSpecificComic(url=cell) return self.get_specific_comic(url=cell)
def getLastComic(self): def get_last_comic(self):
response = requests.api.get(f"{self.url}/{self.__api}") response = requests.api.get(f"{self.url}/{self.api}")
return Comic(json.loads(response.text)) return Comic(json.loads(response.text))
def getSpecificComic(self, num=None, url=None): def get_specific_comic(self, num=None, url=None):
if num != None: if num is not None:
response = requests.api.get(url=f"{self.url}/{num}/{self.__api}") response = requests.api.get(url=f"{self.url}/{num}/{self.api}")
return Comic(json.loads(response.text)) return Comic(json.loads(response.text))
if url != None: if url is not None:
response = requests.api.get(url=f"{url}/{self.__api}") response = requests.api.get(url=f"{url}/{self.api}")
return Comic(json.loads(response.text)) return Comic(json.loads(response.text))
class Reddit:
def __init__(self) -> None:
self.url = "https://www.reddit.com"
self.random = "random.json"
def _getRandomPost(self, community):
response = requests.get(f"{self.url}/{community}/{self.random}")
return json.loads(response.text)
class RedditProgrammerHumor(Reddit):
def __init__(self) -> None:
super().__init__()
self.community = "r/ProgrammerHumor"
def getRandomPost(self):
post = self._getRandomPost(self.community)
with open(file="data/log/test.json", mode="w") as file:
file.write(json.dumps(obj=post, indent=2))
file.close()
return post

View File

@ -2,10 +2,9 @@ import time as t
import asyncio import asyncio
import logging import logging
import datetime import datetime
import secretHandler import secret_handler
from addons import ProgrammerExcuses from addons import ProgrammerExcuses
from addons import XKCD from addons import XKCD
#from addons import RedditProgrammerHumor
from models.xkcdComic import Comic from models.xkcdComic import Comic
@ -18,14 +17,10 @@ from discord import Guild
from discord import Color from discord import Color
from discord.activity import Game from discord.activity import Game
botVersion = "1.0.23" botVersion = "1.0.24"
botDate = "02.03.2023" botDate = "16.02.2024"
secret = secretHandler.secret() secret = secret_handler.get_bot_token()
token = secret.loadSecret("secret.txt")
if token[0] != 0:
exit(f"Cannot load token. Error Code {token[0]}")
botToken = token[1]
# Init Logger # Init Logger
logger = logging.getLogger('discord') logger = logging.getLogger('discord')
@ -34,132 +29,142 @@ handler = logging.FileHandler(filename='data/log/discord.log', encoding='utf-8',
handler.setFormatter(logging.Formatter('%(asctime)s|%(levelname)s|%(name)s|:%(message)s')) handler.setFormatter(logging.Formatter('%(asctime)s|%(levelname)s|%(name)s|:%(message)s'))
logger.addHandler(handler) logger.addHandler(handler)
#Init Addons # Init Addons
programmerExcuses = ProgrammerExcuses() programmer_excuses = ProgrammerExcuses()
#redditProgrammerHumor = RedditProgrammerHumor() # redditProgrammerHumor = RedditProgrammerHumor()
xkcd = XKCD() xkcd = XKCD()
class client(discord.Client):
async def startup(self):
await self.wait_until_ready()
def getDateTime(): class Client(discord.Client):
dateNow = datetime.datetime.now() async def startup(self):
dateNow = str(dateNow).split(" ") await self.wait_until_ready()
unix = t.time()
time = dateNow[1]
time = time.split(".")
time = time[0]
dateNow = dateNow[0]
return dateNow, time, unix
startTime = getDateTime()[2]
bot = client(intents=discord.Intents.all()) 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) tree = app_commands.CommandTree(client=bot)
async def chnagePresence(intervalInSeconds=60):
while True:
await bot.change_presence(activity=Game(name="with penguins"), status=Status.online)
await asyncio.sleep(intervalInSeconds)
countGuilds = 0 async def change_presence(interval_in_seconds=120):
async for guild in bot.fetch_guilds(): while True:
countGuilds += 1 await bot.change_presence(activity=Game(name="with penguins"), status=Status.online)
await asyncio.sleep(interval_in_seconds)
await bot.change_presence(activity=Game(name=f"on {countGuilds} Servers"), status=Status.online)
await asyncio.sleep(intervalInSeconds) 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 @bot.event
async def on_ready(): async def on_ready():
startTime = getDateTime()[2] start_time = get_date_time()[2]
bot.loop.create_task(chnagePresence()) await bot.loop.create_task(change_presence())
logger.info(f"Logged in as: {bot.user.name} with ID {bot.user.id}") logger.info(f"Logged in as: {bot.user.name} with ID {bot.user.id}")
await bot.change_presence(activity=Game(name="with penguins"), status=Status.online) await bot.change_presence(activity=Game(name="with penguins"), status=Status.online)
await tree.sync() await tree.sync()
@bot.event @bot.event
async def on_guild_join(guild: Guild): async def on_guild_join(guild: Guild):
logger.info("Added to Guild") logger.info("Added to Guild")
await guild.system_channel.send("Hii^^") await guild.system_channel.send("Hii^^")
@tree.command(name='excuse', description='Get a random excuse from programmingexcuses') @tree.command(name='excuse', description='Get a random excuse from programmingexcuses')
async def slash(interaction: Interaction): async def slash(interaction: Interaction):
logger.info("Command: excuse") logger.info("Command: excuse")
await interaction.response.send_message(programmerExcuses.getExcuse()) await interaction.response.send_message(programmer_excuses.get_excuse())
@tree.command(name='get-latest-comic', description='Get latest comic from XKCD') @tree.command(name='get-latest-comic', description='Get latest comic from XKCD')
async def slash(interaction: Interaction): async def slash(interaction: Interaction):
logger.info("Command: get-latest-comic") logger.info("Command: get-latest-comic")
comic = xkcd.getLastComic() 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)
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') @tree.command(name='get-random-comic', description='Get a random comic from XKCD')
async def slash(interaction: Interaction): async def slash(interaction: Interaction):
logger.info("Command: get-random-comic") logger.info("Command: get-random-comic")
comic = xkcd.getRandomComic() 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') embed = discord.Embed(title=comic.title, color=Color.blue(), url=f"{xkcd.url}/{comic.num}")
#async def slash(interaction: Interaction): embed.set_image(url=comic.img)
# post = redditProgrammerHumor.getRandomPost() await interaction.response.send_message(embed=embed)
# await interaction.response.send_message("hi")
# @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") @tree.command(name="info", description="get info about this bot")
async def slash(interaction: Interaction): async def slash(interaction: Interaction):
logger.info("Command: info") logger.info("Command: info")
timeNow = getDateTime()[2] time_now = get_date_time()[2]
uptime = timeNow - startTime uptime = time_now - start_time
botString = "" bot_string = ""
botString += f"Uptime : {int(round(uptime, 0))}s\n" bot_string += f"Uptime : {int(round(uptime, 0))}s\n"
botString += f"Version : {botVersion} from {botDate}\n" bot_string += f"Version : {botVersion} from {botDate}\n"
botString += f"Developer : DasMoorhuhn.py#2604\n" bot_string += f"Developer : dasmoorhuhn\n"
botString += f"Sourcecode: https://gitlab.com/HendrikHeine/tux-discord-bot" 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)
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=botString, inline=False)
await interaction.response.send_message(embed=embed)
@tree.command(name="help", description="List of all Commands") @tree.command(name="help", description="List of all Commands")
async def slash(interaction: Interaction): async def slash(interaction: Interaction):
logger.info("Command: help") logger.info("Command: help")
commandListString = "" command_list_string = ""
commandListString += "`/info` : Get infos about the server and the Bot\n" command_list_string += "`/info` : Get infos about the server and the Bot\n"
commandListString += "`/help` : Get this view\n" command_list_string += "`/help` : Get this view\n"
commandListString += "`/get-random-comic`: Get a randowm XCCD comic\n" command_list_string += "`/get-random-comic`: Get a randowm XCCD comic\n"
commandListString += "`/get-latest-comic`: Get latest comic from XKCD\n" command_list_string += "`/get-latest-comic`: Get latest comic from XKCD\n"
commandListString += "`/excuse` : Get a random excuse from programmingexcuses" command_list_string += "`/excuse` : Get a random excuse from programmingexcuses"
embed = discord.Embed(title=f"Help", description="List of commands", color=Color.blue()) embed = discord.Embed(title=f"Help", description="List of commands", color=Color.blue())
#embed.set_thumbnail(url=interaction.guild.icon) # embed.set_thumbnail(url=interaction.guild.icon)
embed.add_field(name="Commands", value=commandListString, inline=True) embed.add_field(name="Commands", value=command_list_string, inline=True)
await interaction.response.send_message(embed=embed)
await interaction.response.send_message(embed=embed)
@tree.error @tree.error
async def on_app_command_error(interaction: Interaction, error): async def on_app_command_error(interaction: Interaction, error):
if isinstance(error, app_commands.MissingPermissions): if isinstance(error, app_commands.MissingPermissions):
await interaction.response.send_message(content="Du hast keine Adminrechte", ephemeral=True) await interaction.response.send_message(content="Du hast keine Adminrechte", ephemeral=True)
else: else:
raise error raise error
#Prevent Gateway Heartbeat Block
# Prevent Gateway Heartbeat Block
try: try:
bot.run(token=botToken) bot.run(token=secret_handler.get_bot_token())
except Exception as err: except Exception as err:
raise err raise err
exit(1)
finally: finally:
logger.info("Stopped") logger.info("Stopped")

View File

@ -1,13 +1,13 @@
class Comic: class Comic:
def __init__(self, data) -> None: def __init__(self, data) -> None:
self.day = data['day'] self.day = data['day']
self.month = data['month'] self.month = data['month']
self.year = data['year'] self.year = data['year']
self.num = data['num'] self.num = data['num']
self.link = data['link'] self.link = data['link']
self.news = data['news'] self.news = data['news']
self.safe_title = data['safe_title'] self.safe_title = data['safe_title']
self.transcript = data['transcript'] self.transcript = data['transcript']
self.alt = data['alt'] self.alt = data['alt']
self.img = data['img'] self.img = data['img']
self.title = data['title'] self.title = data['title']

View File

@ -1,69 +0,0 @@
'''https://gitlab.com/HendrikHeine/py-secret-handler'''
import json
class __fileType:
def __init__(self) -> None:
pass
def _loadFromTXT(self, fileName:str):
'''!!!DONT USE!!!'''
try:
with open(file=fileName, mode="r") as file:
return [0, str(file.readlines()[0].strip("\n"))]
except:
return [1]
def _loadFromJSON(self, fileName:str, item:str):
'''!!!DONT USE!!!'''
if item == "":
return [2]
else:
try:
with open(file=fileName, mode="r") as file:
try:return [0, json.loads(file.read())[item]]
except:return [5]
except:
return [1]
class secret(__fileType):
'''Class for load secrets like API keys or tokens'''
def __init__(self) -> None:
super().__init__()
def loadSecret(self, fileName:str, item=""):
'''
fileName(str)
the name of the secret file.
Valid formats: .json and .txt
item(str)
name of the item in the JSON file. By default empty
Return Values(list):
0: Ok
1: File could not load
2: No item given for JSON
3: Invalid file format (for example .exe, .csv)
4: No format for file given
5: Invalid item for JSON
'''
try:fileType = fileName.split(".")[1]
except:return [4]
if fileType == "json":
result = self._loadFromJSON(fileName=fileName, item=item)
if result[0] == 0:
return result
else:
return [result[0]]
elif fileType == "txt":
result = self._loadFromTXT(fileName=fileName)
if result[0] == 0:
return result
else:
return [result[0]]
else:
return [3]

7
src/secret_handler.py Normal file
View File

@ -0,0 +1,7 @@
import json
def get_bot_token():
with open(file='secret.json', mode='r') as file:
secret = json.load(file)
return secret['BOT_TOKEN']