Migration de Kuby vers disnake

This commit is contained in:
Mathis 2026-05-06 17:07:09 +02:00
parent dc6e235f27
commit c8c579eefe
36 changed files with 1205 additions and 1253 deletions

View file

@ -7,9 +7,8 @@ import asyncio
from datetime import datetime
from typing import Dict, Any, List
import discord
from discord.ext import commands
from discord import app_commands
import disnake
from disnake.ext import commands
BACKUPS_ROOT = "data/security_backups" # dossier de sortie des sauvegardes
@ -46,10 +45,10 @@ def estimate_duration_seconds(
return int(meta_cost + msg_cost + base_overhead)
def serialize_overwrites(channel: discord.abc.GuildChannel) -> List[Dict[str, Any]]:
def serialize_overwrites(channel: disnake.abc.GuildChannel) -> List[Dict[str, Any]]:
serialized: List[Dict[str, Any]] = []
for target, perms in channel.overwrites.items():
target_type = "role" if isinstance(target, discord.Role) else "member"
target_type = "role" if isinstance(target, disnake.Role) else "member"
serialized.append({
"target_type": target_type,
"target_id": target.id,
@ -64,20 +63,17 @@ class Backup(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
backup_group = app_commands.Group(name="backup", description="Outils de sauvegarde du serveur")
@commands.slash_command(name="backup", description="Outils de sauvegarde du serveur")
async def backup_group(self, interaction: disnake.ApplicationCommandInteraction):
pass
@backup_group.command(name="create", description="Créer une sauvegarde du serveur")
@app_commands.describe(
save_messages="Inclure l'export des messages",
privacy_notice="Afficher un avertissement public si messages sauvegardés",
message_limit_per_channel="Nombre max de messages à exporter par salon (0 = tous)"
)
@backup_group.sub_command(name="create", description="Créer une sauvegarde du serveur")
async def backup_create(
self,
interaction: discord.Interaction,
save_messages: bool = True,
privacy_notice: bool = True,
message_limit_per_channel: int = 10000
interaction: disnake.ApplicationCommandInteraction,
save_messages: bool = commands.Param(True, description="Inclure l'export des messages"),
privacy_notice: bool = commands.Param(True, description="Afficher un avertissement public si messages sauvegardés"),
message_limit_per_channel: int = commands.Param(10000, description="Nombre max de messages à exporter par salon (0 = tous)")
):
guild = interaction.guild
assert guild is not None, "Cette commande doit être utilisée dans un serveur."
@ -93,20 +89,20 @@ class Backup(commands.Cog):
)
return
# Déferre l'interaction
await interaction.response.defer(ephemeral=True, thinking=True)
# Deferre l'interaction
await interaction.response.defer(ephemeral=True)
# Avertissement de confidentialité
if privacy_notice and save_messages:
try:
await interaction.channel.send(
embed=discord.Embed(
embed=disnake.Embed(
title="📢 Information de confidentialité (transparence)",
description=(
"Une **sauvegarde du serveur** est en cours et **inclus les messages**.\n"
"Vous êtes dans l'obligation de prévenir les membres."
),
color=discord.Color.orange()
color=disnake.Color.orange()
)
)
except Exception:
@ -132,14 +128,14 @@ class Backup(commands.Cog):
message_limit_per_channel if message_limit_per_channel else 100000
)
prog_embed = discord.Embed(
prog_embed = disnake.Embed(
title="🗄️ Sauvegarde en cours",
description=(
f"**Serveur :** {guild.name} (`{guild.id}`)\n"
f"**Estimation :** ~{estimation_s} secondes\n"
f"**Options** : messages={'oui' if save_messages else 'non'} • limite/chan={message_limit_per_channel or 'tous'}"
),
color=discord.Color.blurple()
color=disnake.Color.blurple()
)
prog_embed.add_field(name="Progression", value=progress_bar(0.0), inline=False)
progress_msg = await interaction.followup.send(embed=prog_embed, ephemeral=False)
@ -173,11 +169,11 @@ class Backup(commands.Cog):
chans_dump=[]
for ch in guild.channels:
base={"id":ch.id,"name":ch.name,"type":str(ch.type),"position":ch.position,"category_id":ch.category.id if getattr(ch,"category",None) else None,"overwrites":serialize_overwrites(ch)}
if isinstance(ch,discord.TextChannel):
if isinstance(ch,disnake.TextChannel):
base.update({"topic":ch.topic,"nsfw":ch.nsfw,"slowmode_delay":ch.slowmode_delay,"default_auto_archive_duration":ch.default_auto_archive_duration})
elif isinstance(ch,discord.VoiceChannel):
elif isinstance(ch,disnake.VoiceChannel):
base.update({"bitrate":ch.bitrate,"user_limit":ch.user_limit,"rtc_region":str(ch.rtc_region) if ch.rtc_region else None})
elif isinstance(ch,discord.ForumChannel):
elif isinstance(ch,disnake.ForumChannel):
base.update({"nsfw":ch.nsfw,"default_auto_archive_duration":ch.default_auto_archive_duration})
chans_dump.append(base)
with open(os.path.join(base_dir,"channels.json"),"w",encoding="utf-8") as f:
@ -208,7 +204,7 @@ class Backup(commands.Cog):
data={"id":msg.id,"channel_id":msg.channel.id,"author_id":msg.author.id,"author_bot":msg.author.bot,"created_at":msg.created_at.isoformat(),"content":msg.content,"attachments":[a.url for a in msg.attachments],"embeds":[e.to_dict() for e in msg.embeds],"reference":{"message_id":getattr(msg.reference,"message_id",None),"channel_id":getattr(msg.reference,"channel_id",None)} if msg.reference else None}
f.write(json.dumps(data,ensure_ascii=False)+"\n")
count+=1
except discord.Forbidden: pass
except disnake.Forbidden: pass
except Exception: pass
exported_total+=count
done+=per_chan_weight
@ -226,7 +222,7 @@ class Backup(commands.Cog):
rel=os.path.relpath(full,base_dir)
zf.write(full,rel)
except Exception as exc:
prog_embed.color=discord.Color.red()
prog_embed.color=disnake.Color.red()
prog_embed.set_field_at(0,name="Progression",value=progress_bar(1.0),inline=False)
prog_embed.set_footer(text=f"Erreur lors de la création du ZIP : {exc}")
await progress_msg.edit(embed=prog_embed)
@ -234,15 +230,15 @@ class Backup(commands.Cog):
return
# Finalisation
prog_embed.color=discord.Color.green()
prog_embed.color=disnake.Color.green()
prog_embed.set_field_at(0,name="Progression",value=progress_bar(1.0),inline=False)
prog_embed.add_field(name="Archive",value=f"`{zip_path}`",inline=False)
prog_embed.set_footer(text="Sauvegarde terminée ✅")
await progress_msg.edit(embed=prog_embed)
await interaction.followup.send("🎉 Sauvegarde terminée. Un message de progression avec le chemin de larchive a été publié.", ephemeral=True)
@backup_group.command(name="list", description="Lister les archives de sauvegarde disponibles")
async def backup_list(self, interaction: discord.Interaction):
@backup_group.sub_command(name="list", description="Lister les archives de sauvegarde disponibles")
async def backup_list(self, interaction: disnake.ApplicationCommandInteraction):
guild = interaction.guild
assert guild is not None, "Cette commande doit être utilisée dans un serveur."
@ -256,7 +252,7 @@ class Backup(commands.Cog):
)
return
await interaction.response.defer(ephemeral=True, thinking=True)
await interaction.response.defer(ephemeral=True)
ensure_dir(BACKUPS_ROOT)
files = [f for f in os.listdir(BACKUPS_ROOT) if f.endswith(".zip")]
files.sort(reverse=True)
@ -266,7 +262,7 @@ class Backup(commands.Cog):
return
desc="\n".join(f"• `{name}`" for name in files[:20])
embed=discord.Embed(title="📦 Archives disponibles",description=desc,color=discord.Color.blurple())
embed=disnake.Embed(title="📦 Archives disponibles",description=desc,color=disnake.Color.blurple())
if len(files)>20:
embed.set_footer(text=f"... et {len(files)-20} de plus")
await interaction.followup.send(embed=embed,ephemeral=True)