05-sep: [parental] pausar y bloquear dispositivos por nombre
This commit is contained in:
@@ -7,6 +7,7 @@ import unicodedata
|
||||
|
||||
import aiohttp
|
||||
from asusrouter import AsusData, AsusRouter
|
||||
from asusrouter.modules.parental_control import PCRuleType, ParentalControlRule
|
||||
|
||||
|
||||
def _load_env():
|
||||
@@ -71,6 +72,41 @@ async def _parental_data():
|
||||
await session.close()
|
||||
|
||||
|
||||
async def _set_block(mac, name, blocked):
|
||||
username = _env("ASUS_USERNAME")
|
||||
password = _env("ASUS_PASSWORD")
|
||||
if not username or not password:
|
||||
raise RuntimeError(
|
||||
"Falta ASUS_USERNAME o ASUS_PASSWORD en el .env de la Raspberry"
|
||||
)
|
||||
session = aiohttp.ClientSession()
|
||||
router = AsusRouter(
|
||||
hostname=_env("ASUS_ROUTER_IP", "192.168.50.1"),
|
||||
username=username,
|
||||
password=password,
|
||||
session=session,
|
||||
)
|
||||
try:
|
||||
await router.async_connect()
|
||||
rule = ParentalControlRule(
|
||||
mac=mac,
|
||||
name=name if blocked else None,
|
||||
type=PCRuleType.BLOCK if blocked else PCRuleType.REMOVE,
|
||||
)
|
||||
return await router.async_set_state(rule)
|
||||
finally:
|
||||
await router.async_disconnect()
|
||||
await session.close()
|
||||
|
||||
|
||||
def parental_status():
|
||||
data = asyncio.run(_parental_data())
|
||||
return json.dumps(data, ensure_ascii=False, indent=2, default=str)
|
||||
|
||||
|
||||
def cambiar_bloqueo(nombre, blocked):
|
||||
device = resolver_dispositivo(nombre)
|
||||
if not device:
|
||||
raise ValueError(f"Dispositivo no reconocido: {nombre}")
|
||||
asyncio.run(_set_block(device["mac"], device["name"], blocked))
|
||||
return f"{'Bloqueado' if blocked else 'Activado'}: {device['name']}"
|
||||
|
||||
@@ -15,6 +15,7 @@ ultimos_torrents = {} # chat_id -> {'titulo':..., 'torrents':[...]}
|
||||
flujo_genero = {} # chat_id -> 'esperando_tipo' | 'esperando_genero' | None
|
||||
flujo_genero_tipo = {} # chat_id -> 'movie' | 'series' (tipo ya elegido)
|
||||
panel_descargas = {} # chat_id -> estado del panel editable
|
||||
temporizadores_parental = {} # alias normalizado -> Timer de desbloqueo
|
||||
|
||||
BASE = os.path.dirname(os.path.abspath(__file__))
|
||||
LOG = os.path.join(BASE, "bot.log")
|
||||
@@ -458,23 +459,48 @@ def procesar(texto, chat_id):
|
||||
else:
|
||||
enviar("Acción de router no reconocida. Usa <code>/router ayuda</code>.", chat_id)
|
||||
elif comando == "parental":
|
||||
partes_parental = argumento.split()
|
||||
accion_parental = partes_parental[0].lower() if partes_parental else "listar"
|
||||
try:
|
||||
from asus_api_control import cambiar_bloqueo, normalizar_nombre
|
||||
if accion_parental == "listar":
|
||||
from router_control import control_parental
|
||||
enviar(
|
||||
"👪 <b>RUTINAS PARENTALES</b>\n"
|
||||
"Alias reconocidos: <code>Inés</code>, <code>INES</code>, <code>Carolina</code>.\n"
|
||||
"Rutinas previstas:\n"
|
||||
"<code>/parental listar</code>\n"
|
||||
"<code>/parental activar <rutina></code>\n"
|
||||
"<code>/parental desactivar <rutina></code>\n"
|
||||
"<code>/parental pausa <rutina> <minutos></code>\n\n"
|
||||
"Las acciones por nombre quedan preparadas para la primera rutina.\n\n"
|
||||
"Estado actual:\n" + control_parental(),
|
||||
chat_id,
|
||||
enviar("👪 <b>CONTROL PARENTAL ASUS</b>\n" + control_parental(), chat_id)
|
||||
elif accion_parental in ("desactivar", "bloquear") and len(partes_parental) >= 2:
|
||||
alias = " ".join(partes_parental[1:])
|
||||
enviar(f"🔒 {cambiar_bloqueo(alias, True)}", chat_id)
|
||||
elif accion_parental in ("activar", "desbloquear") and len(partes_parental) >= 2:
|
||||
alias = " ".join(partes_parental[1:])
|
||||
timer = temporizadores_parental.pop(normalizar_nombre(alias), None)
|
||||
if timer:
|
||||
timer.cancel()
|
||||
enviar(f"🔓 {cambiar_bloqueo(alias, False)}", chat_id)
|
||||
elif accion_parental == "pausa" and len(partes_parental) >= 3:
|
||||
alias = " ".join(partes_parental[1:-1])
|
||||
minutos = int(partes_parental[-1])
|
||||
if minutos < 1 or minutos > 1440:
|
||||
raise ValueError("Los minutos deben estar entre 1 y 1440")
|
||||
cambiar_bloqueo(alias, True)
|
||||
clave = normalizar_nombre(alias)
|
||||
anterior = temporizadores_parental.pop(clave, None)
|
||||
if anterior:
|
||||
anterior.cancel()
|
||||
timer = threading.Timer(
|
||||
minutos * 60,
|
||||
lambda: cambiar_bloqueo(alias, False),
|
||||
)
|
||||
timer.daemon = True
|
||||
temporizadores_parental[clave] = timer
|
||||
timer.start()
|
||||
enviar(f"⏸️ Bloqueado {alias} durante {minutos} minutos.", chat_id)
|
||||
else:
|
||||
enviar(
|
||||
"Uso: <code>/parental pausa Inés 60</code>, "
|
||||
"<code>/parental desactivar Carolina</code> o "
|
||||
"<code>/parental activar Inés</code>.", chat_id)
|
||||
except Exception as e:
|
||||
log(f"parental error: {e}")
|
||||
enviar(f"❌ Error consultando parental: {e}", chat_id)
|
||||
enviar(f"❌ Error en control parental: {e}", chat_id)
|
||||
elif t in ("pelis", "/pelis"):
|
||||
procesar_pelis(chat_id)
|
||||
elif t in ("series", "/series"):
|
||||
@@ -532,10 +558,10 @@ def procesar(texto, chat_id):
|
||||
"━━━ 👪 CONTROL PARENTAL ━━━\n"
|
||||
"<b>14.</b> <code>parental listar</code> — estado y dispositivos\n"
|
||||
" ✏️ Ej: <code>/parental listar</code>\n"
|
||||
"<b>15.</b> <code>parental activar|desactivar</code> — rutinas por nombre (preparado)\n"
|
||||
" ✏️ Ej: <code>/parental activar noches_escolares</code>\n"
|
||||
"<b>16.</b> <code>parental pausa</code> — pausa temporal (preparado)\n"
|
||||
" ✏️ Ej: <code>/parental pausa noches_escolares 60</code>\n\n"
|
||||
"<b>15.</b> <code>parental desactivar|activar</code> — bloquea o desbloquea\n"
|
||||
" ✏️ Ej: <code>/parental desactivar Inés</code>\n"
|
||||
"<b>16.</b> <code>parental pausa</code> — bloquea X minutos\n"
|
||||
" ✏️ Ej: <code>/parental pausa Carolina 60</code>\n\n"
|
||||
"━━━ 🛠️ SISTEMA ━━━\n"
|
||||
"<b>17.</b> <code>estado</code> — estado de la Pi\n"
|
||||
" ✏️ Ej: <code>/estado</code>\n"
|
||||
|
||||
Reference in New Issue
Block a user