Ported sparkles over from Nova, updated normal sparkle emoji to not be a star

This commit is contained in:
Lilac-Rose
2025-09-29 20:02:39 +02:00
parent c2f6c76917
commit abde18b3b6
4 changed files with 176 additions and 19 deletions

51
bot.py
View File

@@ -5,7 +5,10 @@ from discord.ext import commands
import asyncio
import glob
import traceback
from xp.database import get_db
from xp.database import get_db as get_xp_db
# Import sparkle DB to ensure it exists
from sparkle.database import get_db as get_sparkle_db
load_dotenv()
@@ -15,15 +18,16 @@ ADMIN_ROLE_ID = int(os.getenv("ADMIN_ROLE_ID"))
bot = commands.Bot(command_prefix="!", intents=discord.Intents.all())
async def load_cogs(folder: str):
# List of files that are NOT cogs (utility files)
non_cog_files = {"add_xp.py", "database.py", "utils.py", "__init__.py","import_old_data.py", "repair_db.py", "reset_db.py"}
"""Load all cogs in the folder except utility files"""
non_cog_files = {"add_xp.py", "database.py", "utils.py", "__init__.py",
"import_old_data.py", "repair_db.py", "reset_db.py"}
for file in glob.glob(f"{folder}/*.py"):
filename = os.path.basename(file)
if filename in non_cog_files:
print(f"Skipping {filename} (utility file)")
continue
module_name = f"{folder}.{os.path.splitext(filename)[0]}"
try:
await bot.load_extension(module_name)
@@ -36,26 +40,34 @@ async def load_cogs(folder: str):
async def on_ready():
print(f"Logged in as {bot.user}!")
# Test database connections
# Ensure XP database connection works
for lifetime in (True, False):
try:
conn, cur = get_db(lifetime)
conn, cur = get_xp_db(lifetime)
conn.close()
print(f"Database connection successful (lifetime={lifetime})")
print(f"XP database connection successful (lifetime={lifetime})")
except Exception as e:
print(f"Database connection failed (lifetime={lifetime}): {e}")
# Load cogs FIRST
print(f"XP database connection failed (lifetime={lifetime}): {e}")
# Ensure Sparkle DB exists
try:
conn = get_sparkle_db()
conn.close()
print("Sparkle database initialized successfully.")
except Exception as e:
print(f"Failed to initialize sparkle database: {e}")
# Load all cogs
await load_cogs("commands")
await load_cogs("wordbomb")
await load_cogs("moderation")
await load_cogs("xp")
# Sync slash commands AFTER cogs are loaded
await load_cogs("sparkle") # <-- Load sparkle cogs
# Sync slash commands after loading cogs
try:
synced = await bot.tree.sync()
print(f"Synced {len(synced)} slash commands")
# Print the names of synced commands for debugging
for cmd in synced:
print(f" - {cmd.name}")
except Exception as e:
@@ -72,20 +84,21 @@ async def on_command_error(ctx, error):
@bot.command(name="reload")
@commands.has_role(ADMIN_ROLE_ID)
async def reload(ctx):
# Reload cogs
"""Reload commands cogs and sync slash commands"""
await load_cogs("commands")
await load_cogs("moderation")
await load_cogs("xp")
# Re-sync slash commands after reload
await load_cogs("sparkle") # Reload sparkle cogs
try:
synced = await bot.tree.sync()
await ctx.send(f"Cogs reloaded successfully! Synced {len(synced)} slash commands.")
except Exception as e:
await ctx.send(f"Cogs reloaded but failed to sync slash commands: {e}")
# hook XP into messages
# Hook XP into messages
from xp.add_xp import add_xp
@bot.event
async def on_message(message):
if message.author.bot:
@@ -106,4 +119,4 @@ async def main():
traceback.print_exc()
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main())

20
sparkle/database.py Normal file
View File

@@ -0,0 +1,20 @@
import sqlite3
import os
DB_PATH = os.path.join(os.path.dirname(__file__), "sparkle.db")
def get_db():
"""Return a SQLite3 connection."""
conn = sqlite3.connect(DB_PATH)
conn.execute("""
CREATE TABLE IF NOT EXISTS sparkles (
server_id TEXT,
user_id TEXT,
epic INTEGER DEFAULT 0,
rare INTEGER DEFAULT 0,
regular INTEGER DEFAULT 0,
PRIMARY KEY (server_id, user_id)
)
""")
conn.commit()
return conn

73
sparkle/leaderboard.py Normal file
View File

@@ -0,0 +1,73 @@
import discord
from discord.ext import commands
from discord import app_commands
from discord.utils import escape_markdown
from .database import get_db
import asyncio
class SparkleLeaderboard(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.sparkle_emojis = {
"epic": "✨",
"rare": "🌟",
"regular": "💫"
}
@commands.hybrid_command(name="sparkleleaderboard", aliases=["sparklelb"], description="Show server Sparkle leaderboard")
@app_commands.describe(limit="Number of users to show (max 20)")
async def sparkle_leaderboard(self, ctx: commands.Context, limit: int = 10):
limit = max(1, min(20, limit))
guild_member_ids = {str(member.id) for member in ctx.guild.members}
if not guild_member_ids:
await ctx.send("This server has no members to display.", ephemeral=True)
return
def db_task():
conn = get_db()
placeholders = ",".join(["?"] * len(guild_member_ids))
query = f"""
SELECT user_id, epic, rare, regular,
(epic + rare + regular) as total
FROM sparkles
WHERE server_id = ? AND user_id IN ({placeholders})
ORDER BY total DESC
LIMIT ?
"""
params = [str(ctx.guild.id), *guild_member_ids, limit]
cursor = conn.execute(query, params)
results = cursor.fetchall()
conn.close()
return results
results = await asyncio.to_thread(db_task)
if not results:
await ctx.send("No sparkle data available for members of this server.", ephemeral=True)
return
embed = discord.Embed(
title=f"{escape_markdown(ctx.guild.name)} Sparkle Leaderboard",
color=discord.Color.gold()
)
for rank, (user_id, epic, rare, regular, total) in enumerate(results, 1):
user = ctx.guild.get_member(int(user_id))
display_name = escape_markdown(user.display_name) if user else f"Unknown User ({user_id})"
sparkles = (
f"{self.sparkle_emojis['epic']} {epic} (Epic) | "
f"{self.sparkle_emojis['rare']} {rare} (Rare) | "
f"{self.sparkle_emojis['regular']} {regular} (Regular) | "
f"**Total:** {total}"
)
embed.add_field(name=f"{rank}. {display_name}", value=sparkles, inline=False)
if rank == 1 and user:
embed.set_thumbnail(url=user.display_avatar.url)
embed.set_footer(text="✨ Epic | 🌟 Rare | 💫 Regular")
await ctx.send(embed=embed)
async def setup(bot):
await bot.add_cog(SparkleLeaderboard(bot))

51
sparkle/sparkle.py Normal file
View File

@@ -0,0 +1,51 @@
import random
import discord
from discord.ext import commands
from .database import get_db
import asyncio
class Sparkle(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.chances = {
"epic": (1, "✨", "an **epic sparkle**"),
"rare": (10, "🌟", "a **rare sparkle**"),
"regular": (1000, "💫", "a **sparkle**")
}
async def _add_sparkle(self, message, sparkle_type):
emoji, description = self.chances[sparkle_type][1:]
await message.add_reaction(emoji)
await message.reply(
f"**{message.author.name}** got {description}! {emoji}",
mention_author=False
)
def db_task():
conn = get_db()
conn.execute(
f"""INSERT INTO sparkles (server_id, user_id, {sparkle_type})
VALUES (?, ?, 1)
ON CONFLICT(server_id, user_id) DO UPDATE SET
{sparkle_type} = {sparkle_type} + 1""",
(str(message.guild.id), str(message.author.id))
)
conn.commit()
conn.close()
await asyncio.to_thread(db_task)
@commands.Cog.listener()
async def on_message(self, message):
if message.author.bot or not message.guild:
return
chance = random.randint(1, 1000000)
if chance == 1:
await self._add_sparkle(message, "epic")
elif chance <= 10:
await self._add_sparkle(message, "rare")
elif chance <= 1000:
await self._add_sparkle(message, "regular")
async def setup(bot):
await bot.add_cog(Sparkle(bot))