792 lines
25 KiB
Python
792 lines
25 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""menu_idd.py - Menu de botones inline para el bot IDD (Telegram).
|
||
|
||
Capa nueva sobre pi_bot.py: los botones NO duplican logica, disparan los
|
||
mismos comandos de texto llamando a pi_bot.procesar(). Asi las integraciones
|
||
(NAS, router, camaras, TV, Tapo, parental, AiMesh, QoS, limites) siguen
|
||
exactamente igual. Se importa pi_bot de forma perezosa para evitar ciclos.
|
||
"""
|
||
|
||
import json
|
||
import time
|
||
|
||
API = "https://api.telegram.org/bot"
|
||
|
||
# Prefijo de los callback_data del menu: "m:<ruta>"
|
||
PREFIJO = "m:"
|
||
|
||
|
||
def _bot_token():
|
||
import pi_bot
|
||
return pi_bot.TOKEN
|
||
|
||
|
||
def _api(method):
|
||
return f"{API}{_bot_token()}/{method}"
|
||
|
||
|
||
def _log(linea):
|
||
import pi_bot
|
||
try:
|
||
pi_bot.log(f"menu: {linea}")
|
||
except Exception:
|
||
pass
|
||
|
||
|
||
def _txt(codigo, chat_id):
|
||
"""Recupera el estado de la ultima busqueda de pi_bot para este chat."""
|
||
import pi_bot
|
||
try:
|
||
if codigo == "ultimos_titulos":
|
||
estado = pi_bot.ultima_titulos.get(chat_id) or {}
|
||
return estado.get("results") or []
|
||
if codigo == "ultimos_torrents":
|
||
return pi_bot.ultimos_torrents.get(chat_id) or {}
|
||
except Exception:
|
||
return {} if codigo == "ultimos_torrents" else []
|
||
return [] if codigo == "ultimos_torrents" else {}
|
||
|
||
|
||
def _btn(texto, data):
|
||
return {"text": texto, "callback_data": data}
|
||
|
||
|
||
def _mk(filas):
|
||
return {"inline_keyboard": filas}
|
||
|
||
|
||
# ---------------------------------------------------------------- teclados --
|
||
|
||
FILA_VOLVER = [_btn("⬅️ Menú", PREFIJO + "ini")]
|
||
|
||
|
||
def teclado_principal():
|
||
return _mk([
|
||
[
|
||
_btn("🎬 Videoclub", PREFIJO + "cat:videoclub"),
|
||
_btn("📥 NAS/Descargas", PREFIJO + "cat:nas"),
|
||
],
|
||
[
|
||
_btn("📺 TV", PREFIJO + "cat:tv"),
|
||
_btn("👪 Control parental", PREFIJO + "cat:parental"),
|
||
_btn("🏠 Domótica", PREFIJO + "cat:domotica"),
|
||
],
|
||
[
|
||
_btn("🛠️ Sistema", PREFIJO + "cat:sistema"),
|
||
_btn("📚 Ayuda (texto)", PREFIJO + "acc:ayuda"),
|
||
],
|
||
])
|
||
|
||
|
||
def teclado_videoclub(chat_id):
|
||
filas = [
|
||
[
|
||
_btn("🔎 Buscar", PREFIJO + "txt:busca"),
|
||
_btn("🎬 Película", PREFIJO + "txt:pelicula"),
|
||
_btn("📺 Serie", PREFIJO + "txt:serie"),
|
||
],
|
||
[
|
||
_btn("🎭 Por género", PREFIJO + "acc:genero"),
|
||
_btn("🆕 Novedades", PREFIJO + "acc:novedades"),
|
||
],
|
||
]
|
||
titulos = _txt("ultimos_titulos", chat_id)
|
||
if titulos:
|
||
filas.append([
|
||
_btn("🧲 Torrents…", PREFIJO + "sub:torrents"),
|
||
_btn("⬇️ Bajar…", PREFIJO + "sub:bajar"),
|
||
])
|
||
filas.append(FILA_VOLVER)
|
||
return _mk(filas)
|
||
|
||
|
||
def teclado_nas():
|
||
return _mk([
|
||
[
|
||
_btn("📥 Panel descargas", PREFIJO + "acc:descargas"),
|
||
_btn("➕ Añadir enlace", PREFIJO + "txt:descargar"),
|
||
],
|
||
FILA_VOLVER,
|
||
])
|
||
|
||
|
||
def teclado_domotica():
|
||
return _mk([
|
||
[
|
||
_btn("🤖 Aspiradora", PREFIJO + "cat:aspi"),
|
||
_btn("🔌 Termo", PREFIJO + "cat:termo"),
|
||
],
|
||
FILA_VOLVER,
|
||
])
|
||
|
||
|
||
def teclado_aspi():
|
||
return _mk([
|
||
[
|
||
_btn("📊 Estado", PREFIJO + "acc:aspiradora:estado"),
|
||
_btn("🧹 Aspirar", PREFIJO + "acc:aspiradora:start"),
|
||
],
|
||
[
|
||
_btn("⏸️ Pausar", PREFIJO + "acc:aspiradora:pause"),
|
||
_btn("🏠 A la base", PREFIJO + "acc:aspiradora:home"),
|
||
],
|
||
[
|
||
_btn("🗑️ Vaciar", PREFIJO + "acc:aspiradora:vaciar"),
|
||
_btn("📊 Stats", PREFIJO + "acc:aspiradora:stats"),
|
||
],
|
||
[
|
||
_btn("⚡ Potencia…", PREFIJO + "cat:potencia"),
|
||
_btn("🔧 Consumibles", PREFIJO + "acc:aspiradora:consumibles"),
|
||
],
|
||
[_btn("⬅️ Domótica", PREFIJO + "cat:domotica")],
|
||
])
|
||
|
||
|
||
def teclado_potencia():
|
||
return _mk([
|
||
[
|
||
_btn("🔈 Silencioso", PREFIJO + "acc:potencia:0"),
|
||
_btn("🔉 Estándar", PREFIJO + "acc:potencia:1"),
|
||
],
|
||
[
|
||
_btn("🔊 Medio", PREFIJO + "acc:potencia:2"),
|
||
_btn("📢 Fuerte", PREFIJO + "acc:potencia:3"),
|
||
],
|
||
[_btn("⬅️ Aspiradora", PREFIJO + "cat:aspi")],
|
||
])
|
||
|
||
|
||
def teclado_termo():
|
||
return _mk([
|
||
[
|
||
_btn("🔌 ON", PREFIJO + "acc:termo:on"),
|
||
_btn("🔌 OFF", PREFIJO + "acc:termo:off"),
|
||
_btn("📊 Estado", PREFIJO + "acc:termo:estado"),
|
||
],
|
||
[_btn("⬅️ Domótica", PREFIJO + "cat:domotica")],
|
||
])
|
||
|
||
|
||
def teclado_tv():
|
||
return _mk([
|
||
[
|
||
_btn("📺 Mensaje", PREFIJO + "txt:tv"),
|
||
_btn("🚨 Alarma", PREFIJO + "txt:alarma"),
|
||
],
|
||
[_btn("▶️ YouTube", PREFIJO + "txt:youtube")],
|
||
FILA_VOLVER,
|
||
])
|
||
|
||
|
||
def teclado_parental():
|
||
return _mk([
|
||
[
|
||
_btn("🔒 Bloquear tablets", PREFIJO + "acc:tablets:bloquear"),
|
||
_btn("🔓 Desbloquear tablets", PREFIJO + "acc:tablets:desbloquear"),
|
||
],
|
||
[_btn("📋 Listar estado", PREFIJO + "acc:parental_listar")],
|
||
[_btn("📺 Bloquear dispositivo…", PREFIJO + "acc:dispositivos")],
|
||
[
|
||
_btn("🔒 Desactivar…", PREFIJO + "sub:desactivar"),
|
||
_btn("🔓 Activar…", PREFIJO + "sub:activar"),
|
||
],
|
||
[_btn("⏸️ Pausa…", PREFIJO + "sub:pausa")],
|
||
FILA_VOLVER,
|
||
])
|
||
|
||
|
||
def teclado_sistema():
|
||
return _mk([
|
||
[
|
||
_btn("📊 Estado", PREFIJO + "acc:estado"),
|
||
_btn("🌡️ Temperatura", PREFIJO + "acc:temperatura"),
|
||
],
|
||
[
|
||
_btn("📡 Router…", PREFIJO + "sub:router"),
|
||
_btn("🌐 AiMesh", PREFIJO + "acc:aimesh"),
|
||
],
|
||
[
|
||
_btn("⚙️ QoS", PREFIJO + "acc:qos"),
|
||
_btn("🚦 Límites", PREFIJO + "acc:limite"),
|
||
_btn("🛡️ Seguridad", PREFIJO + "acc:seguridad"),
|
||
],
|
||
[
|
||
_btn("📸 Panorama", PREFIJO + "acc:panorama"),
|
||
_btn("🧹 Limpieza", PREFIJO + "acc:limpieza"),
|
||
],
|
||
[_btn("🗑️ Limpiar pantalla", PREFIJO + "acc:limpiar")],
|
||
FILA_VOLVER,
|
||
])
|
||
|
||
|
||
def teclado_router():
|
||
return _mk([
|
||
[
|
||
_btn("📊 Estado", PREFIJO + "acc:router:estado"),
|
||
_btn("📶 Clientes", PREFIJO + "acc:router:clientes"),
|
||
_btn("📡 Wi-Fi", PREFIJO + "acc:router:wifi"),
|
||
],
|
||
[
|
||
_btn("📋 Inventario", PREFIJO + "acc:router:inventario"),
|
||
_btn("👪 Parental", PREFIJO + "acc:router:parental"),
|
||
],
|
||
[
|
||
_btn("🔄 Reiniciar", PREFIJO + "acc:router:reiniciar"),
|
||
_btn("🔁 Reservar IPs", PREFIJO + "acc:router:reservar"),
|
||
],
|
||
[_btn("⬅️ Sistema", PREFIJO + "cat:sistema")],
|
||
])
|
||
|
||
|
||
def teclado_nombres(accion):
|
||
return _mk([
|
||
[_btn("👧 Inés", PREFIJO + f"sub:{accion}:Inés"),
|
||
_btn("👩 Carolina", PREFIJO + f"sub:{accion}:Carolina")],
|
||
[_btn("✏️ Otro…", PREFIJO + f"txt:{accion}")],
|
||
[_btn("⬅️ Control parental", PREFIJO + "cat:parental")],
|
||
])
|
||
|
||
|
||
def teclado_minutos_pausa(nombre):
|
||
return _mk([
|
||
[
|
||
_btn("15 min", PREFIJO + "pausa_min:15"),
|
||
_btn("30 min", PREFIJO + "pausa_min:30"),
|
||
_btn("60 min", PREFIJO + "pausa_min:60"),
|
||
],
|
||
[_btn("✏️ Otro…", PREFIJO + "pausa_min:otro")],
|
||
[_btn("⬅️ Nombres", PREFIJO + "cat:parental")],
|
||
])
|
||
|
||
|
||
# Snapshot de la lista de dispositivos por chat (para toggle por numero).
|
||
menu_dispositivos = {}
|
||
|
||
|
||
def teclado_dispositivos(lista):
|
||
filas = []
|
||
for i, d in enumerate(lista, start=1):
|
||
marca = "🔒" if d["bloqueado"] else "🔓"
|
||
extra = f" {d['ip']}" if d.get("ip") else ""
|
||
filas.append([_btn(f"{i}. {marca} {d['tipo']} {d['nombre'][:28]}{extra}",
|
||
PREFIJO + f"acc:blqdev:{i}")])
|
||
filas.append([_btn("⬅️ Control parental", PREFIJO + "cat:parental")])
|
||
return _mk(filas)
|
||
|
||
|
||
def _mostrar_dispositivos(chat_id, message_id):
|
||
import pi_bot
|
||
try:
|
||
from asus_api_control import listar_dispositivos
|
||
lista = listar_dispositivos()
|
||
except Exception as e:
|
||
_enviar_nuevo(chat_id, f"❌ Error listando dispositivos: {e}", None)
|
||
return
|
||
if not lista:
|
||
_enviar_nuevo(chat_id, "No hay dispositivos en red.", None)
|
||
return
|
||
menu_dispositivos[chat_id] = lista
|
||
_enviar_edit(chat_id, message_id,
|
||
"📺 <b>Bloquear dispositivo</b>\nPulsa el número para "
|
||
"bloquear/desbloquear:",
|
||
teclado_dispositivos(lista))
|
||
|
||
|
||
def teclado_resultados(lista, prefijo):
|
||
filas = []
|
||
for i, item in enumerate(lista[:12], start=1):
|
||
nombre = item.get("name") or item.get("filename") or item.get("title") or item.get("clean") or f"Opción {i}"
|
||
filas.append([_btn(f"{i}. {nombre[:40]}", PREFIJO + f"acc:{prefijo}:{i}")])
|
||
filas.append([_btn("⬅️ Videoclub", PREFIJO + "cat:videoclub")])
|
||
return filas
|
||
|
||
|
||
def teclado_cancelar():
|
||
return _mk([[_btn("❌ Cancelar", PREFIJO + "cancelar")]])
|
||
|
||
|
||
# --------------------------------------------------------------- helpers ---
|
||
|
||
def _enviar_edit(chat_id, message_id, texto, teclado):
|
||
import requests
|
||
try:
|
||
requests.post(_api("editMessageText"), data={
|
||
"chat_id": chat_id,
|
||
"message_id": message_id,
|
||
"text": texto,
|
||
"parse_mode": "HTML",
|
||
"reply_markup": json.dumps(teclado),
|
||
}, timeout=10)
|
||
except Exception as e:
|
||
_log(f"edit error: {e}")
|
||
|
||
|
||
def _enviar_nuevo(chat_id, texto, teclado=None):
|
||
import requests
|
||
data = {
|
||
"chat_id": chat_id,
|
||
"text": texto,
|
||
"parse_mode": "HTML",
|
||
}
|
||
if teclado:
|
||
data["reply_markup"] = json.dumps(teclado)
|
||
try:
|
||
requests.post(_api("sendMessage"), data=data, timeout=10)
|
||
except Exception as e:
|
||
_log(f"send error: {e}")
|
||
|
||
|
||
def _cerrar_menu(chat_id, message_id):
|
||
"""Quita los botones del menu (lo deja cerrado como texto estatico)."""
|
||
import requests
|
||
try:
|
||
requests.post(_api("editMessageReplyMarkup"),
|
||
data={"chat_id": chat_id, "message_id": message_id},
|
||
timeout=10)
|
||
except Exception as e:
|
||
_log(f"cerrar menu error: {e}")
|
||
|
||
|
||
def _disp(chat_id, message_id, comando, categoria=None):
|
||
"""Ejecuta un comando, cierra el menu viejo y devuelve al menu."""
|
||
import pi_bot
|
||
pi_bot.procesar(comando, chat_id)
|
||
_cerrar_menu(chat_id, message_id)
|
||
_reenviar_menu(chat_id, categoria)
|
||
|
||
|
||
def _fin_accion(chat_id, categoria=None):
|
||
"""Tras una accion terminal: deja ver el resultado, limpia toda la
|
||
pantalla y devuelve al menu de la categoria."""
|
||
import time as _time
|
||
import pi_bot
|
||
_time.sleep(4)
|
||
try:
|
||
pi_bot.limpiar_pantalla(chat_id)
|
||
except Exception:
|
||
pass
|
||
_reenviar_menu(chat_id, categoria)
|
||
|
||
|
||
def _reabrir(chat_id, message_id, categoria, comando):
|
||
"""Para consultas (estado, listar): ejecuta, borra los mensajes viejos
|
||
dejando solo el ultimo resultado y muestra de nuevo el menu de la
|
||
categoria (con su tecla de volver operativa)."""
|
||
import pi_bot
|
||
pi_bot.procesar(comando, chat_id)
|
||
try:
|
||
hist = pi_bot.historial_chat.get(chat_id, []) or []
|
||
for mid in hist[:-1]:
|
||
_borrar(chat_id, mid)
|
||
pi_bot.historial_chat[chat_id] = hist[-1:] if hist else []
|
||
ent = pi_bot.entrantes_chat.get(chat_id, []) or []
|
||
for mid in ent:
|
||
_borrar(chat_id, mid)
|
||
pi_bot.entrantes_chat[chat_id] = []
|
||
except Exception:
|
||
pass
|
||
_borrar(chat_id, message_id)
|
||
_reenviar_menu(chat_id, categoria)
|
||
|
||
|
||
# ----------------------------------------------------------------- menu ----
|
||
|
||
def enviar_menu(chat_id):
|
||
_enviar_nuevo(
|
||
chat_id,
|
||
"🧭 <b>Menú IDD</b>\nElige una categoría:",
|
||
teclado_principal(),
|
||
)
|
||
|
||
|
||
def _header(categoria):
|
||
nombres = {
|
||
"videoclub": "🎬 <b>Videoclub</b>",
|
||
"nas": "📥 <b>NAS / Descargas</b>",
|
||
"tv": "📺 <b>TV</b>",
|
||
"parental": "👪 <b>Control parental</b>",
|
||
"domotica": "🏠 <b>Domótica</b>",
|
||
"aspi": "🤖 <b>Aspiradora</b>",
|
||
"potencia": "⚡ <b>Potencia aspiradora</b>",
|
||
"termo": "🔌 <b>Termo</b>",
|
||
"sistema": "🛠️ <b>Sistema</b>",
|
||
"router": "📡 <b>Router ASUS</b>",
|
||
}
|
||
return nombres.get(categoria, "🧭 <b>Menú IDD</b>")
|
||
|
||
|
||
# Ultima categoria visitada por chat: a ella se vuelve tras cada accion.
|
||
menu_cat = {}
|
||
|
||
|
||
def _record_cat(chat_id, categoria):
|
||
menu_cat[chat_id] = categoria
|
||
|
||
|
||
def _reenviar_menu(chat_id, categoria=None):
|
||
"""Envia de nuevo el menu de la categoria (con su volver operativo)."""
|
||
cat = categoria or menu_cat.get(chat_id)
|
||
if not cat:
|
||
_enviar_nuevo(chat_id, "🧭 <b>Menú IDD</b>\nElige una categoría:",
|
||
teclado_principal())
|
||
return
|
||
teclado = _teclado_categoria(chat_id, cat)
|
||
if teclado is None:
|
||
_enviar_nuevo(chat_id, "🧭 <b>Menú IDD</b>\nElige una categoría:",
|
||
teclado_principal())
|
||
return
|
||
_enviar_nuevo(chat_id, _header(cat), teclado)
|
||
|
||
|
||
def volver_al_menu(chat_id, categoria=None):
|
||
"""API para pi_bot: tras un texto libre del menu, devuelve al menu."""
|
||
_reenviar_menu(chat_id, categoria)
|
||
|
||
|
||
def _teclado_categoria(chat_id, categoria):
|
||
teclados = {
|
||
"videoclub": lambda: teclado_videoclub(chat_id),
|
||
"nas": teclado_nas,
|
||
"tv": teclado_tv,
|
||
"parental": teclado_parental,
|
||
"domotica": teclado_domotica,
|
||
"aspi": teclado_aspi,
|
||
"potencia": teclado_potencia,
|
||
"termo": teclado_termo,
|
||
"sistema": teclado_sistema,
|
||
"router": teclado_router,
|
||
}
|
||
fn = teclados.get(categoria)
|
||
return fn() if fn else None
|
||
|
||
|
||
def _abrir_categoria(chat_id, message_id, categoria):
|
||
_record_cat(chat_id, categoria)
|
||
teclado = _teclado_categoria(chat_id, categoria)
|
||
if teclado is None:
|
||
return False
|
||
_enviar_edit(chat_id, message_id, _header(categoria), teclado)
|
||
return True
|
||
|
||
|
||
def procesar_callback(data, chat_id, message_id):
|
||
"""data llega sin el prefijo 'm:'. Gestiona navegacion y acciones."""
|
||
partes = data.split(":")
|
||
ruta = partes[0]
|
||
_log(f"callback {data} chat={chat_id}")
|
||
|
||
if ruta == "ini":
|
||
_enviar_edit(chat_id, message_id, "🧭 <b>Menú IDD</b>\nElige una categoría:", teclado_principal())
|
||
return
|
||
|
||
if ruta == "cat":
|
||
return _abrir_categoria(chat_id, message_id, partes[1])
|
||
|
||
if ruta == "sub":
|
||
# sub:torrents / sub:bajar / sub:router / sub:parental:<acc>
|
||
sub = partes[1]
|
||
if sub in ("router",):
|
||
_record_cat(chat_id, "router")
|
||
_enviar_edit(chat_id, message_id, _header("router"), teclado_router())
|
||
return
|
||
if sub in ("torrents", "bajar"):
|
||
_record_cat(chat_id, "videoclub")
|
||
return _mostrar_resultados(chat_id, message_id, sub)
|
||
if len(partes) == 2 and sub in ("desactivar", "activar", "pausa"):
|
||
_record_cat(chat_id, "parental")
|
||
_enviar_edit(chat_id, message_id,
|
||
f"¿Sobre qué dispositivo? ({sub})",
|
||
teclado_nombres(sub))
|
||
return
|
||
# sub:<accion>:<nombre> -> accion parental con nombre directo
|
||
if len(partes) >= 3 and sub in ("desactivar", "activar", "pausa"):
|
||
return _ejecutar_parental(chat_id, message_id, sub, partes[2])
|
||
_log(f"sub desconocida: {data}")
|
||
return
|
||
|
||
if ruta == "txt":
|
||
# pide un dato por teclado: lo captura el siguiente mensaje
|
||
accion = partes[1]
|
||
_guardar_pendiente(chat_id, accion)
|
||
CAT_TXT = {
|
||
"busca": "videoclub", "pelicula": "videoclub", "serie": "videoclub",
|
||
"tv": "tv", "alarma": "tv", "youtube": "tv",
|
||
"descargar": "nas",
|
||
"desactivar": "parental", "activar": "parental",
|
||
}
|
||
_record_cat(chat_id, CAT_TXT.get(accion, "sistema"))
|
||
preguntas = {
|
||
"busca": "🔎 ¿Qué busco? Escribe el nombre.",
|
||
"pelicula": "🎬 ¿Qué película busco?",
|
||
"serie": "📺 ¿Qué serie busco?",
|
||
"tv": "📺 ¿Qué mensaje envío a la tele?",
|
||
"alarma": "🚨 ¿Qué mensaje de alarma lanzo?",
|
||
"youtube": "▶️ Pega la URL de YouTube.",
|
||
"descargar": "🧲 Pega el enlace magnet o URL a descargar.",
|
||
"desactivar": "🔒 ¿A quién bloqueo? Escribe el nombre.",
|
||
"activar": "🔓 ¿A quién desbloqueo? Escribe el nombre.",
|
||
}
|
||
_enviar_nuevo(chat_id, preguntas.get(accion, "Escribe el dato:"),
|
||
teclado_cancelar())
|
||
_cerrar_menu(chat_id, message_id)
|
||
return
|
||
|
||
if ruta == "pausa_min":
|
||
nombre = _get_pausa_nombre(chat_id)
|
||
if not nombre:
|
||
_enviar_nuevo(chat_id, "Empieza de nuevo: /menu", teclado_cancelar())
|
||
_cerrar_menu(chat_id, message_id)
|
||
return
|
||
if partes[1] == "otro":
|
||
_guardar_pendiente(chat_id, "pausa_minutos")
|
||
_enviar_nuevo(chat_id, "⏱️ ¿Cuántos minutos? (1-1440)", teclado_cancelar())
|
||
_cerrar_menu(chat_id, message_id)
|
||
return
|
||
minutos = partes[1]
|
||
import pi_bot
|
||
pi_bot.procesar(f"parental pausa {nombre} {minutos}", chat_id)
|
||
_cerrar_menu(chat_id, message_id)
|
||
_fin_accion(chat_id, "parental")
|
||
return
|
||
|
||
if ruta == "acc":
|
||
return _ejecutar_accion(chat_id, message_id, partes[1:])
|
||
|
||
if ruta == "cancelar":
|
||
_limpiar_pendiente(chat_id)
|
||
_borrar(chat_id, message_id)
|
||
return
|
||
|
||
|
||
def _mostrar_resultados(chat_id, message_id, tipo):
|
||
titulos = _txt("ultimos_titulos", chat_id)
|
||
if tipo == "torrents":
|
||
if titulos:
|
||
_enviar_edit(chat_id, message_id,
|
||
"🧲 Elige el título para ver sus torrents:",
|
||
teclado_resultados(titulos, "torrents"))
|
||
else:
|
||
_enviar_nuevo(chat_id, "Primero haz una <b>/busca</b> o usa <code>/torrents <n></code>.", None)
|
||
return
|
||
torrents = _txt("ultimos_torrents", chat_id)
|
||
if torrents:
|
||
_enviar_edit(chat_id, message_id,
|
||
f"⬇️ Elige torrent de «{torrents.get('titulo')}»:",
|
||
teclado_resultados(torrents.get("torrents", []), "bajar"))
|
||
else:
|
||
_enviar_nuevo(chat_id, "Primero consulta <code>/torrents <n></code> de un título.", None)
|
||
|
||
|
||
def _ejecutar_parental(chat_id, message_id, accion, nombre):
|
||
if accion == "pausa":
|
||
_record_cat(chat_id, "parental")
|
||
_set_pausa_nombre(chat_id, nombre)
|
||
_enviar_edit(chat_id, message_id,
|
||
f"⏸️ Pausa para <b>{nombre}</b>. ¿Cuántos minutos?",
|
||
teclado_minutos_pausa(nombre))
|
||
return
|
||
comando = f"parental {'desactivar' if accion == 'desactivar' else 'activar'} {nombre}"
|
||
import pi_bot
|
||
pi_bot.procesar(comando, chat_id)
|
||
_cerrar_menu(chat_id, message_id)
|
||
_fin_accion(chat_id, "parental")
|
||
|
||
|
||
def _ejecutar_accion(chat_id, message_id, partes):
|
||
import pi_bot
|
||
accion = partes[0]
|
||
sub = partes[1] if len(partes) > 1 else ""
|
||
directos = {
|
||
"ayuda": "ayuda",
|
||
"genero": "genero",
|
||
"novedades": "novedades",
|
||
"descargas": "descargas",
|
||
"estado": "estado",
|
||
"temperatura": "temperatura",
|
||
"panorama": "panorama",
|
||
"limpieza": "limpieza",
|
||
"limpiar": "limpiar",
|
||
"aimesh": "aiMesh estado",
|
||
"qos": "qos estado",
|
||
"limite": "limite listar",
|
||
"seguridad": "seguridad estado",
|
||
}
|
||
if accion == "parental_listar":
|
||
_reabrir(chat_id, message_id, "parental", "parental listar")
|
||
return
|
||
CAT_ACC = {
|
||
"ayuda": None, "genero": "videoclub", "novedades": "videoclub",
|
||
"descargas": "nas", "estado": "sistema", "temperatura": "sistema",
|
||
"panorama": "sistema", "limpieza": "sistema", "limpiar": "sistema",
|
||
"aimesh": "sistema", "qos": "sistema", "limite": "sistema",
|
||
"seguridad": "sistema",
|
||
}
|
||
if accion in directos:
|
||
_disp(chat_id, message_id, directos[accion], CAT_ACC.get(accion))
|
||
return
|
||
if accion == "termo":
|
||
if sub == "estado":
|
||
_reabrir(chat_id, message_id, "termo", "termo estado")
|
||
elif sub in ("on", "off"):
|
||
pi_bot.procesar(f"termo {sub}", chat_id)
|
||
_cerrar_menu(chat_id, message_id)
|
||
_fin_accion(chat_id, "termo")
|
||
return
|
||
if accion == "aspiradora":
|
||
if sub in ("estado", "stats", "consumibles"):
|
||
_reabrir(chat_id, message_id, "aspi", f"aspiradora {sub}")
|
||
elif sub in ("start", "stop", "home", "pause", "locate", "vaciar"):
|
||
pi_bot.procesar(f"aspiradora {sub}", chat_id)
|
||
_cerrar_menu(chat_id, message_id)
|
||
_fin_accion(chat_id, "aspi")
|
||
return
|
||
if accion == "potencia":
|
||
if sub.isdigit() and int(sub) in (0, 1, 2, 3):
|
||
pi_bot.procesar(f"aspiradora potencia {sub}", chat_id)
|
||
_cerrar_menu(chat_id, message_id)
|
||
_fin_accion(chat_id, "aspi")
|
||
return
|
||
if accion == "dispositivos":
|
||
_record_cat(chat_id, "parental")
|
||
_mostrar_dispositivos(chat_id, message_id)
|
||
return
|
||
if accion == "blqdev":
|
||
_record_cat(chat_id, "parental")
|
||
lista = menu_dispositivos.get(chat_id) or []
|
||
numero = int(sub) if sub.isdigit() else 0
|
||
if 1 <= numero <= len(lista):
|
||
d = lista[numero - 1]
|
||
try:
|
||
from asus_api_control import bloquear_mac, listar_dispositivos
|
||
bloquear_mac(d["mac"], not d["bloqueado"], d["nombre"])
|
||
lista = listar_dispositivos()
|
||
menu_dispositivos[chat_id] = lista
|
||
except Exception as e:
|
||
_enviar_nuevo(chat_id, f"❌ Error: {e}", None)
|
||
return
|
||
_enviar_edit(chat_id, message_id,
|
||
"📺 <b>Bloquear dispositivo</b>\nPulsa el número para "
|
||
"bloquear/desbloquear:",
|
||
teclado_dispositivos(lista))
|
||
return
|
||
if accion == "tablets":
|
||
if sub in ("bloquear", "desbloquear"):
|
||
verbo = "desactivar" if sub == "bloquear" else "activar"
|
||
pi_bot.procesar(f"parental {verbo} Inés", chat_id)
|
||
pi_bot.procesar(f"parental {verbo} Carolina", chat_id)
|
||
_cerrar_menu(chat_id, message_id)
|
||
_fin_accion(chat_id, "parental")
|
||
return
|
||
if accion == "router":
|
||
mapeo = {
|
||
"estado": "router estado",
|
||
"clientes": "router clientes",
|
||
"wifi": "router wifi",
|
||
"inventario": "router inventario",
|
||
"parental": "router parental",
|
||
"reiniciar": "router reiniciar",
|
||
"reservar": "router reservar",
|
||
}
|
||
_disp(chat_id, message_id, mapeo.get(sub, "router ayuda"), "router")
|
||
return
|
||
if accion in ("torrents", "bajar"):
|
||
numero = int(sub) if sub.isdigit() else 0
|
||
if numero:
|
||
_disp(chat_id, message_id, f"{accion} {numero}", "videoclub")
|
||
return
|
||
|
||
|
||
# --------------------------------------------- pendiente de texto libre ----
|
||
|
||
def _pend(chat_id):
|
||
import pi_bot
|
||
return pi_bot.menu_pendiente
|
||
|
||
|
||
def _guardar_pendiente(chat_id, accion):
|
||
_pend(chat_id)[chat_id] = accion
|
||
|
||
|
||
def _limpiar_pendiente(chat_id):
|
||
_pend(chat_id).pop(chat_id, None)
|
||
|
||
|
||
def pendiente_activo(chat_id):
|
||
return chat_id in _pend(chat_id)
|
||
|
||
|
||
def cancelar_pendiente(chat_id):
|
||
_limpiar_pendiente(chat_id)
|
||
|
||
|
||
def construir_comando(chat_id, texto):
|
||
"""Devuelve el texto del comando para el texto libre recibido, o None."""
|
||
accion = _pend(chat_id).get(chat_id)
|
||
if not accion:
|
||
return None
|
||
texto = texto.strip()
|
||
if accion in ("pausa_minutos",):
|
||
if not texto.isdigit():
|
||
return "INVALIDO"
|
||
return None # manejado aparte
|
||
prefijos = {
|
||
"busca": "busca",
|
||
"pelicula": "pelicula",
|
||
"serie": "serie",
|
||
"tv": "tv",
|
||
"alarma": "alarma",
|
||
"youtube": "youtube",
|
||
"descargar": "descargar",
|
||
"desactivar": "parental desactivar",
|
||
"activar": "parental activar",
|
||
}
|
||
prefijo = prefijos.get(accion)
|
||
if prefijo is None:
|
||
return None
|
||
return f"{prefijo} {texto}"
|
||
|
||
|
||
def resolver_pausa_minutos(chat_id, texto):
|
||
"""Si el pendiente es pausa_minutos y el texto es valido, lanza la pausa."""
|
||
accion = _pend(chat_id).get(chat_id)
|
||
if accion != "pausa_minutos":
|
||
return False
|
||
if not texto.strip().isdigit():
|
||
return False
|
||
minutos = int(texto.strip())
|
||
if minutos < 1 or minutos > 1440:
|
||
return False
|
||
nombre = _get_pausa_nombre(chat_id)
|
||
_limpiar_pendiente(chat_id)
|
||
if not nombre:
|
||
return True
|
||
import pi_bot
|
||
pi_bot.procesar(f"parental pausa {nombre} {minutos}", chat_id)
|
||
_reenviar_menu(chat_id, "parental")
|
||
return True
|
||
|
||
|
||
def pausa_estado(chat_id):
|
||
import pi_bot
|
||
return pi_bot.menu_pausa_nombre.get(chat_id)
|
||
|
||
|
||
def _set_pausa_nombre(chat_id, nombre):
|
||
import pi_bot
|
||
pi_bot.menu_pausa_nombre[chat_id] = nombre
|
||
|
||
|
||
def _get_pausa_nombre(chat_id):
|
||
import pi_bot
|
||
return pi_bot.menu_pausa_nombre.get(chat_id)
|
||
|
||
|
||
def _borrar(chat_id, message_id):
|
||
import requests
|
||
try:
|
||
requests.post(_api("deleteMessage"),
|
||
data={"chat_id": chat_id, "message_id": message_id},
|
||
timeout=10)
|
||
except Exception:
|
||
pass
|