DiscordPY
Intégrer la vérification des votes dans un bot Discord (Python)
Dans cet exemple, nous créons une commande /vote qui :
Envoie un message avec :
un bouton « Voter sur DiscordTop » → ouvre la page de vote,
un bouton « Vérifier mon vote » → appelle l’API DiscordTop.
Si le vote est validé par l’API, vous appliquez vos propres récompenses :
donner un rôle,
ajouter de l’XP,
débloquer un salon, etc.
1. Pré-requis
Python 3.10+
Un bot Discord fonctionnel (token)
Un token API DiscordTop (
api_token) associé à votre serveur
Packages à installer :
pip install -U discord.py aiohttp python-dotenv2. Configuration du projet
Créez un fichier .env à la racine de votre projet :
DISCORD_TOKEN=VOTRE_TOKEN_BOT
DISCORD_GUILD_ID=ID_DU_SERVEUR_DE_TEST
DTOP_API_TOKEN=VOTRE_CLE_API_DISCORDTOP
DTOP_GUILD_ID=ID_DU_SERVEUR_SUR_DTOP
DTOP_GUILD_IDcorrespond à l’ID du serveur tel qu’il apparaît sur DiscordTop (en général, c’est le même que l’ID Discord).
3. Bot Python complet : commande /vote + boutons + appel API DTOP
/vote + boutons + appel API DTOPCréez un fichier bot.py avec le contenu suivant :
import os
import asyncio
from dotenv import load_dotenv
import aiohttp
import discord
from discord import app_commands
from discord.ext import commands
load_dotenv()
DISCORD_TOKEN = os.getenv("DISCORD_TOKEN")
DISCORD_GUILD_ID = int(os.getenv("DISCORD_GUILD_ID"))
DTOP_API_TOKEN = os.getenv("DTOP_API_TOKEN")
DTOP_GUILD_ID = os.getenv("DTOP_GUILD_ID") # ID du serveur sur DiscordTop
# Exemple : rôle récompense (à remplacer par un ID réel si vous utilisez cette partie)
REWARD_ROLE_ID = 0 # ex: 123456789012345678
intents = discord.Intents.default()
intents.members = True # nécessaire si vous attribuez des rôles
bot = commands.Bot(command_prefix="!", intents=intents)
def get_discordtop_vote_url() -> str:
"""Construit l'URL de vote DiscordTop pour votre serveur."""
return f"https://discordtop.net/guild/{DTOP_GUILD_ID}/vote"
async def check_vote_on_discordtop(user_id: int):
"""
Appelle l’API DiscordTop pour vérifier si l’utilisateur a voté.
GET https://api.discordtop.net/v7/check-vote?discord_id=...
Retourne (status, body_json | None).
"""
url = "https://api.discordtop.net/v7/check-vote"
params = {
"discord_id": str(user_id),
# "locale": "fr", # décommentez pour forcer la langue si besoin
}
async with aiohttp.ClientSession() as session:
async with session.get(
url,
params=params,
headers={"Authorization": f"Bearer {DTOP_API_TOKEN}","Accept-Language": "fr-FR"},
) as resp:
status = resp.status
try:
data = await resp.json()
except Exception:
data = None
return status, data
class VoteView(discord.ui.View):
"""Vue avec les boutons de vote."""
def __init__(self):
super().__init__(timeout=60 * 5) # 5 minutes
# Bouton lien vers la page de vote DTOP
self.add_item(
discord.ui.Button(
label="Voter sur DiscordTop",
style=discord.ButtonStyle.link,
url=get_discordtop_vote_url(),
)
)
@discord.ui.button(
label="Vérifier mon vote",
style=discord.ButtonStyle.primary,
custom_id="dtop-check-vote",
)
async def check_vote_button(
self,
interaction: discord.Interaction,
button: discord.ui.Button,
):
"""Callback du bouton 'Vérifier mon vote'."""
await interaction.response.defer(ephemeral=True)
user_id = interaction.user.id
try:
status, body = await check_vote_on_discordtop(user_id)
except Exception as exc:
print("Erreur lors de l'appel à l'API DiscordTop :", exc)
return await interaction.edit_original_response(
content="❌ Impossible de contacter l’API DiscordTop pour le moment."
)
# Gestion des principaux statuts HTTP
if status == 200:
if not isinstance(body, dict):
return await interaction.edit_original_response(
content="❌ Réponse inattendue de l’API DiscordTop."
)
# Selon la structure de la réponse, vous pouvez vérifier un champ comme `has_voted`
has_voted = bool(body.get("has_voted", False))
if not has_voted:
return await interaction.edit_original_response(
content=(
"❌ Vous n'avez pas encore voté sur DiscordTop !\n"
"Cliquez sur « Voter sur DiscordTop », votez, puis réessayez."
)
)
# 👉 C'est ici que vous appliquez VOS récompenses :
# - ajout de rôle
# - ajout d'XP
# - accès à un salon, etc.
if REWARD_ROLE_ID:
try:
member = interaction.user
if not isinstance(member, discord.Member):
member = await interaction.guild.fetch_member(user_id)
role = interaction.guild.get_role(REWARD_ROLE_ID)
if role:
await member.add_roles(
role, reason="Récompense de vote DiscordTop"
)
except Exception as exc:
print("Erreur lors de l'attribution du rôle :", exc)
return await interaction.edit_original_response(
content="✅ Vote validé sur DiscordTop ! Vos récompenses ont été appliquées."
)
if status == 404:
return await interaction.edit_original_response(
content=(
"Aucun vote récent n'a été trouvé pour votre compte.\n"
"Assurez-vous d'avoir voté sur la bonne page et réessayez dans quelques instants."
)
)
if status == 429:
retry_after = 60
if isinstance(body, dict):
retry_after = int(body.get("retry_after", retry_after))
return await interaction.edit_original_response(
content=(
f"🚫 Vous effectuez trop de vérifications de vote.\n"
f"Merci de patienter **{retry_after} secondes** avant de réessayer."
)
)
if status in (401, 403):
return await interaction.edit_original_response(
content=(
"⚠️ La configuration de l'API DiscordTop semble incorrecte "
"(clé invalide ou serveur non autorisé). Contactez un administrateur."
)
)
# Autres erreurs (400, 500, etc.)
print("Erreur API DiscordTop :", status, body)
return await interaction.edit_original_response(
content=(
"❌ Une erreur est survenue lors de la vérification du vote.\n"
"Merci de réessayer plus tard."
)
)
@bot.event
async def on_ready():
print(f"✅ Connecté en tant que {bot.user} (ID: {bot.user.id})")
# Synchronisation des commandes slash sur une guilde précise (plus rapide pour les tests)
guild = discord.Object(id=DISCORD_GUILD_ID)
bot.tree.copy_global_to(guild=guild)
await bot.tree.sync(guild=guild)
print(f"🧵 Commandes synchronisées sur la guilde {DISCORD_GUILD_ID}")
@bot.tree.command(
name="vote",
description="Lien de vote DiscordTop + vérification du vote.",
)
async def vote_command(interaction: discord.Interaction):
"""Commande /vote : envoie les boutons."""
view = VoteView()
await interaction.response.send_message(
(
"Merci de soutenir le serveur en votant sur DiscordTop !\n"
"Cliquez sur **Voter sur DiscordTop**, puis utilisez **Vérifier mon vote** "
"pour recevoir vos récompenses."
),
view=view,
ephemeral=True,
)
def main():
bot.run(DISCORD_TOKEN)
if __name__ == "__main__":
asyncio.run(main())4. Où appliquer vos propres récompenses ?
Le bloc à modifier est ici :
if status == 200:
# 👉 C'est ici que vous appliquez VOS récompenses :
# - ajout de rôle
# - ajout d'XP
# - accès à un salon, etc.À cet endroit, vous pouvez :
incrémenter un champ XP dans votre base de données,
donner un rôle temporaire ou permanent,
ouvrir l’accès à un salon réservé aux voteurs,
logger l’événement dans un salon staff, etc.
5. Résumé du flux côté bot
L’utilisateur exécute la commande
/vote.Le bot envoie un message avec :
un bouton lien → page de vote DiscordTop,
un bouton « Vérifier mon vote ».
L’utilisateur clique sur « Vérifier mon vote ».
Le bot appelle :
GET https://api.discordtop.net/v7/check-vote?discord_id=USER_IDSelon la réponse :
✅ 200 → vote valide → vos récompenses sont appliquées
❌ 404 → pas de vote récent
🚫 429 → trop de requêtes, respectez
retry_after🔐 401/403 → problème de configuration API
💥 500 → erreur côté DTOP (à réessayer plus tard)
Last updated