05-sep: [parental] pausar y bloquear dispositivos por nombre
This commit is contained in:
@@ -7,6 +7,7 @@ import unicodedata
|
|||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from asusrouter import AsusData, AsusRouter
|
from asusrouter import AsusData, AsusRouter
|
||||||
|
from asusrouter.modules.parental_control import PCRuleType, ParentalControlRule
|
||||||
|
|
||||||
|
|
||||||
def _load_env():
|
def _load_env():
|
||||||
@@ -71,6 +72,41 @@ async def _parental_data():
|
|||||||
await session.close()
|
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():
|
def parental_status():
|
||||||
data = asyncio.run(_parental_data())
|
data = asyncio.run(_parental_data())
|
||||||
return json.dumps(data, ensure_ascii=False, indent=2, default=str)
|
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 = {} # chat_id -> 'esperando_tipo' | 'esperando_genero' | None
|
||||||
flujo_genero_tipo = {} # chat_id -> 'movie' | 'series' (tipo ya elegido)
|
flujo_genero_tipo = {} # chat_id -> 'movie' | 'series' (tipo ya elegido)
|
||||||
panel_descargas = {} # chat_id -> estado del panel editable
|
panel_descargas = {} # chat_id -> estado del panel editable
|
||||||
|
temporizadores_parental = {} # alias normalizado -> Timer de desbloqueo
|
||||||
|
|
||||||
BASE = os.path.dirname(os.path.abspath(__file__))
|
BASE = os.path.dirname(os.path.abspath(__file__))
|
||||||
LOG = os.path.join(BASE, "bot.log")
|
LOG = os.path.join(BASE, "bot.log")
|
||||||
@@ -458,23 +459,48 @@ def procesar(texto, chat_id):
|
|||||||
else:
|
else:
|
||||||
enviar("Acción de router no reconocida. Usa <code>/router ayuda</code>.", chat_id)
|
enviar("Acción de router no reconocida. Usa <code>/router ayuda</code>.", chat_id)
|
||||||
elif comando == "parental":
|
elif comando == "parental":
|
||||||
|
partes_parental = argumento.split()
|
||||||
|
accion_parental = partes_parental[0].lower() if partes_parental else "listar"
|
||||||
try:
|
try:
|
||||||
|
from asus_api_control import cambiar_bloqueo, normalizar_nombre
|
||||||
|
if accion_parental == "listar":
|
||||||
from router_control import control_parental
|
from router_control import control_parental
|
||||||
enviar(
|
enviar("👪 <b>CONTROL PARENTAL ASUS</b>\n" + control_parental(), chat_id)
|
||||||
"👪 <b>RUTINAS PARENTALES</b>\n"
|
elif accion_parental in ("desactivar", "bloquear") and len(partes_parental) >= 2:
|
||||||
"Alias reconocidos: <code>Inés</code>, <code>INES</code>, <code>Carolina</code>.\n"
|
alias = " ".join(partes_parental[1:])
|
||||||
"Rutinas previstas:\n"
|
enviar(f"🔒 {cambiar_bloqueo(alias, True)}", chat_id)
|
||||||
"<code>/parental listar</code>\n"
|
elif accion_parental in ("activar", "desbloquear") and len(partes_parental) >= 2:
|
||||||
"<code>/parental activar <rutina></code>\n"
|
alias = " ".join(partes_parental[1:])
|
||||||
"<code>/parental desactivar <rutina></code>\n"
|
timer = temporizadores_parental.pop(normalizar_nombre(alias), None)
|
||||||
"<code>/parental pausa <rutina> <minutos></code>\n\n"
|
if timer:
|
||||||
"Las acciones por nombre quedan preparadas para la primera rutina.\n\n"
|
timer.cancel()
|
||||||
"Estado actual:\n" + control_parental(),
|
enviar(f"🔓 {cambiar_bloqueo(alias, False)}", chat_id)
|
||||||
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:
|
except Exception as e:
|
||||||
log(f"parental error: {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"):
|
elif t in ("pelis", "/pelis"):
|
||||||
procesar_pelis(chat_id)
|
procesar_pelis(chat_id)
|
||||||
elif t in ("series", "/series"):
|
elif t in ("series", "/series"):
|
||||||
@@ -532,10 +558,10 @@ def procesar(texto, chat_id):
|
|||||||
"━━━ 👪 CONTROL PARENTAL ━━━\n"
|
"━━━ 👪 CONTROL PARENTAL ━━━\n"
|
||||||
"<b>14.</b> <code>parental listar</code> — estado y dispositivos\n"
|
"<b>14.</b> <code>parental listar</code> — estado y dispositivos\n"
|
||||||
" ✏️ Ej: <code>/parental listar</code>\n"
|
" ✏️ Ej: <code>/parental listar</code>\n"
|
||||||
"<b>15.</b> <code>parental activar|desactivar</code> — rutinas por nombre (preparado)\n"
|
"<b>15.</b> <code>parental desactivar|activar</code> — bloquea o desbloquea\n"
|
||||||
" ✏️ Ej: <code>/parental activar noches_escolares</code>\n"
|
" ✏️ Ej: <code>/parental desactivar Inés</code>\n"
|
||||||
"<b>16.</b> <code>parental pausa</code> — pausa temporal (preparado)\n"
|
"<b>16.</b> <code>parental pausa</code> — bloquea X minutos\n"
|
||||||
" ✏️ Ej: <code>/parental pausa noches_escolares 60</code>\n\n"
|
" ✏️ Ej: <code>/parental pausa Carolina 60</code>\n\n"
|
||||||
"━━━ 🛠️ SISTEMA ━━━\n"
|
"━━━ 🛠️ SISTEMA ━━━\n"
|
||||||
"<b>17.</b> <code>estado</code> — estado de la Pi\n"
|
"<b>17.</b> <code>estado</code> — estado de la Pi\n"
|
||||||
" ✏️ Ej: <code>/estado</code>\n"
|
" ✏️ Ej: <code>/estado</code>\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user