Merge branch 'master' of git.slipstreamm.dev:slipstream/discordbot

This commit is contained in:
Slipstreamm 2025-06-14 05:00:13 -06:00
commit 15f8c91baf

View File

@ -9,16 +9,35 @@ import json
import os
import aiofiles # Import aiofiles
import aiofiles.os
import discord_oauth
GIVEAWAY_DATA_FILE = "data/giveaways.json"
DATA_DIR = "data"
# --- Helper Functions ---
async def get_nitro_status_oauth(user: discord.User | discord.Member) -> bool | None:
"""Return True if user has Nitro according to OAuth info, False if not, None if unknown."""
token = await discord_oauth.get_token(str(user.id))
if not token:
return None
try:
user_info = await discord_oauth.get_user_info(token)
except Exception:
return None
return user_info.get("premium_type", 0) in (1, 2)
# --- Additional Helper Functions ---
async def is_user_nitro_like(
user: discord.User | discord.Member, bot: commands.Bot = None
) -> bool:
"""Checks if a user has an animated avatar or a banner, indicating Nitro."""
"""Heuristically check if a user has Nitro, falling back to OAuth if available."""
nitro_oauth = await get_nitro_status_oauth(user)
if nitro_oauth is not None:
return nitro_oauth
# Fetch the full user object to get banner information
if bot:
try:
@ -59,10 +78,23 @@ class GiveawayEnterButton(ui.Button["GiveawayEnterView"]):
await interaction.message.edit(view=self.view)
return
if giveaway["is_nitro_giveaway"]:
if not await is_user_nitro_like(interaction.user, bot=self.cog.bot):
if giveaway["is_nitro_giveaway"] or giveaway.get("exclude_nitro_users"):
nitro_status = await get_nitro_status_oauth(interaction.user)
if nitro_status is None:
await interaction.response.send_message(
"This is a Nitro-exclusive giveaway. You don't appear to have Nitro (animated avatar or banner).",
"Please authenticate with /auth so I can verify your Nitro status before entering.",
ephemeral=True,
)
return
if giveaway["is_nitro_giveaway"] and not nitro_status:
await interaction.response.send_message(
"This is a Nitro-exclusive giveaway, and your account does not appear to have Nitro.",
ephemeral=True,
)
return
if giveaway.get("exclude_nitro_users") and nitro_status:
await interaction.response.send_message(
"Nitro users are excluded from this giveaway.",
ephemeral=True,
)
return
@ -150,11 +182,16 @@ class GiveawayRerollButton(ui.Button["GiveawayEndView"]):
except discord.NotFound:
continue # Skip if user cannot be found
if user and not user.bot:
# Apply Nitro check again if it was a nitro giveaway
if giveaway_data.get(
"is_nitro_giveaway", False
) and not is_user_nitro_like(user):
continue
if giveaway_data.get("is_nitro_giveaway") or giveaway_data.get(
"exclude_nitro_users"
):
nitro_status = await get_nitro_status_oauth(user)
if nitro_status is None:
continue
if giveaway_data.get("is_nitro_giveaway") and not nitro_status:
continue
if giveaway_data.get("exclude_nitro_users") and nitro_status:
continue
entrants_users.append(user)
if not entrants_users:
@ -228,6 +265,7 @@ class GiveawaysCog(commands.Cog, name="Giveaways"):
# "creator_id": int,
# "participants": set(), # Store user_ids. Stored as list in JSON.
# "is_nitro_giveaway": bool,
# "exclude_nitro_users": bool,
# "ended": bool
# }
# Ensure data directory exists before loading/saving
@ -325,6 +363,7 @@ class GiveawaysCog(commands.Cog, name="Giveaways"):
)
gw_data["participants"] = set(gw_data.get("participants", []))
gw_data.setdefault("is_nitro_giveaway", False)
gw_data.setdefault("exclude_nitro_users", False)
gw_data.setdefault(
"ended", gw_data["end_time"] <= now
) # Set ended if time has passed
@ -432,7 +471,8 @@ class GiveawaysCog(commands.Cog, name="Giveaways"):
prize="What is the prize?",
duration="How long should the giveaway last? (e.g., 10m, 1h, 2d, 1w)",
winners="How many winners? (default: 1)",
nitro_giveaway="Is this a Nitro-only giveaway? (checks for animated avatar/banner)",
nitro_giveaway="Is this a Nitro-only giveaway? (OAuth verification)",
exclude_nitro="Exclude Nitro users from entering?",
)
@app_commands.checks.has_permissions(manage_guild=True)
async def create_giveaway_slash(
@ -442,6 +482,7 @@ class GiveawaysCog(commands.Cog, name="Giveaways"):
duration: str,
winners: int = 1,
nitro_giveaway: bool = False,
exclude_nitro: bool = False,
):
"""Slash command to create a giveaway using buttons."""
parsed_duration = self.parse_duration(duration)
@ -469,6 +510,8 @@ class GiveawaysCog(commands.Cog, name="Giveaways"):
)
if nitro_giveaway:
embed.description += "\n*This is a Nitro-exclusive giveaway!*"
if exclude_nitro:
embed.description += "\n*Users with Nitro are excluded from entering.*"
embed.set_footer(
text=f"Giveaway started by {interaction.user.display_name}. Entries: 0"
) # Initial entry count
@ -488,6 +531,7 @@ class GiveawaysCog(commands.Cog, name="Giveaways"):
"creator_id": interaction.user.id,
"participants": set(),
"is_nitro_giveaway": nitro_giveaway,
"exclude_nitro_users": exclude_nitro,
"ended": False,
}
self.active_giveaways.append(giveaway_data)
@ -559,10 +603,16 @@ class GiveawaysCog(commands.Cog, name="Giveaways"):
if user_to_check.bot:
continue
if giveaway_data["is_nitro_giveaway"] and not is_user_nitro_like(
user_to_check
if giveaway_data["is_nitro_giveaway"] or giveaway_data.get(
"exclude_nitro_users"
):
continue # Skip non-nitro users for nitro giveaways
nitro_status = await get_nitro_status_oauth(user_to_check)
if nitro_status is None:
continue
if giveaway_data["is_nitro_giveaway"] and not nitro_status:
continue
if giveaway_data.get("exclude_nitro_users") and nitro_status:
continue
entrants_users.append(user_to_check)
winners_list = []
@ -685,10 +735,16 @@ class GiveawaysCog(commands.Cog, name="Giveaways"):
user_id
) or await self.bot.fetch_user(user_id)
if user and not user.bot:
if giveaway_info.get(
"is_nitro_giveaway", False
) and not is_user_nitro_like(user):
continue
if giveaway_info.get("is_nitro_giveaway") or giveaway_info.get(
"exclude_nitro_users"
):
nitro_status = await get_nitro_status_oauth(user)
if nitro_status is None:
continue
if giveaway_info.get("is_nitro_giveaway") and not nitro_status:
continue
if giveaway_info.get("exclude_nitro_users") and nitro_status:
continue
entrants.add(user)
if not entrants:
await interaction.followup.send(
@ -704,8 +760,23 @@ class GiveawaysCog(commands.Cog, name="Giveaways"):
reaction_found = True
async for user in reaction.users():
if not user.bot:
# For manual reaction roll, we might not know if it was nitro_giveaway
# Consider adding a parameter to manual_roll for this if needed
if giveaway_info and (
giveaway_info.get("is_nitro_giveaway")
or giveaway_info.get("exclude_nitro_users")
):
nitro_status = await get_nitro_status_oauth(user)
if nitro_status is None:
continue
if (
giveaway_info.get("is_nitro_giveaway")
and not nitro_status
):
continue
if (
giveaway_info.get("exclude_nitro_users")
and nitro_status
):
continue
entrants.add(user)
break
if not reaction_found: