File size: 6,636 Bytes
732ca45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# cogs/admin.py
import discord
from discord import app_commands
from discord.ext import commands
import os
import time
import aiohttp
import urllib.parse
import logging
import asyncio

from database.db import db
from utils.image_prep import prepare_database_image

logger = logging.getLogger(__name__)

class AdminCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    # ==========================================================
    # πŸ‘€ ADD SINGLE CHARACTER
    # ==========================================================
    @app_commands.command(name="add_character", description="[ADMIN] Add a character or alternate variant")
    @app_commands.default_permissions(administrator=True)
    @app_commands.describe(
        name="Character Name (e.g. Raiden Shogun)",
        series="Anime/Game Series",
        rarity="Rarity (Common, Rare, Epic, Legendary, Mythic)",
        element="Element type",
        atk="Base Attack Stat",
        defense="Base Defense Stat",
        image="Upload the RAW character image",
        variant="Optional: Create an alt version (e.g. Summer)"
    )
    @app_commands.choices(rarity=[
        app_commands.Choice(name="Common", value="C"),
        app_commands.Choice(name="Rare", value="R"),
        app_commands.Choice(name="Epic", value="SR"),
        app_commands.Choice(name="Legendary", value="SSR"),
        app_commands.Choice(name="Mythic", value="UR")
    ])
    async def add_character(self, interaction: discord.Interaction, name: str, series: str, rarity: app_commands.Choice[str], element: str, atk: int, defense: int, image: discord.Attachment, variant: str = None):
        await interaction.response.defer(ephemeral=True)

        base_name = name.strip()
        final_name = f"{base_name} ({variant.strip()})" if variant else base_name

        async with db.pool.acquire() as conn:
            exists = await conn.fetchval("SELECT 1 FROM characters WHERE name ILIKE $1", final_name)
            if exists:
                if variant:
                    return await interaction.followup.send(f"❌ Error: The variant **{final_name}** already exists!", ephemeral=True)
                else:
                    count = await conn.fetchval("SELECT COUNT(*) FROM characters WHERE name ILIKE $1", f"{base_name} (Alt %)")
                    alt_num = count + 1 if count else 1
                    final_name = f"{base_name} (Alt {alt_num})"
                    while await conn.fetchval("SELECT 1 FROM characters WHERE name ILIKE $1", final_name):
                        alt_num += 1
                        final_name = f"{base_name} (Alt {alt_num})"

        supabase_url = os.getenv("SUPABASE_URL")
        supabase_key = os.getenv("SUPABASE_KEY")
        bucket_name = os.getenv("SUPABASE_BUCKET", "gacha-images")

        if not supabase_url or not supabase_key:
            return await interaction.followup.send("❌ Error: Supabase keys are missing from your .env file.", ephemeral=True)

        raw_image_bytes = await image.read()
        
        try:
            optimized_bytes = await asyncio.to_thread(prepare_database_image, raw_image_bytes)
            
            safe_filename = f"single_{int(time.time())}_{final_name.replace(' ', '_').lower()}.webp"
            upload_url = f"{supabase_url}/storage/v1/object/{bucket_name}/{safe_filename}"
            
            headers = {
                "Authorization": f"Bearer {supabase_key}",
                "apikey": supabase_key,
                "Content-Type": "image/webp"
            }

            async with aiohttp.ClientSession() as session:
                async with session.post(upload_url, headers=headers, data=optimized_bytes) as resp:
                    if resp.status not in [200, 201]:
                        error_json = await resp.json()
                        logger.error(f"Supabase upload failed: {error_json}")
                        return await interaction.followup.send("❌ Supabase API rejected the upload.", ephemeral=True)
                    
                    public_url = f"{supabase_url}/storage/v1/object/public/{bucket_name}/{safe_filename}"

            async with db.pool.acquire() as conn:
                await conn.execute(
                    """
                    INSERT INTO characters (name, series, rarity, element, atk, def, image_url) 
                    VALUES ($1, $2, $3, $4, $5, $6, $7)
                    """,
                    final_name, series, rarity.value, element, atk, defense, public_url
                )

            embed = discord.Embed(title="βœ… Character Added Safely!", color=discord.Color.green())
            embed.add_field(name="Name", value=final_name, inline=True)
            embed.add_field(name="Series", value=series, inline=True)
            embed.add_field(name="Rarity", value=rarity.name, inline=True)
            embed.set_thumbnail(url=public_url)
            
            await interaction.followup.send(embed=embed)

        except Exception as e:
            logger.error(f"Add Character Error: {e}", exc_info=True)
            await interaction.followup.send("❌ An unexpected error occurred.", ephemeral=True)

    @app_commands.command(name="add_frame", description="[ADMIN] Upload a card frame directly to your bot's assets")
    @app_commands.default_permissions(administrator=True)
    @app_commands.choices(rarity=[
        app_commands.Choice(name="Common", value="C"),
        app_commands.Choice(name="Rare", value="R"),
        app_commands.Choice(name="Epic", value="SR"),
        app_commands.Choice(name="Legendary", value="SSR"),
        app_commands.Choice(name="Mythic", value="UR")
    ])
    async def add_frame(self, interaction: discord.Interaction, rarity: app_commands.Choice[str], frame_image: discord.Attachment):
        await interaction.response.defer(ephemeral=True)
        if not frame_image.filename.lower().endswith('.png'):
            return await interaction.followup.send("❌ Error: Frame images MUST be `.png` files.", ephemeral=True)

        base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        frames_dir = os.path.join(base_dir, "assets", "frames")
        os.makedirs(frames_dir, exist_ok=True)
        save_path = os.path.join(frames_dir, f"{rarity.value}.png")
        
        try:
            await frame_image.save(save_path)
            await interaction.followup.send(f"βœ… The **{rarity.name}** frame has been uploaded!")
        except Exception as e:
            await interaction.followup.send("❌ Failed to save the frame.", ephemeral=True)

async def setup(bot):
    await bot.add_cog(AdminCog(bot))