mirror of
https://github.com/Lilac-Rose/Lacie.git
synced 2026-08-01 16:04:45 -05:00
Started the command consolodation
This commit is contained in:
parent
6bcf37af3d
commit
8bd385eee5
|
|
@ -158,10 +158,13 @@ class Birthday(commands.Cog):
|
|||
|
||||
return filtered[:25] # Discord limit of 25 at a time
|
||||
|
||||
@app_commands.command(name="setbirthday", description="Set your birthday timezone.")
|
||||
# Create command groups
|
||||
birthday_group = app_commands.Group(name="birthday", description="Manage birthday settings")
|
||||
|
||||
@birthday_group.command(name="set", description="Set your birthday and timezone")
|
||||
@app_commands.describe(date="Your birthday (MM-DD)", timezone="Your timezone, search your city/country to find it!")
|
||||
@app_commands.autocomplete(timezone=timezone_autocomplete)
|
||||
async def setbirthday(self, interaction: discord.Interaction, date: str, timezone: str):
|
||||
async def set_birthday(self, interaction: discord.Interaction, date: str, timezone: str):
|
||||
try:
|
||||
datetime.strptime(date, "%m-%d")
|
||||
except ValueError:
|
||||
|
|
@ -180,8 +183,8 @@ class Birthday(commands.Cog):
|
|||
|
||||
await interaction.response.send_message(f"🎂 Birthday set to '{date}' in timezone '{timezone}'!", ephemeral=True)
|
||||
|
||||
@app_commands.command(name="removebirthday", description="Remove your saved birthday.")
|
||||
async def removebirthday(self, interaction: discord.Interaction):
|
||||
@birthday_group.command(name="remove", description="Remove your saved birthday")
|
||||
async def remove_birthday(self, interaction: discord.Interaction):
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("DELETE FROM birthdays WHERE user_id = ?", (interaction.user.id,))
|
||||
|
|
@ -194,29 +197,9 @@ class Birthday(commands.Cog):
|
|||
else:
|
||||
await interaction.response.send_message("You don't have a birthday set.", ephemeral=True)
|
||||
|
||||
@app_commands.command(name="setbirthdaychannel", description="Set the channel for birthday announcements.")
|
||||
@app_commands.describe(channel="Channel where birthday announcements will be sent.")
|
||||
async def setbirthdaychannel(self, interaction: discord.Interaction, channel: discord.TextChannel):
|
||||
member = interaction.user
|
||||
if not ModerationBase.is_admin():
|
||||
await interaction.response.send_message("You do not have permission to use this command.", ephemeral=True)
|
||||
return
|
||||
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
INSERT INTO guild_settings (guild_id, channel_id)
|
||||
VALUES (?, ?)
|
||||
ON CONFLICT(guild_id) DO UPDATE SET channel_id=excluded.channel_id
|
||||
""", (interaction.guild.id, channel.id))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
await interaction.response.send_message(f"Birthday announcements will be sent in {channel.mention}")
|
||||
|
||||
@app_commands.command(name="listbirthdays", description="List all birthdays for a specific month.")
|
||||
@birthday_group.command(name="list", description="List all birthdays for a specific month")
|
||||
@app_commands.describe(month="Specify a month (1-12) to see birthdays for that month")
|
||||
async def listbirthdays(self, interaction: discord.Interaction, month: int):
|
||||
async def list_birthdays(self, interaction: discord.Interaction, month: int):
|
||||
if month < 1 or month > 12:
|
||||
await interaction.response.send_message("Invalid month! Please use a number between 1 and 12.", ephemeral=True)
|
||||
return
|
||||
|
|
@ -261,6 +244,24 @@ class Birthday(commands.Cog):
|
|||
)
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
@birthday_group.command(name="channel", description="Set the channel for birthday announcements")
|
||||
@app_commands.describe(channel="Channel where birthday announcements will be sent")
|
||||
async def set_channel(self, interaction: discord.Interaction, channel: discord.TextChannel):
|
||||
if not ModerationBase.is_admin():
|
||||
await interaction.response.send_message("You do not have permission to use this command.", ephemeral=True)
|
||||
return
|
||||
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
INSERT INTO guild_settings (guild_id, channel_id)
|
||||
VALUES (?, ?)
|
||||
ON CONFLICT(guild_id) DO UPDATE SET channel_id=excluded.channel_id
|
||||
""", (interaction.guild.id, channel.id))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
await interaction.response.send_message(f"Birthday announcements will be sent in {channel.mention}")
|
||||
|
||||
@tasks.loop(minutes=1)
|
||||
async def check_birthdays(self):
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ class EmbedColor(commands.Cog):
|
|||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.setup_table()
|
||||
|
||||
|
||||
|
||||
def get_db(self):
|
||||
return sqlite3.connect(DB_PATH)
|
||||
|
||||
|
|
@ -25,8 +24,8 @@ class EmbedColor(commands.Cog):
|
|||
""")
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
def get_user_color(self, user:discord.User) -> discord.Color:
|
||||
|
||||
def get_user_color(self, user: discord.User) -> discord.Color:
|
||||
db = self.get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT color FROM user_embed_colors WHERE user_id = ?", (user.id,))
|
||||
|
|
@ -35,12 +34,17 @@ class EmbedColor(commands.Cog):
|
|||
if result and result[0]:
|
||||
return discord.Color(int(result[0], 16))
|
||||
return user.accent_color or discord.Color.blurple()
|
||||
|
||||
@app_commands.command(name="setembedcolor", description="Set your preferred embed color (hex, e.g. #ff66cc).")
|
||||
async def setcolor(self, interaction: discord.Interaction, hex_color: str):
|
||||
|
||||
# Create a command group
|
||||
embed_group = app_commands.Group(name="embedcolor", description="Manage your embed color preferences")
|
||||
|
||||
@embed_group.command(name="set", description="Set your preferred embed color (hex, e.g. #ff66cc)")
|
||||
@app_commands.describe(hex_color="Hex color code (e.g., #ff66cc)")
|
||||
async def set_color(self, interaction: discord.Interaction, hex_color: str):
|
||||
if not hex_color.startswith("#") or len(hex_color) != 7:
|
||||
await interaction.response.send_message("Please provide a valid hex color in the format: `#rrggbb`.", ephemeral=True)
|
||||
return
|
||||
|
||||
try:
|
||||
int(hex_color[1:], 16)
|
||||
except ValueError:
|
||||
|
|
@ -56,11 +60,11 @@ class EmbedColor(commands.Cog):
|
|||
""", (interaction.user.id, hex_color[1:]))
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
|
||||
await interaction.response.send_message(f"Your embed color has been set to `{hex_color}`")
|
||||
|
||||
@app_commands.command(name="myembedcolor", description="View your current embed color.")
|
||||
async def mycolor(self, interaction: discord.Interaction):
|
||||
|
||||
@embed_group.command(name="view", description="View your current embed color")
|
||||
async def view_color(self, interaction: discord.Interaction):
|
||||
color = self.get_user_color(interaction.user)
|
||||
hex_code = f"#{color.value:06x}"
|
||||
embed = discord.Embed(
|
||||
|
|
@ -69,6 +73,20 @@ class EmbedColor(commands.Cog):
|
|||
color=color
|
||||
)
|
||||
await interaction.response.send_message(embed=embed)
|
||||
|
||||
@embed_group.command(name="remove", description="Remove your custom embed color")
|
||||
async def remove_color(self, interaction: discord.Interaction):
|
||||
db = self.get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("DELETE FROM user_embed_colors WHERE user_id = ?", (interaction.user.id,))
|
||||
changes = db.total_changes
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
if changes > 0:
|
||||
await interaction.response.send_message("Your custom embed color has been removed. Default colors will be used.", ephemeral=True)
|
||||
else:
|
||||
await interaction.response.send_message("You don't have a custom embed color set.", ephemeral=True)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(EmbedColor(bot))
|
||||
191
events/git_webhook.py
Normal file
191
events/git_webhook.py
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
"""
|
||||
Discord bot cog that runs a webhook server to receive Git commits.
|
||||
The bot receives the webhook from GitHub and posts directly to Discord.
|
||||
|
||||
Add to your .env (optional):
|
||||
GITHUB_WEBHOOK_SECRET=your_secret_here
|
||||
WEBHOOK_PORT=5000
|
||||
"""
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from aiohttp import web
|
||||
import hmac
|
||||
import hashlib
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
COMMIT_CHANNEL_ID = 876777562599194644
|
||||
USER_ID_TO_PING = 252130669919076352
|
||||
WEBHOOK_SECRET = os.getenv("GITHUB_WEBHOOK_SECRET", "")
|
||||
WEBHOOK_PORT = int(os.getenv("WEBHOOK_PORT", 5000))
|
||||
|
||||
class GitWebhook(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.app = web.Application()
|
||||
self.app.router.add_post('/webhook', self.handle_webhook)
|
||||
self.app.router.add_get('/health', self.health_check)
|
||||
self.runner = None
|
||||
self.site = None
|
||||
|
||||
async def cog_load(self):
|
||||
"""Start the webhook server when cog loads."""
|
||||
self.runner = web.AppRunner(self.app)
|
||||
await self.runner.setup()
|
||||
self.site = web.TCPSite(self.runner, '0.0.0.0', WEBHOOK_PORT)
|
||||
await self.site.start()
|
||||
print(f"✅ Git webhook server started on port {WEBHOOK_PORT}")
|
||||
print(f" Configure GitHub to send webhooks to: http://185.187.170.61:{WEBHOOK_PORT}/webhook")
|
||||
|
||||
async def cog_unload(self):
|
||||
"""Stop the webhook server when cog unloads."""
|
||||
if self.site:
|
||||
await self.site.stop()
|
||||
if self.runner:
|
||||
await self.runner.cleanup()
|
||||
print("🛑 Git webhook server stopped")
|
||||
|
||||
def verify_signature(self, payload_body, signature_header):
|
||||
"""Verify GitHub webhook signature for security."""
|
||||
if not WEBHOOK_SECRET:
|
||||
return True
|
||||
|
||||
hash_object = hmac.new(
|
||||
WEBHOOK_SECRET.encode('utf-8'),
|
||||
msg=payload_body,
|
||||
digestmod=hashlib.sha256
|
||||
)
|
||||
expected_signature = "sha256=" + hash_object.hexdigest()
|
||||
return hmac.compare_digest(expected_signature, signature_header)
|
||||
|
||||
async def health_check(self, request):
|
||||
"""Health check endpoint."""
|
||||
return web.json_response({"status": "healthy"})
|
||||
|
||||
async def handle_webhook(self, request):
|
||||
"""Handle incoming Git webhook from GitHub/GitLab."""
|
||||
try:
|
||||
# Verify signature if secret is configured
|
||||
if WEBHOOK_SECRET:
|
||||
signature = request.headers.get('X-Hub-Signature-256', '')
|
||||
body = await request.read()
|
||||
if not self.verify_signature(body, signature):
|
||||
return web.json_response({"error": "Invalid signature"}, status=403)
|
||||
data = await request.json()
|
||||
else:
|
||||
data = await request.json()
|
||||
|
||||
# Handle GitHub ping event (test from GitHub)
|
||||
if 'zen' in data and 'hook_id' in data:
|
||||
print("✅ Received GitHub ping event - webhook is configured correctly!")
|
||||
return web.json_response({"status": "pong"}, status=200)
|
||||
|
||||
# Get the Discord channel
|
||||
channel = self.bot.get_channel(COMMIT_CHANNEL_ID)
|
||||
if not channel:
|
||||
print(f"❌ Channel {COMMIT_CHANNEL_ID} not found!")
|
||||
return web.json_response({"error": "Channel not found"}, status=500)
|
||||
|
||||
# Handle GitHub push events
|
||||
if 'commits' in data and 'repository' in data:
|
||||
await self.handle_github_push(data, channel)
|
||||
return web.json_response({"status": "success"}, status=200)
|
||||
|
||||
# Handle GitLab push events
|
||||
elif 'project' in data and 'commits' in data:
|
||||
await self.handle_gitlab_push(data, channel)
|
||||
return web.json_response({"status": "success"}, status=200)
|
||||
|
||||
print(f"⚠️ Unknown webhook format. Keys in data: {list(data.keys())}")
|
||||
return web.json_response({"error": "Unknown webhook format"}, status=400)
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Webhook error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
async def handle_github_push(self, data, channel):
|
||||
"""Handle GitHub push webhook."""
|
||||
repo_name = data['repository']['full_name']
|
||||
repo_url = data['repository']['html_url']
|
||||
branch = data['ref'].split('/')[-1]
|
||||
pusher = data['pusher']['name']
|
||||
commits = data['commits']
|
||||
compare_url = data.get('compare', '')
|
||||
|
||||
if not commits:
|
||||
return
|
||||
|
||||
# Build commit list
|
||||
commit_lines = []
|
||||
for commit in commits[:10]: # Show up to 10 commits
|
||||
short_sha = commit['id'][:7]
|
||||
message = commit['message'].split('\n')[0] # First line only
|
||||
if len(message) > 72:
|
||||
message = message[:69] + "..."
|
||||
author = commit['author']['name']
|
||||
url = commit['url']
|
||||
commit_lines.append(f"[`{short_sha}`]({url}) {message}")
|
||||
|
||||
# Create embed
|
||||
embed = discord.Embed(
|
||||
title=f"📝 [{repo_name}:{branch}] {len(commits)} new commit{'s' if len(commits) != 1 else ''}",
|
||||
url=compare_url if compare_url else repo_url,
|
||||
description="\n".join(commit_lines),
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
|
||||
if len(commits) > 10:
|
||||
embed.description += f"\n\n*...and {len(commits) - 10} more commit(s)*"
|
||||
|
||||
embed.set_author(name=pusher, icon_url="https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png")
|
||||
embed.set_footer(text="GitHub")
|
||||
|
||||
# Send to Discord
|
||||
await channel.send(f"<@{USER_ID_TO_PING}>", embed=embed)
|
||||
|
||||
async def handle_gitlab_push(self, data, channel):
|
||||
"""Handle GitLab push webhook."""
|
||||
repo_name = data['project']['path_with_namespace']
|
||||
repo_url = data['project']['web_url']
|
||||
branch = data['ref'].split('/')[-1]
|
||||
pusher = data['user_name']
|
||||
commits = data['commits']
|
||||
|
||||
if not commits:
|
||||
return
|
||||
|
||||
# Build commit list
|
||||
commit_lines = []
|
||||
for commit in commits[:10]:
|
||||
short_sha = commit['id'][:7]
|
||||
message = commit['message'].split('\n')[0]
|
||||
if len(message) > 72:
|
||||
message = message[:69] + "..."
|
||||
author = commit['author']['name']
|
||||
url = commit['url']
|
||||
commit_lines.append(f"[`{short_sha}`]({url}) {message}")
|
||||
|
||||
# Create embed
|
||||
embed = discord.Embed(
|
||||
title=f"📝 [{repo_name}:{branch}] {len(commits)} new commit{'s' if len(commits) != 1 else ''}",
|
||||
url=repo_url,
|
||||
description="\n".join(commit_lines),
|
||||
color=0xFC6D26 # GitLab orange
|
||||
)
|
||||
|
||||
if len(commits) > 10:
|
||||
embed.description += f"\n\n*...and {len(commits) - 10} more commit(s)*"
|
||||
|
||||
embed.set_author(name=pusher)
|
||||
embed.set_footer(text="GitLab")
|
||||
|
||||
# Send to Discord
|
||||
await channel.send(f"<@{USER_ID_TO_PING}>", embed=embed)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(GitWebhook(bot))
|
||||
152
xp/calculate.py
152
xp/calculate.py
|
|
@ -26,94 +26,106 @@ class CalculateCommand(commands.Cog):
|
|||
user: discord.Member = None,
|
||||
board_type: app_commands.Choice[str] = None
|
||||
):
|
||||
if user is None:
|
||||
user = interaction.user
|
||||
# Immediately defer to prevent timeout
|
||||
await interaction.response.defer(thinking=True, ephemeral=False)
|
||||
|
||||
# Load config fresh
|
||||
config = load_config()
|
||||
COOLDOWN = config["COOLDOWN"]
|
||||
random_xp_config = config.get("RANDOM_XP", {"min": 50, "max": 100})
|
||||
try:
|
||||
if user is None:
|
||||
user = interaction.user
|
||||
|
||||
# Determine which database to use
|
||||
use_lifetime = True if (board_type is None or board_type.value == "lifetime") else False
|
||||
board_name = "Lifetime" if use_lifetime else "Annual"
|
||||
# Load config safely
|
||||
config = load_config()
|
||||
COOLDOWN = config["COOLDOWN"]
|
||||
random_xp_config = config.get("RANDOM_XP", {"min": 50, "max": 100})
|
||||
|
||||
conn, cur = get_db(lifetime=use_lifetime)
|
||||
cur.execute("SELECT xp, level, last_message FROM xp WHERE user_id = ?", (str(user.id),))
|
||||
row = cur.fetchone()
|
||||
conn.close()
|
||||
# Determine board type
|
||||
use_lifetime = True if (board_type is None or board_type.value == "lifetime") else False
|
||||
board_name = "Lifetime" if use_lifetime else "Annual"
|
||||
|
||||
if not row:
|
||||
await interaction.response.send_message(
|
||||
f"{user.mention} has no XP yet on the **{board_name}** board.",
|
||||
ephemeral=True
|
||||
)
|
||||
return
|
||||
|
||||
current_xp, current_level, last_message = row
|
||||
# Database query
|
||||
conn, cur = get_db(db_type="lifetime")
|
||||
cur.execute("SELECT xp, level, last_message FROM xp WHERE user_id = ?", (str(user.id),))
|
||||
row = cur.fetchone()
|
||||
conn.close()
|
||||
|
||||
if level <= current_level:
|
||||
await interaction.response.send_message(
|
||||
f"{user.mention} is already level {current_level} on the **{board_name}** board. Please choose a higher target level.",
|
||||
ephemeral=True
|
||||
)
|
||||
return
|
||||
|
||||
target_xp = xp_for_level(level)
|
||||
remaining_xp = target_xp - current_xp
|
||||
if not row:
|
||||
await interaction.followup.send(
|
||||
f"{user.mention} has no XP yet on the **{board_name}** board.",
|
||||
ephemeral=True
|
||||
)
|
||||
return
|
||||
|
||||
current_xp, current_level, last_message = row
|
||||
|
||||
multiplier = get_multiplier(user, apply_multiplier=True)
|
||||
if level <= current_level:
|
||||
await interaction.followup.send(
|
||||
f"{user.mention} is already level {current_level} on the **{board_name}** board. Please choose a higher target level.",
|
||||
ephemeral=True
|
||||
)
|
||||
return
|
||||
|
||||
target_xp = xp_for_level(level)
|
||||
remaining_xp = target_xp - current_xp
|
||||
|
||||
min_xp_per_msg = int(random_xp_config["min"] * multiplier)
|
||||
max_xp_per_msg = int(random_xp_config["max"] * multiplier)
|
||||
avg_xp_per_msg = (min_xp_per_msg + max_xp_per_msg) / 2
|
||||
multiplier = get_multiplier(user, apply_multiplier=True)
|
||||
|
||||
max_messages = int(remaining_xp / min_xp_per_msg)
|
||||
min_messages = int(remaining_xp / max_xp_per_msg)
|
||||
avg_messages = int(remaining_xp / avg_xp_per_msg)
|
||||
min_xp_per_msg = int(random_xp_config["min"] * multiplier)
|
||||
max_xp_per_msg = int(random_xp_config["max"] * multiplier)
|
||||
avg_xp_per_msg = (min_xp_per_msg + max_xp_per_msg) / 2
|
||||
|
||||
time_remaining_seconds = avg_messages * COOLDOWN
|
||||
days = time_remaining_seconds / 86400
|
||||
max_messages = int(remaining_xp / min_xp_per_msg)
|
||||
min_messages = int(remaining_xp / max_xp_per_msg)
|
||||
avg_messages = int(remaining_xp / avg_xp_per_msg)
|
||||
|
||||
progress = (current_xp / target_xp) * 100
|
||||
time_remaining_seconds = avg_messages * COOLDOWN
|
||||
days = time_remaining_seconds / 86400
|
||||
|
||||
bar_length = 30
|
||||
filled = int((progress / 100) * bar_length)
|
||||
bar = "█" * filled + "░" * (bar_length - filled)
|
||||
progress = (current_xp / target_xp) * 100
|
||||
|
||||
current_xp_fmt = f"{current_xp:,}"
|
||||
target_xp_fmt = f"{target_xp:,}"
|
||||
remaining_xp_fmt = f"{remaining_xp:,}"
|
||||
min_messages_fmt = f"{min_messages:,}"
|
||||
max_messages_fmt = f"{max_messages:,}"
|
||||
avg_messages_fmt = f"{avg_messages:,}"
|
||||
# Progress bar
|
||||
bar_length = 30
|
||||
filled = int((progress / 100) * bar_length)
|
||||
bar = "█" * filled + "░" * (bar_length - filled)
|
||||
|
||||
time_since_last = time.time() - last_message
|
||||
cooldown_ready = can_get_xp(last_message)
|
||||
cooldown_status = ""
|
||||
if not cooldown_ready:
|
||||
cooldown_remaining = COOLDOWN - time_since_last
|
||||
cooldown_status = f"\n⏳ Cooldown: {int(cooldown_remaining)}s remaining"
|
||||
# Formatting numbers
|
||||
current_xp_fmt = f"{current_xp:,}"
|
||||
target_xp_fmt = f"{target_xp:,}"
|
||||
remaining_xp_fmt = f"{remaining_xp:,}"
|
||||
min_messages_fmt = f"{min_messages:,}"
|
||||
max_messages_fmt = f"{max_messages:,}"
|
||||
avg_messages_fmt = f"{avg_messages:,}"
|
||||
|
||||
response = f"""**{board_name} Level {level} Target**
|
||||
**Current XP:** {current_xp_fmt} (Level {current_level})
|
||||
**Target XP:** {target_xp_fmt}
|
||||
**Remaining XP:** {remaining_xp_fmt}
|
||||
# Cooldown info
|
||||
time_since_last = time.time() - last_message
|
||||
cooldown_ready = can_get_xp(last_message)
|
||||
cooldown_status = ""
|
||||
if not cooldown_ready:
|
||||
cooldown_remaining = COOLDOWN - time_since_last
|
||||
cooldown_status = f"\n⏳ Cooldown: {int(cooldown_remaining)}s remaining"
|
||||
|
||||
**XP per message:** {min_xp_per_msg} - {max_xp_per_msg}
|
||||
**Messages remaining:** {min_messages_fmt} - {max_messages_fmt} (avg. {avg_messages_fmt})
|
||||
**Time remaining:** {days:.1f} days{cooldown_status}
|
||||
response = f"""**{board_name} Level {level} Target**
|
||||
**Current XP:** {current_xp_fmt} (Level {current_level})
|
||||
**Target XP:** {target_xp_fmt}
|
||||
**Remaining XP:** {remaining_xp_fmt}
|
||||
|
||||
{bar} ({progress:.2f}%)"""
|
||||
**XP per message:** {min_xp_per_msg} - {max_xp_per_msg}
|
||||
**Messages remaining:** {min_messages_fmt} - {max_messages_fmt} (avg. {avg_messages_fmt})
|
||||
**Time remaining:** {days:.1f} days{cooldown_status}
|
||||
|
||||
embed = discord.Embed(
|
||||
description=response,
|
||||
color=self.bot.get_cog("EmbedColor").get_user_color(interaction.user)
|
||||
)
|
||||
embed.set_author(name=user.display_name, icon_url=user.display_avatar.url)
|
||||
{bar} ({progress:.2f}%)"""
|
||||
|
||||
await interaction.response.send_message(embed=embed)
|
||||
# Safe color handling
|
||||
color_cog = self.bot.get_cog("EmbedColor")
|
||||
color = color_cog.get_user_color(interaction.user) if color_cog else discord.Color.blurple()
|
||||
|
||||
embed = discord.Embed(description=response, color=color)
|
||||
embed.set_author(name=user.display_name, icon_url=user.display_avatar.url)
|
||||
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
except Exception as e:
|
||||
await interaction.followup.send(f"⚠️ **Error:** {e}", ephemeral=False)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(CalculateCommand(bot))
|
||||
await bot.add_cog(CalculateCommand(bot))
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user