133 lines
4.3 KiB
Python
133 lines
4.3 KiB
Python
# rhymes.py
|
|
import json
|
|
import random
|
|
from datetime import datetime, timedelta
|
|
from pathlib import Path
|
|
from typing import Any, Dict, Tuple
|
|
import discord
|
|
from discord import Interaction, app_commands
|
|
|
|
import database
|
|
|
|
RHYMES_FILE = "resources/rhymes.json"
|
|
RHYME_LOG_FILE = "data/rhyme_log.csv"
|
|
|
|
loaded_rhymes = {}
|
|
|
|
|
|
def ensure_log_file() -> None:
|
|
Path(RHYME_LOG_FILE).parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
if not Path(RHYME_LOG_FILE).exists():
|
|
with open(RHYME_LOG_FILE, "w", encoding="utf-8") as f:
|
|
f.write("timestamp,last_word,rhyme_triggered\n")
|
|
|
|
|
|
def load_rhymes() -> Tuple[bool, str]:
|
|
global loaded_rhymes
|
|
try:
|
|
with open(RHYMES_FILE, "r", encoding="utf-8") as f:
|
|
loaded_rhymes = json.load(f)
|
|
return True, f'Loaded rhymes file "{RHYMES_FILE}"'
|
|
except FileNotFoundError:
|
|
return False, f'No rhymes file found at "{RHYMES_FILE}"'
|
|
except json.JSONDecodeError as e:
|
|
return False, f'Invalid JSON in "{RHYMES_FILE}": {e}'
|
|
|
|
|
|
def log_rhyme(last_word: str, rhyme_triggered: str) -> None:
|
|
timestamp = datetime.now().isoformat()
|
|
|
|
with open(RHYME_LOG_FILE, "a", encoding="utf-8") as f:
|
|
safe_rhyme = rhyme_triggered.replace(",", ";")
|
|
f.write(f"{timestamp},{last_word},{safe_rhyme}\n")
|
|
|
|
|
|
def get_last_word(text: str) -> str:
|
|
truncated = text
|
|
while True:
|
|
if len(truncated) < 2 or truncated[-1].isnumeric():
|
|
return ""
|
|
if truncated[-1].isalpha() and truncated[-2].isalpha():
|
|
break
|
|
truncated = truncated[:-1]
|
|
truncated = truncated.split(" ")[-1]
|
|
return truncated if truncated.isalpha() else ""
|
|
|
|
|
|
def find_rhyme(word: str) -> str:
|
|
global loaded_rhymes
|
|
|
|
for rhyme in loaded_rhymes:
|
|
if word in rhyme["blacklist"]:
|
|
return ""
|
|
if word.endswith(tuple(rhyme["keys"])):
|
|
log_rhyme(word, rhyme["sound"])
|
|
return random.choice(rhyme["rhymes"])
|
|
return ""
|
|
|
|
|
|
async def get_guild_name(guildId, client) -> str:
|
|
guild = await client.fetch_guild(guildId)
|
|
return "[Server={0}]".format(guild.name)
|
|
|
|
|
|
async def handle_rhyme_logic(message, client) -> bool:
|
|
message_content = message.content.lower()
|
|
last_word = get_last_word(message_content)
|
|
|
|
if message.author != client.user and message.guild and last_word:
|
|
rhyme = find_rhyme(last_word)
|
|
guild_id = str(message.guild.id)
|
|
|
|
if rhyme:
|
|
guild_state = database.get_guild_state(guild_id)
|
|
cooldown_ratio = guild_state["cooldown_ratio"]
|
|
|
|
if cooldown_ratio >= 0:
|
|
cooldown_dt = datetime.fromisoformat(guild_state["cooldown_until"])
|
|
now_dt = datetime.now()
|
|
|
|
if now_dt >= cooldown_dt:
|
|
self_control = guild_state["self_control"]
|
|
|
|
if random.random() < self_control:
|
|
database.rhyme_damage_self_control(guild_id)
|
|
return False
|
|
|
|
database.rhyme_reset_cooldown(guild_id, cooldown_ratio)
|
|
|
|
await message.channel.send(rhyme)
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
async def handle_message(message, client) -> bool:
|
|
database.ensure_db()
|
|
ensure_log_file()
|
|
|
|
return await handle_rhyme_logic(message, client)
|
|
|
|
|
|
def setup_rhymes_commands(client: discord.Client, tree: discord.app_commands.CommandTree) -> None:
|
|
@tree.command(
|
|
name="config",
|
|
description="Permet de configurer à quel point le Père Fouras est relou"
|
|
)
|
|
@app_commands.default_permissions(manage_guild=True)
|
|
@app_commands.checks.has_permissions(manage_guild=True)
|
|
@app_commands.describe(ratio="ratio de cooldown (0 = )")
|
|
async def config(
|
|
interaction: discord.Interaction,
|
|
ratio: float
|
|
):
|
|
guild_id: str = str(interaction.guild_id)
|
|
guild_state = database.get_guild_state(guild_id)
|
|
database.rhyme_configure_cooldown_ratio(guild_id, ratio)
|
|
msg = f"Le ratio de cooldown passe de {guild_state["cooldown_ratio"]:.2f} à {ratio:.2f} pour le serveur {interaction.guild.name}"
|
|
if ratio < 0:
|
|
await interaction.response.send_message(f"{msg}\nLes \"poil au\" sont désormais désactivés.", ephemeral=True)
|
|
else:
|
|
await interaction.response.send_message(f"{msg}\nLes \"poil au\" ont désormais un cooldown entre 0 et {int(180*ratio)} minutes.", ephemeral=True)
|