mirror of
https://github.com/Lilac-Rose/Lacie.git
synced 2026-07-22 02:21:33 -05:00
145 lines
5.3 KiB
Python
145 lines
5.3 KiB
Python
import discord
|
|
from discord.ext import commands
|
|
from discord import app_commands
|
|
from discord.ui import View, Button
|
|
from .database import get_db
|
|
from .groups import xp_group
|
|
import math
|
|
|
|
class LeaderboardView(View):
|
|
def __init__(self, embed_pages):
|
|
super().__init__(timeout=60)
|
|
self.embed_pages = embed_pages
|
|
self.current_page = 0
|
|
self.update_button_states()
|
|
|
|
async def update_message(self, interaction: discord.Interaction):
|
|
self.update_button_states()
|
|
embed = self.embed_pages[self.current_page]
|
|
await interaction.response.edit_message(embed=embed, view=self)
|
|
|
|
def update_button_states(self):
|
|
self.previous.disabled = self.current_page == 0
|
|
self.next.disabled = self.current_page == len(self.embed_pages) - 1
|
|
|
|
@discord.ui.button(label="⬅️ Previous", style=discord.ButtonStyle.secondary)
|
|
async def previous(self, interaction: discord.Interaction, button: Button):
|
|
if self.current_page > 0:
|
|
self.current_page -= 1
|
|
await self.update_message(interaction)
|
|
|
|
@discord.ui.button(label="➡️ Next", style=discord.ButtonStyle.secondary)
|
|
async def next(self, interaction: discord.Interaction, button: Button):
|
|
if self.current_page < len(self.embed_pages) - 1:
|
|
self.current_page += 1
|
|
await self.update_message(interaction)
|
|
|
|
async def on_timeout(self):
|
|
for child in self.children:
|
|
if isinstance(child, Button):
|
|
child.disabled = True
|
|
|
|
if hasattr(self, "message") and self.message:
|
|
try:
|
|
await self.message.edit(view=self)
|
|
except discord.NotFound:
|
|
pass
|
|
|
|
|
|
class Leaderboard(commands.Cog):
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
# Register this command onto the shared xp group
|
|
xp_group.add_command(app_commands.command(name="top", description="Show the server leaderboard")(self.leaderboard))
|
|
|
|
@app_commands.describe(
|
|
board_type="Choose which leaderboard to view",
|
|
show_absent="Include members who are no longer in the server (default: False)"
|
|
)
|
|
@app_commands.choices(
|
|
board_type=[
|
|
app_commands.Choice(name="Lifetime XP", value="lifetime"),
|
|
app_commands.Choice(name="Annual XP", value="annual"),
|
|
app_commands.Choice(name="Monthly XP", value="monthly"),
|
|
app_commands.Choice(name="Weekly XP", value="weekly"),
|
|
app_commands.Choice(name="Daily XP", value="daily")
|
|
]
|
|
)
|
|
async def leaderboard(
|
|
self,
|
|
interaction: discord.Interaction,
|
|
board_type: app_commands.Choice[str] = None,
|
|
show_absent: bool = False
|
|
):
|
|
await interaction.response.defer(thinking=True)
|
|
|
|
board_type_value = board_type.value if board_type else "annual"
|
|
board_display_name = board_type.name if board_type else "Annual XP"
|
|
|
|
conn, cur = get_db(board_type_value)
|
|
|
|
cur.execute("SELECT user_id, xp, level FROM xp ORDER BY xp DESC")
|
|
all_rows = cur.fetchall()
|
|
conn.close()
|
|
|
|
if not all_rows:
|
|
return await interaction.followup.send("No leaderboard data yet!", ephemeral=True)
|
|
|
|
user_id = str(interaction.user.id)
|
|
|
|
# Filter out absent users UNLESS show_absent is True
|
|
if not show_absent:
|
|
all_rows = [
|
|
row for row in all_rows
|
|
if interaction.guild.get_member(int(row[0])) is not None
|
|
]
|
|
|
|
if not all_rows:
|
|
return await interaction.followup.send(
|
|
"No visible leaderboard entries with the current settings.", ephemeral=True
|
|
)
|
|
|
|
per_page = 10
|
|
total_pages = math.ceil(len(all_rows) / per_page)
|
|
embeds = []
|
|
|
|
for page_num in range(total_pages):
|
|
start_idx = page_num * per_page
|
|
end_idx = start_idx + per_page
|
|
page_rows = all_rows[start_idx:end_idx]
|
|
|
|
embed = discord.Embed(
|
|
title=f"{board_display_name} Leaderboard (Page {page_num + 1}/{total_pages})",
|
|
color=self.bot.get_cog("EmbedColor").get_user_color(interaction.user)
|
|
)
|
|
|
|
if page_num == 0 and page_rows:
|
|
top_member = interaction.guild.get_member(int(page_rows[0][0]))
|
|
if top_member:
|
|
embed.set_thumbnail(url=top_member.display_avatar.url)
|
|
|
|
description_lines = []
|
|
for idx, (uid, xp, level) in enumerate(page_rows, start=start_idx + 1):
|
|
member = interaction.guild.get_member(int(uid))
|
|
if member:
|
|
line = f"{idx}. {member.mention} · Level {level} · {xp:,} XP"
|
|
elif show_absent:
|
|
# Only show absent users if show_absent is True
|
|
line = f"{idx}. User {uid} · Level {level} · {xp:,} XP"
|
|
else:
|
|
continue
|
|
description_lines.append(line)
|
|
|
|
embed.description = "\n".join(description_lines)
|
|
embeds.append(embed)
|
|
|
|
view = LeaderboardView(embeds)
|
|
await interaction.followup.send(embed=embeds[0], view=view)
|
|
|
|
view.message = await interaction.original_response()
|
|
|
|
def cog_unload(self):
|
|
xp_group.remove_command("top")
|
|
|
|
async def setup(bot):
|
|
await bot.add_cog(Leaderboard(bot)) |