[Python] I'm trying to convert my discord bot commands into app commands so they can be used...

Discussão em 'Python' iniciado por Stack, Setembro 4, 2025.

  1. Stack

    Stack Membro Participativo

    Here is the code


    import os
    import sys
    import threading
    import time
    import asyncio
    import discord
    from discord import app_commands
    import requests
    from discord.ext import commands
    from flask import Flask, render_template_string, request, redirect, url_for, session

    ADMIN_KEY = "imnotgivingyouthekeysilly"

    # === Discord Bot Setup ===
    intents = discord.Intents.default()
    intents.guilds = True
    intents.message_content = True
    owner = "sl.ip"
    co_owner = "lcjunior1220"

    bot = commands.Bot(command_prefix="/", intents=intents)
    tree = app_commands.CommandTree(bot)

    # === Flask App Setup ===
    app = Flask(__name__)
    app.secret_key = os.environ.get("FLASK_SECRET_KEY", "supersecret")

    HTML_TEMPLATE = """
    <!DOCTYPE html>
    <html>
    <head>
    <title>Bot Dashboard</title>
    <style>
    body { font-family: Arial, sans-serif; background: #1e1e2f; color: #fff; padding: 20px; }
    h1 { color: #50fa7b; }
    select, input[type=text] { padding: 6px; border-radius: 5px; border: none; margin: 5px 0; }
    input[type=submit] { background: #50fa7b; border: none; padding: 8px 12px; border-radius: 5px; color: #000; cursor: pointer; }
    .server { background: #282a36; padding: 10px; margin-bottom: 15px; border-radius: 10px; }
    .logout { margin-top: 20px; }
    .presence-button {
    display: inline-block;
    margin-top: 10px;
    background-color: #7289da;
    color: white;
    padding: 10px 18px;
    border-radius: 8px;
    text-decoration: none;
    font-weight: bold;
    transition: background-color 0.3s ease;
    }
    .presence-button:hover {
    background-color: #5b6eae;
    }
    </style>
    </head>
    <body>
    <h1> Bot Dashboard</h1>
    <p>Status: <b style="color:lime;">Online</b></p>
    <p>Connected to {{ guilds|length }} {{ 'server' if guilds|length == 1 else 'servers' }}</p>

    <!-- Presence Button -->
    <a href="https://dsc.gg/StealAExperience" target="_blank" rel="noopener" class="presence-button">
    Join Our Server
    </a>

    {% for g in guilds %}
    <div class="server">
    <h3>{{ g.name }}</h3>
    <form action="/send" method="post">
    <input type="hidden" name="guild_id" value="{{ g.id }}">
    <label for="channel">Channel:</label>
    <select name="channel_id">
    {% for c in g.text_channels %}
    <option value="{{ c.id }}">{{ c.name }}</option>
    {% endfor %}
    </select>
    <br>
    <label for="message">Message:</label>
    <input type="text" name="message" placeholder="Enter your message" required>
    <br>
    <input type="submit" value="Send">
    </form>
    </div>
    {% endfor %}
    <div class="logout">
    <a href="/logout" style="color: #ff5555;">Logout</a>
    </div>
    </body>
    </html>
    """

    # === Admin Auth Decorator ===
    def admin_required(f):
    def wrapped(*args, **kwargs):
    if session.get("admin") != True:
    return redirect(url_for("admin_login"))
    return f(*args, **kwargs)
    wrapped.__name__ = f.__name__
    return wrapped

    # === Flask Routes ===
    @app.route("/status")
    def status():
    return "OK", 200

    @app.route("/activity")
    def activity():
    return redirect(url_for("admin_login"))

    @app.route("/login", methods=["GET", "POST"])
    def admin_login():
    if session.get("admin") == True:
    return redirect(url_for("dashboard"))

    if request.method == "POST":
    key = request.form.get("key")
    if key == ADMIN_KEY:
    session["admin"] = True
    return redirect(url_for("dashboard"))
    else:
    return '''
    <h3 style="color: red; font-family: Arial, sans-serif;">Incorrect key.</h3>
    <a href="/login" style="font-family: Arial, sans-serif; color: #50fa7b;">Try again</a>
    '''

    return '''
    <!DOCTYPE html>
    <html>
    <head>
    <title>Admin Login</title>
    <style>
    body {
    background: #121212;
    color: #eee;
    font-family: Arial, sans-serif;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    }
    .login-container {
    background: #282a36;
    padding: 40px 50px;
    border-radius: 12px;
    box-shadow: 0 0 15px #50fa7b;
    text-align: center;
    width: 320px;
    }
    h2 {
    margin-bottom: 25px;
    color: #50fa7b;
    }
    input[type=password] {
    width: 100%;
    padding: 12px;
    margin-bottom: 20px;
    border: none;
    border-radius: 6px;
    font-size: 16px;
    background: #44475a;
    color: #f8f8f2;
    }
    input[type=password]::placeholder {
    color: #bd93f9;
    }
    button {
    background: #50fa7b;
    border: none;
    color: #000;
    padding: 12px 0;
    width: 100%;
    font-size: 16px;
    font-weight: bold;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.3s ease;
    }
    button:hover {
    background: #44d366;
    }
    a {
    display: inline-block;
    margin-top: 15px;
    color: #50fa7b;
    text-decoration: none;
    font-size: 14px;
    }
    a:hover {
    text-decoration: underline;
    }
    </style>
    </head>
    <body>
    <div class="login-container">
    <h2>Admin Login</h2>
    <form method="POST">
    <input type="password" name="key" placeholder="Enter admin key" required>
    <button type="submit">Login</button>
    </form>
    </div>
    </body>
    </html>
    '''

    @app.route("/logout")
    def admin_logout():
    session.clear()
    return redirect(url_for("admin_login"))

    # Dashboard at root /
    @app.route("/", methods=["GET"])
    @admin_required
    def dashboard():
    if not bot_ready:
    return "<h3>Bot is not ready yet, please try again in a moment.</h3>"
    return render_template_string(HTML_TEMPLATE, guilds=cached_guilds)

    # Redirect /activity to /
    @app.route("/activity")
    def activity_redirect():
    return redirect(url_for("dashboard"))

    @app.route("/send", methods=["POST"])
    @admin_required
    def send_message():
    guild_id = int(request.form["guild_id"])
    channel_id = int(request.form["channel_id"])
    message = request.form["message"]

    guild = discord.utils.get(bot.guilds, id=guild_id)
    if guild:
    channel = discord.utils.get(guild.text_channels, id=channel_id)
    if channel:
    try:
    bot.loop.create_task(channel.send(message))
    except Exception as e:
    print(f"Failed to send message: {e}")

    return redirect(url_for("dashboard"))

    # === Globals for caching and ready state ===
    cached_guilds = []
    bot_ready = False

    # === Background task to update cached guilds every 20 seconds ===
    async def update_guild_cache():
    global cached_guilds
    while True:
    await bot.tree.sync()
    cached_guilds = list(bot.guilds)
    print(f"[Cache Update] Cached {len(cached_guilds)} guilds at {time.strftime('%X')}")
    await asyncio.sleep(20)

    # === Bot Events ===
    @bot.event
    async def on_ready():
    global bot_ready
    bot_ready = True
    await bot.tree.sync()
    print(f"Logged in as {bot.user}")

    if len(bot.guilds) == 1:
    await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=bot.guilds[0].name))
    else:
    await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=f"{len(bot.guilds)} servers"))

    # Start the cache updater task
    bot.loop.create_task(update_guild_cache())

    # === Guild Commands === (had to remove some commands just to post this)
    @bot.tree.command(name="pfp", description="Get a pfp from someone's spook.bio profile.")
    async def pfp(interaction: discord.Interaction, username: str = "phis"):
    url = f"https://spook.bio/u/{username}/pfp.jpg"
    response = requests.get(url)
    if response.status_code == 200:
    await interaction.response.send_message(url, ephemeral=False)
    print("Fetched data successfully!")
    else:
    await interaction.response.send_message(f":x: {response.status_code} Not Found :x:", ephemeral=True)
    print(f"Error fetching data: {response.status_code}")

    # === App Commands === (had to remove some commands just to post this)
    @tree.command(name="pfp", description="Get a pfp from someone's spook.bio profile.")




    # === Flask Runner in Thread ===
    def run_flask():
    port = int(os.environ.get("PORT", 5000))
    print(f"Starting Flask on port {port}")
    app.run(host="0.0.0.0", port=port)

    # === Run Bot + Flask Webserver ===
    if __name__ == "__main__":
    threading.Thread(target=run_flask).start()
    bot.run(os.environ.get("DISCORD_BOT_TOKEN"))


    I have tried adding app_commands using the "tree" variable

    tree = app_commands.CommandTree(bot)

    but it returns this error whenever it runs.

    raise ClientException('This client already has an associated command tree.') discord.errors.ClientException: This client already has an associated command tree.

    If you can figure out how to make this use an app commands I would be happy!

    Continue reading...

Compartilhe esta Página