05-sep: [feat] menu wizard en bot OpenCode (/menu), menu IDD cierra al elegir + updates en hilos, borrar tarea NAS (0%) desde panel
This commit is contained in:
@@ -19,6 +19,7 @@ temporizadores_parental = {} # alias normalizado -> Timer de desbloqueo
|
||||
menu_pendiente = {} # chat_id -> accion de texto libre esperada (menu botones)
|
||||
menu_pausa_nombre = {} # chat_id -> nombre elegido en flujo de pausa
|
||||
historial_chat = {} # chat_id -> [message_id...] enviados por el bot (para /limpiar)
|
||||
borrar_pend = {} # chat_id -> lista de tareas NAS esperando numero a borrar
|
||||
|
||||
BASE = os.path.dirname(os.path.abspath(__file__))
|
||||
LOG = os.path.join(BASE, "bot.log")
|
||||
@@ -119,6 +120,7 @@ def teclado_descargas():
|
||||
],
|
||||
[
|
||||
{"text": "📁 Todas", "callback_data": "dl:all"},
|
||||
{"text": "🗑️ Borrar…", "callback_data": "dl:del"},
|
||||
{"text": "✖️ Cerrar", "callback_data": "dl:close"},
|
||||
],
|
||||
]
|
||||
@@ -245,6 +247,9 @@ def procesar_callback(callback):
|
||||
return
|
||||
accion = data.split(":", 1)[-1]
|
||||
estado_panel = panel_descargas.get(chat_id)
|
||||
if accion == "del":
|
||||
pedir_borrar(chat_id)
|
||||
return
|
||||
if not estado_panel:
|
||||
return
|
||||
if accion == "close":
|
||||
@@ -292,6 +297,57 @@ def limpiar_pantalla(chat_id):
|
||||
threading.Timer(6.0, borrar, args=(chat_id, aviso)).start()
|
||||
|
||||
|
||||
def pedir_borrar(chat_id):
|
||||
"""Pide que se elija el numero de la tarea NAS a borrar."""
|
||||
try:
|
||||
import nas_dl
|
||||
except Exception as e:
|
||||
log(f"pedir_borrar import error: {e}")
|
||||
enviar(f"❌ Error cargando el módulo del NAS: {e}", chat_id)
|
||||
return
|
||||
try:
|
||||
tareas = nas_dl.listar_tareas()
|
||||
except Exception as e:
|
||||
log(f"listar tareas error: {e}")
|
||||
enviar(f"❌ Error listando descargas: {e}", chat_id)
|
||||
return
|
||||
if not tareas:
|
||||
enviar("No hay tareas en Download Station.", chat_id)
|
||||
return
|
||||
borrar_pend[chat_id] = tareas
|
||||
iconos = {"downloading": "▶️", "waiting": "⏳", "error": "❌",
|
||||
"finished": "✅", "paused": "⏸️", "seeding": "🌱"}
|
||||
lineas = ["🗑️ <b>Responde el número</b> de la tarea a BORRAR "
|
||||
"(o escribe <code>cancelar</code>):", ""]
|
||||
for i, t in enumerate(tareas, start=1):
|
||||
ic = iconos.get(t["status"], "•")
|
||||
titulo = (t["title"] or "?").strip()
|
||||
lineas.append(f"{i}. {ic} [{t['status']}] ({t['pct']:.0f}%) {titulo[:70]}")
|
||||
enviar("\n".join(lineas), chat_id)
|
||||
|
||||
|
||||
def _ejecutar_borrado(chat_id, numero):
|
||||
tareas = borrar_pend.pop(chat_id, None)
|
||||
if not tareas:
|
||||
return False
|
||||
if numero < 1 or numero > len(tareas):
|
||||
enviar("❌ Número no válido.", chat_id)
|
||||
return True
|
||||
tarea = tareas[numero - 1]
|
||||
try:
|
||||
import nas_dl
|
||||
except Exception as e:
|
||||
enviar(f"❌ Error cargando el módulo del NAS: {e}", chat_id)
|
||||
return True
|
||||
ok, detalle = nas_dl.borrar_tarea(tarea["id"])
|
||||
titulo = (tarea["title"] or "?").strip()
|
||||
if ok:
|
||||
enviar(f"🗑️ Tarea borrada: <b>{titulo[:80]}</b>", chat_id)
|
||||
else:
|
||||
enviar(f"❌ No se pudo borrar <b>{titulo[:60]}</b>: {detalle}", chat_id)
|
||||
return True
|
||||
|
||||
|
||||
def mandar_tv(mensaje, simple):
|
||||
try:
|
||||
url = f"{TV_API}?texto={urllib.parse.quote(mensaje)}"
|
||||
@@ -340,6 +396,10 @@ def procesar(texto, chat_id):
|
||||
return
|
||||
if cmd:
|
||||
return procesar(cmd, chat_id)
|
||||
# Borrado de descargas pendiente (numero de tarea NAS)
|
||||
if t.isdigit() and chat_id in borrar_pend:
|
||||
_ejecutar_borrado(chat_id, int(t))
|
||||
return
|
||||
# Flujo interactivo por genero (espera numeros en pasos)
|
||||
if flujo_genero.get(chat_id) and t.isdigit():
|
||||
paso = flujo_genero[chat_id]
|
||||
@@ -418,6 +478,10 @@ def procesar(texto, chat_id):
|
||||
else:
|
||||
ok = mandar_youtube(url)
|
||||
enviar("🎬 YouTube lanzado en la TV ✅" if ok else "❌ No se pudo lanzar YouTube", chat_id)
|
||||
elif comando == "borrar" and not argumento:
|
||||
pedir_borrar(chat_id)
|
||||
elif comando == "descargas" and argumento.lower() == "borrar":
|
||||
pedir_borrar(chat_id)
|
||||
elif t in ("descargas", "/descargas") or (comando == "descargar" and not argumento):
|
||||
abrir_panel_descargas(chat_id)
|
||||
elif comando == "descargar":
|
||||
@@ -716,7 +780,8 @@ def procesar(texto, chat_id):
|
||||
" ✏️ Ej: <code>/novedades</code>\n\n"
|
||||
"━━━ 🖥️ NAS / DESCARGAS ━━━\n"
|
||||
"<b>8.</b> <code>descargas</code> — panel con progreso y botones\n"
|
||||
" ✏️ Ej: <code>/descargas</code> o <code>/descargar</code>\n"
|
||||
" ▶️ En el panel: botón <b>🗑️ Borrar…</b> para eliminar una tarea\n"
|
||||
" ✏️ Ej: <code>/descargas</code> o <code>/borrar</code>\n"
|
||||
"<b>9.</b> <code>descargar <enlace></code> — añade a Download Station\n"
|
||||
" ✏️ Ej: <code>/descargar magnet:?xt=urn:btih:...</code>\n"
|
||||
"<b>10.</b> <code>termo on|off|estado</code> — controla el enchufe Tapo\n"
|
||||
@@ -1091,6 +1156,23 @@ def guardar_offset(offset):
|
||||
pass
|
||||
|
||||
|
||||
def _atender_update(upd):
|
||||
"""Procesa una update en su propio hilo (no bloquea el polling)."""
|
||||
try:
|
||||
if upd.get("callback_query"):
|
||||
procesar_callback(upd["callback_query"])
|
||||
return
|
||||
msg = upd.get("message") or upd.get("channel_post")
|
||||
if not msg:
|
||||
return
|
||||
texto = msg.get("text")
|
||||
chat_id = msg["chat"]["id"]
|
||||
if texto:
|
||||
procesar(texto, chat_id)
|
||||
except Exception as e:
|
||||
log(f"ERROR update: {e}")
|
||||
|
||||
|
||||
def main():
|
||||
if not TOKEN:
|
||||
print("Falta TELEGRAM_TOKEN en .env")
|
||||
@@ -1112,16 +1194,8 @@ def main():
|
||||
offset = upd["update_id"] + 1
|
||||
guardar_offset(offset)
|
||||
log(f"UPDATE {upd.get('update_id')}")
|
||||
if upd.get("callback_query"):
|
||||
procesar_callback(upd["callback_query"])
|
||||
continue
|
||||
msg = upd.get("message") or upd.get("channel_post")
|
||||
if not msg:
|
||||
continue
|
||||
texto = msg.get("text")
|
||||
chat_id = msg["chat"]["id"]
|
||||
if texto:
|
||||
procesar(texto, chat_id)
|
||||
threading.Thread(target=_atender_update, args=(upd,),
|
||||
daemon=True).start()
|
||||
except Exception as e:
|
||||
log(f"ERROR {e}")
|
||||
print("Error:", e)
|
||||
|
||||
Reference in New Issue
Block a user