Ajout: Syncronisation automatique des pp discord des agent O.K sur le site via Kuby

This commit is contained in:
Mathis 2026-06-18 22:12:01 +02:00
parent 886bfa4b1e
commit 5a9e9b52d6
2 changed files with 180 additions and 1 deletions

5
.gitignore vendored
View file

@ -36,4 +36,7 @@ logs/
.vscode/ .vscode/
.idea/ .idea/
.DS_Store .DS_Store
.roo/ .roo/
.continue/mcpServers/new-mcp-server.yaml
.continue/mcpServers/new-mcp-server-1.yaml
.gitignore

176
commandes/team_json.py Normal file
View file

@ -0,0 +1,176 @@
# -*- coding: utf-8 -*-
"""
Team JSON Generator
===================
Ce module parcourt les membres d'un serveur Discord, filtre ceux qui possèdent
un ou plusieurs rôles spécifiés, télécharge leurs avatars et génère un fichier
JSON compatible avec le site de production.
Le JSON attendu ressemble à:
[
{
"id": "123456789012345678",
"name": "Nom affiché",
"role": "Nom du rôle filtré",
"avatar": "123456789012345678.png",
"bio": "",
"stats": [],
"skills": [],
"social": {"discord":"","twitter":"",...}
},
...
]
Le champ ``avatar`` correspond au nom de fichier stocké dans ``website/avatars/``.
"""
import os
import json
import aiohttp
from pathlib import Path
from typing import List
import disnake
from disnake.ext import commands, tasks
# ----------------------------------------------------------------------
# Configuration variables d'environnement (dans le .env du projet)
# ----------------------------------------------------------------------
TARGET_GUILD_ID = os.getenv("TARGET_GUILD_ID") # ID du serveur contenant l'équipe
# Liste d'IDs de rôles séparés par des virgules (ex. "123,456,789")
TEAM_ROLE_IDS = os.getenv("TEAM_ROLE_IDS", "").split(",") if os.getenv("TEAM_ROLE_IDS") else []
# Dossiers où seront stockés les avatars et le JSON final
AVATAR_ROOT = Path(__file__).parents[2] / "website" / "avatars"
AVATAR_ROOT.mkdir(parents=True, exist_ok=True)
JSON_OUTPUT = Path(__file__).parents[2] / "website" / "team.json"
# ----------------------------------------------------------------------
class TeamJSON(commands.Cog):
"""Cog responsable de la génération du JSON d'équipe et du téléchargement des avatars."""
def __init__(self, bot: commands.Bot):
self.bot = bot
# Démarre la tâche quotidienne (synchronisation 24h/24)
self.sync_daily.start()
# ------------------------------------------------------------------
@tasks.loop(hours=24)
async def sync_daily(self):
"""Tâche planifiée exécutée chaque jour (cron)."""
await self._generate_team(trigger="cron")
@sync_daily.before_loop
async def before_sync(self):
await self.bot.wait_until_ready()
# ------------------------------------------------------------------
async def _download_avatar(self, session: aiohttp.ClientSession, member: disnake.Member) -> str:
"""Télécharge l'avatar du *member* et le sauvegarde dans ``AVATAR_ROOT``.
Retourne le nom de fichier (ex. ``"123456789.png"``)."""
avatar_url = str(member.display_avatar.url)
filename = f"{member.id}.png"
dest_path = AVATAR_ROOT / filename
try:
async with session.get(avatar_url) as resp:
if resp.status == 200:
dest_path.write_bytes(await resp.read())
else:
self.bot.logger.warning(
f"[TeamJSON] Avatar download failed for {member.id} HTTP {resp.status}"
)
except Exception as exc:
self.bot.logger.error(f"[TeamJSON] Exception while downloading avatar {member.id}: {exc}")
return filename
# ------------------------------------------------------------------
async def _generate_team(self, *, trigger: str = "manual") -> None:
"""Construit le JSON de l'équipe et télécharge les avatars.
Le JSON produit suit exactement le format attendu par le site de production.
Les champs ``stats``, ``skills`` et ``social`` sont laissés vides car ils ne
sont pas disponibles via l'API bot.
"""
if not TARGET_GUILD_ID:
self.bot.logger.error("[TeamJSON] TARGET_GUILD_ID non défini arrêt du générateur.")
return
if not TEAM_ROLE_IDS:
self.bot.logger.error("[TeamJSON] TEAM_ROLE_IDS non défini arrêt du générateur.")
return
# Récupération de la guilde
guild = self.bot.get_guild(int(TARGET_GUILD_ID))
if not guild:
try:
guild = await self.bot.fetch_guild(int(TARGET_GUILD_ID))
except Exception as exc:
self.bot.logger.error(f"[TeamJSON] Impossible de récupérer la guilde {TARGET_GUILD_ID}: {exc}")
return
# Convertir les IDs de rôle en entiers pour la comparaison
role_ids = {int(r) for r in TEAM_ROLE_IDS if r.strip()}
members_data: List[dict] = []
async with aiohttp.ClientSession() as session:
async for member in guild.fetch_members(limit=None):
if member.bot:
continue
# Intersection entre les rôles du membre et les rôles ciblés
member_role_ids = {r.id for r in member.roles}
intersect = member_role_ids.intersection(role_ids)
if not intersect:
continue # le membre ne possède aucun des rôles recherchés
# On prend le premier rôle correspondant comme "role" dans le JSON
role_name = next((r.name for r in member.roles if r.id in intersect), "")
avatar_file = await self._download_avatar(session, member)
entry = {
"id": str(member.id),
"name": member.display_name,
"role": role_name,
"avatar": avatar_file,
"bio": "", # non récupérable via l'API bot
"stats": [],
"skills": [],
"social": {
"discord": "",
"twitter": "",
"instagram": "",
"youtube": "",
"tiktok": "",
"github": "",
},
}
members_data.append(entry)
# Écriture du JSON final
try:
JSON_OUTPUT.parent.mkdir(parents=True, exist_ok=True)
JSON_OUTPUT.write_text(
json.dumps(members_data, indent=2, ensure_ascii=False),
encoding="utf-8",
)
self.bot.logger.info(
f"[TeamJSON] JSON généré ({len(members_data)} membres) → {JSON_OUTPUT}"
)
except Exception as exc:
self.bot.logger.error(f"[TeamJSON] Échec de l'écriture du JSON : {exc}")
# ------------------------------------------------------------------
@commands.slash_command(
name="generate_team_json",
description="Génère le JSON de l'équipe (admin only)"
)
@commands.has_permissions(administrator=True)
async def generate_team_json(self, inter: disnake.ApplicationCommandInteraction):
"""Commande manuelle pour (re)générer le JSON et les avatars."""
await inter.response.defer(ephemeral=True)
await self._generate_team(trigger="manual")
await inter.edit_original_response(
content="✅ JSON de l'équipe généré et avatars synchronisés."
)
# ----------------------------------------------------------------------
def setup(bot: commands.Bot):
bot.add_cog(TeamJSON(bot))