myircbot/plugins/alias.py
2025-05-29 22:58:53 +02:00

196 lines
6.8 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import json
# Ajusta la ruta donde quieras guardar los aliases
ALIAS_FILE = os.path.expanduser("/var/lib/bot/aliases.json")
os.makedirs(os.path.dirname(ALIAS_FILE), exist_ok=True)
class AliasPlugin:
"""
Gestor de alias con soporte para variables posicionales ($1, $2, $*).
Cada alias se convierte en un comando independiente que el usuario
puede invocar con .<alias>.
"""
def __init__(self, send_raw, bot=None):
# Esta función se llama al instanciar el plugin en load_plugins().
self.send_raw = send_raw
self.bot = bot
self.aliases = self.load_aliases()
def load_aliases(self):
"""Carga los alias desde un archivo JSON."""
if os.path.exists(ALIAS_FILE):
try:
with open(ALIAS_FILE, "r", encoding="utf-8") as f:
return json.load(f)
except json.JSONDecodeError:
return {}
return {}
def save_aliases(self):
"""Guarda los alias en un archivo JSON."""
with open(ALIAS_FILE, "w", encoding="utf-8") as f:
json.dump(self.aliases, f, indent=4, ensure_ascii=False)
def add_alias(self, name, command):
"""Añade un alias, lo guarda y recarga los plugins."""
if name in self.aliases:
return f" El alias '{name}' ya existe. Usa `.alias del {name}` para eliminarlo primero."
# Eliminar comillas dobles extra
if command.startswith('"') and command.endswith('"'):
command = command[1:-1] # Elimina la primera y última comilla
self.aliases[name] = command
self.save_aliases()
# Recargar plugins tras añadir un alias
if self.bot:
self.bot.load_plugins()
return f" Alias '{name}' creado para ejecutar: `{command}`"
def remove_alias(self, name):
"""Elimina un alias por su nombre."""
if name not in self.aliases:
return f" El alias '{name}' no existe."
del self.aliases[name]
self.save_aliases()
return f" Alias '{name}' eliminado."
def list_aliases(self):
"""Retorna una lista de todos los alias registrados."""
if not self.aliases:
return " No hay alias registrados."
lines = [f"`{name}` → `{cmd}`" for name, cmd in self.aliases.items()]
return " **Alias disponibles:**\n" + "\n".join(lines)
def execute_alias(self, sender, alias, *args):
if alias not in self.aliases:
return f" El alias '{alias}' no está registrado."
command = self.aliases[alias] # Ej: "echo Hola $1"
# Reemplazo de variables especiales
command = command.replace("$nick", sender) # Reemplaza $nick por el nombre del usuario
# Reemplazo de $1, $2, ..., $*
for i, arg in enumerate(args, start=1):
command = command.replace(f"${i}", arg)
command = command.replace("$*", " ".join(args[1:]))
# Ejecutar el comando procesado como si fuera un plugin del bot
tokens = command.split()
if not tokens:
return " Error: Alias vacío tras el procesamiento."
cmd = tokens[0] # Primer token es el comando (Ej: "echo")
cmd_args = tokens[1:] # El resto son argumentos
# Verificar si el comando existe en los plugins del bot
if cmd in self.bot.plugins:
plugin_or_func = self.bot.plugins[cmd]
try:
# Si es una función (alias dinámico), la llamamos
if callable(plugin_or_func):
response = plugin_or_func(sender, *cmd_args)
else:
# Si es un objeto plugin con método `.run()`, ejecutamos `.run(...)`
response = plugin_or_func.run(*cmd_args)
return response
except Exception as e:
return f" Error al ejecutar alias '{alias}': {str(e)}"
return f" El comando '{cmd}' no existe."
def get_help(self, alias_name):
"""Devuelve un texto con la ayuda de un alias concreto."""
if alias_name in self.aliases:
command = self.aliases[alias_name]
min_args = max(command.count("$1"), 1) # Asume al menos 1
return f"({alias_name} <al menos {min_args} argumento/s>) -- Alias for `{command}`."
return f" No hay ayuda disponible para '{alias_name}'."
def get_dynamic_commands(self):
"""
Retorna un dict con { alias: function } para registrarlos como comandos.
Cada alias quedará accesible con .<alias>.
"""
commands = {}
for alias_name in self.aliases:
# Creamos una función que llame a self.execute_alias
def alias_func(sender, *args, _alias=alias_name):
return self.execute_alias(sender, _alias, *args)
commands[alias_name] = alias_func
return commands
def run(self, sender, *args):
"""
Maneja el uso de `.alias <acción>`:
- .alias add <nombre> <comando>
- .alias del <nombre>
- .alias list
- .alias help <alias>
"""
if not args:
return " Uso: `.alias list` | `.alias add <nombre> <cmd>` | `.alias del <nombre>`"
action = args[0].lower()
if action == "add" and len(args) > 2:
name = args[1]
command = " ".join(args[2:])
return self.add_alias(name, command)
elif action == "del" and len(args) > 1:
return self.remove_alias(args[1])
elif action == "list":
return self.list_aliases()
elif action == "help" and len(args) > 1:
return self.get_help(args[1])
else:
return " Comando no reconocido. Usa `.alias list`."
#
# Función 'run' global para cuando el bot llama a 'alias' como plugin.
#
def run(sender, *args):
"""
Función que se invoca cuando el usuario hace .alias ...
Recuerda que en el bot, normalmente le pasamos: plugin.run(sender, *args)
"""
# Como no necesitamos send_raw aquí, podemos instanciar con None
alias_plugin = AliasPlugin(None)
# Simplemente delegamos la lógica de los comandos a alias_plugin.run
# Como no sabemos si lo primero que llega es 'sender' o no, ajusta según tu bot:
if len(args) == 0:
return alias_plugin.run("", *args)
# Asumiendo que 'sender' es el primer argumento:
sender = args[0]
more_args = args[1:]
return alias_plugin.run(sender, *more_args)
def help():
"""Texto de ayuda para .help alias"""
return (
"Usa `.alias add <nombre> <comando>` para crear un alias.\n"
"Usa `.alias del <nombre>` para eliminarlo.\n"
"Usa `.alias list` para ver todos los alias.\n"
"Usa `.alias help <nombre>` para ver la definición de un alias.\n"
"Los alias pueden usar `$1`, `$2`, `$*` para insertar argumentos."
)