modified: bot.py

This commit is contained in:
SimolZimol
2025-10-10 13:36:22 +02:00
parent 7e0fcd8527
commit 02e9de031d

346
bot.py
View File

@@ -2090,350 +2090,6 @@ async def updategiveawaymessage(ctx, giveaway_id: str):
logger.error(f"Error updating giveaway message: {e}") logger.error(f"Error updating giveaway message: {e}")
await ctx.send(f"❌ Error updating giveaway message: {str(e)}") await ctx.send(f"❌ Error updating giveaway message: {str(e)}")
@client.hybrid_command()
async def endgiveaway(ctx, giveaway_id: str, force: bool = False):
"""Manually end a giveaway and pick winners (Only available for admins)
Parameters:
- giveaway_id: The giveaway ID (first 8 characters of UUID are enough)
- force: Force end even if not expired (default: False)
"""
guild_id = ctx.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 end giveaways.")
return
# Find giveaway by partial ID (check both memory and database)
matching_giveaway = None
matching_id = None
source = "memory"
# First check memory
for giv_id, giveaway in giveaways.items():
if giv_id.startswith(giveaway_id) or giveaway_id in giv_id:
matching_giveaway = giveaway
matching_id = giv_id
break
# If not in memory, check database
if not matching_giveaway:
active_processes = get_active_processes(process_type="giveaway", guild_id=guild_id)
for process in active_processes:
if str(process["uuid"]).startswith(giveaway_id) or giveaway_id in str(process["uuid"]):
# Load giveaway from database
try:
guild = ctx.guild
channel = guild.get_channel(process["channel_id"])
if not channel:
await ctx.send(f"❌ Original channel not found for giveaway `{giveaway_id}`")
return
# Create minimal context
class MinimalContext:
def __init__(self, channel):
self.channel = channel
self.guild = channel.guild
temp_ctx = MinimalContext(channel)
matching_giveaway = Giveaway.from_process_data(temp_ctx, process["data"])
matching_giveaway.end_time = process["end_time"]
matching_giveaway.process_uuid = process["uuid"]
# Restore participants
stored_participants = process["data"].get("participants", [])
for participant_data in stored_participants:
try:
user = await client.fetch_user(participant_data["id"])
matching_giveaway.participants.append(user)
except:
pass
matching_id = str(process["uuid"])
source = "database"
break
except Exception as e:
logger.error(f"Error loading giveaway from database: {e}")
await ctx.send(f"❌ Error loading giveaway: {str(e)}")
return
if not matching_giveaway:
await ctx.send(f"❌ No giveaway found with ID starting with `{giveaway_id}`")
return
# Check if giveaway can be ended
is_expired = matching_giveaway.is_finished()
if not is_expired and not force:
remaining = matching_giveaway.end_time - datetime.now()
embed = discord.Embed(
title="⚠️ Giveaway Not Expired",
description=f"This giveaway is still active and not expired yet.",
color=0xffa500,
timestamp=datetime.now()
)
embed.add_field(name="🆔 Giveaway ID", value=f"`{matching_id[:8]}...`", inline=True)
embed.add_field(name="⏰ Time Left", value=f"<t:{int(matching_giveaway.end_time.timestamp())}:R>", inline=True)
embed.add_field(name="🔧 Force End", value="Use `/endgiveaway <id> True` to force end", inline=False)
await ctx.send(embed=embed)
return
# Check if giveaway has participants
if len(matching_giveaway.participants) == 0:
embed = discord.Embed(
title="❌ No Participants",
description=f"This giveaway has no participants, so no winners can be selected.",
color=0xff0000,
timestamp=datetime.now()
)
embed.add_field(name="🆔 Giveaway ID", value=f"`{matching_id[:8]}...`", inline=True)
embed.add_field(name="👥 Participants", value="0", inline=True)
# Still mark as completed
matching_giveaway.complete_giveaway()
if source == "memory" and matching_id in giveaways:
del giveaways[matching_id]
await ctx.send(embed=embed)
return
try:
# Pick winners
winners = matching_giveaway.pick_winners()
if not winners:
await ctx.send(f"❌ Could not pick winners from {len(matching_giveaway.participants)} participants.")
return
# Create winner announcement
winner_embed = discord.Embed(
title="🎉 Giveaway Ended - Winners Announced!",
description=f"**{matching_giveaway.title}** has been manually ended!",
color=0xFFD700,
timestamp=datetime.now()
)
# Enhanced prize display with game info
if hasattr(matching_giveaway, 'game_info') and matching_giveaway.game_info and matching_giveaway.game_info.get('name'):
if hasattr(matching_giveaway, 'game_url') and matching_giveaway.game_url:
prize_text = f"**[{matching_giveaway.game_info['name']}]({matching_giveaway.game_url})**"
else:
prize_text = f"**{matching_giveaway.game_info['name']}**"
else:
if hasattr(matching_giveaway, 'game_url') and matching_giveaway.game_url:
prize_text = f"**[{matching_giveaway.prize}]({matching_giveaway.game_url})**"
else:
prize_text = f"**{matching_giveaway.prize}**"
winner_embed.add_field(name="🎁 Prize", value=prize_text, inline=True)
winner_embed.add_field(name="🎮 Platform", value=f"**{matching_giveaway.platform}**", inline=True)
winner_embed.add_field(name="👥 Total Participants", value=f"**{len(matching_giveaway.participants)}**", inline=True)
# List winners
winner_list = []
for i, winner in enumerate(winners, 1):
winner_list.append(f"🏆 **#{i}** {winner.mention}")
winner_embed.add_field(name="🎊 Winners", value="\n".join(winner_list), inline=False)
# Add sponsor info if available
if hasattr(matching_giveaway, 'sponsor') and matching_giveaway.sponsor:
winner_embed.add_field(name="💝 Sponsored by", value=f"**{matching_giveaway.sponsor}**", inline=False)
# Add manual end notice
end_type = "🔧 Manually ended" if not is_expired else "⏰ Expired (manually processed)"
winner_embed.add_field(name="📋 Status", value=f"{end_type} by {ctx.author.mention}", inline=False)
winner_embed.add_field(name="📧 Next Steps",
value="Winners have been sent a DM with prize claim instructions!",
inline=False)
# Set game image if available
if hasattr(matching_giveaway, 'game_info') and matching_giveaway.game_info and matching_giveaway.game_info.get('image_url'):
winner_embed.set_image(url=matching_giveaway.game_info['image_url'])
winner_embed.set_thumbnail(url="https://cdn.discordapp.com/emojis/1028701098145587302.png")
else:
winner_embed.set_thumbnail(url="https://cdn.discordapp.com/emojis/1028701098145587302.png")
winner_embed.set_footer(text="Congratulations to all winners! 🎉")
await ctx.send(embed=winner_embed)
# Process winners with enhanced DM
for i, winner in enumerate(winners):
try:
if i < len(matching_giveaway.winner_uuids):
winner_uuid = matching_giveaway.winner_uuids[i]
assign_winner_to_uuid(winner_uuid, winner.id)
# Enhanced winner DM
dm_embed = discord.Embed(
title="🎉 Congratulations! You Won!",
description=f"You are a winner in the **{matching_giveaway.title}** giveaway!",
color=0xFFD700,
timestamp=datetime.now()
)
dm_embed.add_field(name="🎁 Prize", value=prize_text, inline=True)
dm_embed.add_field(name="🎮 Platform", value=f"**{matching_giveaway.platform}**", inline=True)
dm_embed.add_field(name="🏆 Position", value=f"Winner #{i+1}", inline=True)
dm_embed.add_field(name="📋 Prize Claim Instructions",
value="Please contact the server administrators to claim your prize. "
"Make sure to mention this giveaway and your winner position!",
inline=False)
if hasattr(matching_giveaway, 'sponsor') and matching_giveaway.sponsor:
dm_embed.add_field(name="💝 Sponsored by", value=f"**{matching_giveaway.sponsor}**", inline=False)
dm_embed.set_footer(text=f"Server: {ctx.guild.name} • Giveaway ID: {matching_id[:8]}...")
try:
await winner.send(embed=dm_embed)
logger.info(f"Sent winner DM to {winner.name} for giveaway {matching_id[:8]}")
except discord.Forbidden:
logger.warning(f"Could not send DM to winner {winner.name}")
# Notify in channel that DM failed
await ctx.send(f"⚠️ Could not send DM to {winner.mention}. Please contact them manually!")
except Exception as e:
logger.error(f"Error processing winner {winner.name}: {e}")
# Mark giveaway as completed and remove from memory
matching_giveaway.complete_giveaway()
if source == "memory" and matching_id in giveaways:
del giveaways[matching_id]
logger.info(f"Manually ended giveaway {matching_id[:8]} by {ctx.author.id}, {len(winners)} winners selected")
except Exception as e:
logger.error(f"Error ending giveaway: {e}")
await ctx.send(f"❌ Error ending giveaway: {str(e)}")
@client.hybrid_command()
async def expiredgiveaways(ctx):
"""List all expired giveaways that haven't been processed yet (Only available for admins)"""
guild_id = ctx.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 view expired giveaways.")
return
expired_giveaways = []
# Check memory giveaways
for giv_id, giveaway in giveaways.items():
if giveaway.guild_id == guild_id and giveaway.is_finished():
expired_giveaways.append((giv_id, giveaway, "memory"))
# Check database giveaways
try:
active_processes = get_active_processes(process_type="giveaway", guild_id=guild_id)
for process in active_processes:
process_uuid = str(process["uuid"])
# Skip if already in memory
if process_uuid in giveaways:
continue
# Check if expired
if process["end_time"] <= datetime.now():
try:
# Create minimal giveaway object for display
class MinimalGiveaway:
def __init__(self, data, end_time, uuid):
self.title = data.get("title", "Unknown Giveaway")
self.prize = data.get("prize", "Unknown Prize")
self.platform = data.get("platform", "Unknown")
self.num_winners = data.get("num_winners", 1)
self.end_time = end_time
self.process_uuid = uuid
self.participants_count = len(data.get("participants", []))
temp_giveaway = MinimalGiveaway(process["data"], process["end_time"], process["uuid"])
expired_giveaways.append((process_uuid, temp_giveaway, "database"))
except Exception as e:
logger.error(f"Error processing expired giveaway {process_uuid}: {e}")
except Exception as e:
logger.error(f"Error checking database for expired giveaways: {e}")
if not expired_giveaways:
embed = discord.Embed(
title="✅ No Expired Giveaways",
description="There are currently no expired giveaways that need processing.",
color=0x00ff00
)
await ctx.send(embed=embed)
return
# Create list embed
embed = discord.Embed(
title="⏰ Expired Giveaways",
description=f"Found **{len(expired_giveaways)}** expired giveaway(s) that need processing:",
color=0xff6b6b,
timestamp=datetime.now()
)
for giv_id, giveaway, source in expired_giveaways[:10]: # Limit to 10
# Calculate how long expired
time_since_expired = datetime.now() - giveaway.end_time
days = time_since_expired.days
hours, remainder = divmod(time_since_expired.seconds, 3600)
if days > 0:
expired_for = f"{days}d {hours}h ago"
elif hours > 0:
expired_for = f"{hours}h ago"
else:
minutes = remainder // 60
expired_for = f"{minutes}m ago"
# Source indicator
source_emoji = "🧠" if source == "memory" else "💾"
# Participant count
if hasattr(giveaway, 'participants'):
participant_count = len(giveaway.participants)
else:
participant_count = getattr(giveaway, 'participants_count', 0)
embed.add_field(
name=f"{source_emoji} {giveaway.title}",
value=(
f"**ID:** `{giv_id[:8]}...`\n"
f"**Prize:** {giveaway.prize}\n"
f"**Platform:** {giveaway.platform}\n"
f"**Winners:** {giveaway.num_winners}\n"
f"**Participants:** {participant_count}\n"
f"**Expired:** {expired_for}"
),
inline=True
)
if len(expired_giveaways) > 10:
embed.add_field(
name="📋 Additional Info",
value=f"... and {len(expired_giveaways) - 10} more expired giveaways",
inline=False
)
embed.add_field(
name="🔧 How to Process",
value="Use `/endgiveaway <id>` to manually end and pick winners for any expired giveaway.",
inline=False
)
embed.set_footer(text="💾 = Database | 🧠 = Memory | Use /endgiveaway <id> to process")
await ctx.send(embed=embed)
@client.hybrid_command() @client.hybrid_command()
async def listgiveaways(ctx): async def listgiveaways(ctx):
"""List all active giveaways in this server (Only available for admins)""" """List all active giveaways in this server (Only available for admins)"""
@@ -3612,9 +3268,7 @@ async def modhelp(ctx):
"`/processes <action> [type]` - Manage active processes\n" "`/processes <action> [type]` - Manage active processes\n"
"`/startgiveaway` - Create server giveaways with Steam/Epic integration\n" "`/startgiveaway` - Create server giveaways with Steam/Epic integration\n"
"`/editgiveaway <id> <field> <value>` - Edit active giveaways (auto-updates post)\n" "`/editgiveaway <id> <field> <value>` - Edit active giveaways (auto-updates post)\n"
"`/endgiveaway <id> [force]` - Manually end giveaway and pick winners\n"
"`/listgiveaways` - List all active giveaways (memory + database)\n" "`/listgiveaways` - List all active giveaways (memory + database)\n"
"`/expiredgiveaways` - Show expired giveaways that need processing\n"
"`/loadgiveaway <id>` - Load specific giveaway from database\n" "`/loadgiveaway <id>` - Load specific giveaway from database\n"
"`/loadallgiveaways` - Load all giveaways from database\n" "`/loadallgiveaways` - Load all giveaways from database\n"
"`/updategiveawaymessage <id>` - Manually refresh giveaway post\n" "`/updategiveawaymessage <id>` - Manually refresh giveaway post\n"