modified: bot.py
This commit is contained in:
154
bot.py
154
bot.py
@@ -22,6 +22,8 @@ from bs4 import BeautifulSoup
|
||||
from dotenv import load_dotenv
|
||||
import random
|
||||
import time
|
||||
import hashlib
|
||||
from urllib.parse import urlparse
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@@ -204,10 +206,17 @@ def close_database_connection(connection):
|
||||
if connection and connection.is_connected():
|
||||
connection.close()
|
||||
|
||||
def create_user_data_with_member(user_id, guild_id, member=None):
|
||||
async def create_user_data_with_member(user_id, guild_id, member=None):
|
||||
"""Erstellt neue User-Daten mit korrekten Informationen vom Member-Objekt"""
|
||||
nickname = member.display_name if member else ""
|
||||
profile_picture = str(member.display_avatar.url) if member and member.display_avatar else None
|
||||
|
||||
# Profilbild herunterladen und lokal speichern
|
||||
if member and member.display_avatar:
|
||||
discord_avatar_url = str(member.display_avatar.url)
|
||||
profile_picture = await download_and_save_profile_image(user_id, discord_avatar_url)
|
||||
else:
|
||||
profile_picture = "/static/default_profile.png"
|
||||
|
||||
join_date = member.joined_at.date() if member and member.joined_at else None
|
||||
|
||||
user_data = {
|
||||
@@ -242,7 +251,7 @@ def create_user_data_with_member(user_id, guild_id, member=None):
|
||||
join_date
|
||||
)
|
||||
|
||||
logger.info(f"Created new user data for {nickname} (ID: {user_id}) with join_date: {join_date}")
|
||||
logger.info(f"Created new user data for {nickname} (ID: {user_id}) with join_date: {join_date} and profile_picture: {profile_picture}")
|
||||
return user_data
|
||||
|
||||
def load_user_data_from_mysql(user_id, guild_id):
|
||||
@@ -344,7 +353,7 @@ def remove_user_data_from_cache(user_id, guild_id):
|
||||
pending_deletion[(user_id, guild_id)].cancel()
|
||||
del pending_deletion[(user_id, guild_id)]
|
||||
|
||||
def load_user_data(user_id, guild_id, member=None):
|
||||
async def load_user_data(user_id, guild_id, member=None):
|
||||
if (user_id, guild_id) in cached_user_data:
|
||||
return cached_user_data[(user_id, guild_id)]
|
||||
|
||||
@@ -353,7 +362,50 @@ def load_user_data(user_id, guild_id, member=None):
|
||||
|
||||
# Wenn keine User-Daten existieren, erstelle neue mit Member-Informationen
|
||||
if not user_data or user_data.get("user_id") is None:
|
||||
user_data = create_user_data_with_member(user_id, guild_id, member)
|
||||
user_data = await create_user_data_with_member(user_id, guild_id, member)
|
||||
|
||||
asyncio.ensure_future(cache_user_data(user_id, guild_id, user_data))
|
||||
return user_data
|
||||
|
||||
def load_user_data_sync(user_id, guild_id):
|
||||
"""Synchrone Version von load_user_data für bestehende Commands"""
|
||||
if (user_id, guild_id) in cached_user_data:
|
||||
return cached_user_data[(user_id, guild_id)]
|
||||
|
||||
# Daten aus der Datenbank laden oder neu anlegen
|
||||
user_data = load_user_data_from_mysql(user_id, guild_id)
|
||||
|
||||
# Wenn keine User-Daten existieren, erstelle neue mit Default-Werten
|
||||
if not user_data or user_data.get("user_id") is None:
|
||||
user_data = {
|
||||
"user_id": user_id,
|
||||
"guild_id": guild_id,
|
||||
"permission": 0,
|
||||
"points": 0,
|
||||
"ban": 0,
|
||||
"askmultus": 0,
|
||||
"filter_value": 0,
|
||||
"rank": 0,
|
||||
"chat_history": [],
|
||||
"asknotes_history": [],
|
||||
"xp": 0,
|
||||
"level": 1,
|
||||
"nickname": ""
|
||||
}
|
||||
insert_user_data(
|
||||
user_data["user_id"],
|
||||
user_data["guild_id"],
|
||||
user_data["permission"],
|
||||
user_data["points"],
|
||||
user_data["ban"],
|
||||
user_data["askmultus"],
|
||||
user_data["filter_value"],
|
||||
user_data["chat_history"],
|
||||
user_data["xp"],
|
||||
user_data["level"],
|
||||
user_data["nickname"],
|
||||
"/static/default_profile.png"
|
||||
)
|
||||
|
||||
asyncio.ensure_future(cache_user_data(user_id, guild_id, user_data))
|
||||
return user_data
|
||||
@@ -619,7 +671,7 @@ class Giveaway:
|
||||
async def startgiveaway(ctx, platform: str, prize: str, num_winners: int, title: str, subtitle: str, duration: str):
|
||||
"""Creates a new giveaway, only available for admins."""
|
||||
guild_id = ctx.guild.id
|
||||
user_data = load_user_data(ctx.author.id, guild_id)
|
||||
user_data = load_user_data_sync(ctx.author.id, guild_id)
|
||||
if user_data["permission"] < 5:
|
||||
await ctx.send("You don't have permission to create a giveaway.")
|
||||
return
|
||||
@@ -879,7 +931,7 @@ def calculate_xp_needed_for_level(level):
|
||||
async def add_xp_to_user(user_id, guild_id, xp_gained, member=None):
|
||||
"""Fügt einem Benutzer XP hinzu und überprüft, ob er ein Level aufsteigt. Aktualisiert auch Benutzerdaten."""
|
||||
# Lade Benutzerdaten (XP, Level, etc.) - mit member-Objekt für neue User
|
||||
user_data = load_user_data(user_id, guild_id, member)
|
||||
user_data = await load_user_data(user_id, guild_id, member)
|
||||
|
||||
# Initialisiere XP, falls es None ist
|
||||
user_data["xp"] = user_data.get("xp", 0)
|
||||
@@ -911,11 +963,22 @@ async def add_xp_to_user(user_id, guild_id, xp_gained, member=None):
|
||||
update_user_data(user_id, guild_id, "nickname", new_nickname)
|
||||
user_data["nickname"] = new_nickname
|
||||
|
||||
# Aktualisiere Profilbild
|
||||
new_profile_picture = str(member.display_avatar.url) if member.display_avatar else None
|
||||
if user_data.get("profile_picture") != new_profile_picture:
|
||||
update_user_data(user_id, guild_id, "profile_picture", new_profile_picture)
|
||||
user_data["profile_picture"] = new_profile_picture
|
||||
# Aktualisiere Profilbild - mit lokalem Download und Hash-Vergleich
|
||||
if member.display_avatar:
|
||||
discord_avatar_url = str(member.display_avatar.url)
|
||||
# Download und speichere das Profilbild lokal
|
||||
local_profile_path = await download_and_save_profile_image(user_id, discord_avatar_url)
|
||||
|
||||
# Speichere den lokalen Pfad in der Datenbank statt der Discord URL
|
||||
if user_data.get("profile_picture") != local_profile_path:
|
||||
update_user_data(user_id, guild_id, "profile_picture", local_profile_path)
|
||||
user_data["profile_picture"] = local_profile_path
|
||||
else:
|
||||
# Kein Profilbild vorhanden, nutze Default
|
||||
default_path = "/static/default_profile.png"
|
||||
if user_data.get("profile_picture") != default_path:
|
||||
update_user_data(user_id, guild_id, "profile_picture", default_path)
|
||||
user_data["profile_picture"] = default_path
|
||||
|
||||
# Aktualisiere Join-Datum - IMMER wenn member.joined_at verfügbar ist
|
||||
if member.joined_at:
|
||||
@@ -1047,7 +1110,7 @@ async def on_message(message):
|
||||
|
||||
# Optional: Level-Up Benachrichtigung senden
|
||||
if level_up:
|
||||
user_data = load_user_data(user_id, guild_id)
|
||||
user_data = await load_user_data(user_id, guild_id, member)
|
||||
new_level = user_data["level"]
|
||||
try:
|
||||
await message.channel.send(f"🎉 {member.mention} has reached **Level {new_level}**! Congratulations! 🎉")
|
||||
@@ -1479,6 +1542,71 @@ CACHE_DIR = "cache"
|
||||
if not os.path.exists(CACHE_DIR):
|
||||
os.makedirs(CACHE_DIR)
|
||||
|
||||
# Profilbild-Ordner erstellen
|
||||
PROFILE_IMAGES_DIR = "static/profile_images"
|
||||
if not os.path.exists(PROFILE_IMAGES_DIR):
|
||||
os.makedirs(PROFILE_IMAGES_DIR)
|
||||
|
||||
def get_url_hash(url):
|
||||
"""Erstellt einen Hash aus der URL für Vergleichszwecke"""
|
||||
if not url:
|
||||
return None
|
||||
return hashlib.md5(url.encode('utf-8')).hexdigest()
|
||||
|
||||
def get_local_profile_path(user_id):
|
||||
"""Gibt den lokalen Pfad für das Profilbild eines Users zurück"""
|
||||
return os.path.join(PROFILE_IMAGES_DIR, f"user_{user_id}.png")
|
||||
|
||||
def get_web_profile_path(user_id):
|
||||
"""Gibt den Web-Pfad für das Profilbild eines Users zurück"""
|
||||
return f"/static/profile_images/user_{user_id}.png"
|
||||
|
||||
async def download_and_save_profile_image(user_id, discord_url):
|
||||
"""Lädt ein Profilbild herunter und speichert es lokal"""
|
||||
if not discord_url:
|
||||
return "/static/default_profile.png"
|
||||
|
||||
try:
|
||||
local_path = get_local_profile_path(user_id)
|
||||
web_path = get_web_profile_path(user_id)
|
||||
|
||||
# Überprüfe, ob das Bild bereits existiert und der Hash gleich ist
|
||||
hash_file = local_path + ".hash"
|
||||
current_hash = get_url_hash(discord_url)
|
||||
|
||||
if os.path.exists(local_path) and os.path.exists(hash_file):
|
||||
with open(hash_file, 'r') as f:
|
||||
stored_hash = f.read().strip()
|
||||
|
||||
if stored_hash == current_hash:
|
||||
logger.info(f"Profile image for user {user_id} is up to date, skipping download")
|
||||
return web_path
|
||||
|
||||
# Download das Bild
|
||||
logger.info(f"Downloading profile image for user {user_id} from {discord_url}")
|
||||
response = requests.get(discord_url, timeout=10)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Speichere das Bild
|
||||
with open(local_path, 'wb') as f:
|
||||
f.write(response.content)
|
||||
|
||||
# Speichere den Hash
|
||||
with open(hash_file, 'w') as f:
|
||||
f.write(current_hash)
|
||||
|
||||
logger.info(f"Successfully downloaded and saved profile image for user {user_id}")
|
||||
return web_path
|
||||
else:
|
||||
logger.warning(f"Failed to download profile image for user {user_id}: HTTP {response.status_code}")
|
||||
return "/static/default_profile.png"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error downloading profile image for user {user_id}: {e}")
|
||||
return "/static/default_profile.png"
|
||||
|
||||
# Cache-Ordner für Notizen
|
||||
|
||||
@client.hybrid_command()
|
||||
async def addnotes(ctx, type: str, *, source: str):
|
||||
"""Adds a note that can be consulted later."""
|
||||
|
||||
Reference in New Issue
Block a user