550 lines
20 KiB
Python
550 lines
20 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import threading
|
|
import time
|
|
import urllib.parse
|
|
|
|
import requests
|
|
|
|
# Estado por chat para la busqueda global interactiva (numero -> descarga)
|
|
ultima_titulos = {} # chat_id -> {'query':..., 'results':[...]}
|
|
ultimos_torrents = {} # chat_id -> {'titulo':..., 'torrents':[...]}
|
|
|
|
BASE = os.path.dirname(os.path.abspath(__file__))
|
|
LOG = os.path.join(BASE, "bot.log")
|
|
OFFSET_FILE = os.path.join(BASE, "bot.offset")
|
|
TV_API = "http://127.0.0.1:8600/tv/mensaje"
|
|
|
|
|
|
def log(linea):
|
|
try:
|
|
with open(LOG, "a") as f:
|
|
f.write(f"{time.strftime('%H:%M:%S')} {linea}\n")
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def load_env():
|
|
env = {}
|
|
try:
|
|
for line in open(os.path.join(BASE, ".env")):
|
|
line = line.strip()
|
|
if line and not line.startswith("#") and "=" in line:
|
|
k, v = line.split("=", 1)
|
|
env[k.strip()] = v.strip()
|
|
except Exception:
|
|
pass
|
|
return env
|
|
|
|
|
|
ENV = load_env()
|
|
TOKEN = ENV.get("TELEGRAM_TOKEN", "")
|
|
CHAT_ID = ENV.get("TELEGRAM_CHAT_ID", "")
|
|
ALERTA_TEMP = float(ENV.get("ALERTA_TEMP", "80"))
|
|
|
|
|
|
def sh(cmd):
|
|
try:
|
|
return subprocess.run(cmd, shell=True, capture_output=True,
|
|
text=True, timeout=10).stdout.strip()
|
|
except Exception:
|
|
return "n/a"
|
|
|
|
|
|
def estado():
|
|
temp = sh("vcgencmd measure_temp")
|
|
upt = sh("uptime -p")
|
|
load = open("/proc/loadavg").read().split()[:3]
|
|
free = sh("free -h | awk 'NR==2{print $2\" total, \"$7\" disponible\"}'")
|
|
disk = sh("df -h / | awk 'NR==2{print $3\" usados de \"$2\" (\"$5\")\"}'")
|
|
ips = sh("hostname -I")
|
|
temp_c = None
|
|
try:
|
|
temp_c = float(temp.replace("'C", "").replace("temp=", ""))
|
|
except Exception:
|
|
pass
|
|
msg = (
|
|
"📊 Estado de <b>minipc</b>:\n"
|
|
f"🌡️ Temperatura: <b>{temp}</b>\n"
|
|
f"🔌 Uptime: {upt}\n"
|
|
f"⚙️ Carga: {', '.join(load)}\n"
|
|
f"🧠 RAM: {free}\n"
|
|
f"💾 Disco /: {disk}\n"
|
|
f"🌐 IPs: {ips}"
|
|
)
|
|
return msg, temp_c
|
|
|
|
|
|
def enviar(texto, chat_id):
|
|
try:
|
|
r = requests.post(
|
|
f"https://api.telegram.org/bot{TOKEN}/sendMessage",
|
|
data={"chat_id": chat_id, "text": texto, "parse_mode": "HTML"},
|
|
timeout=10,
|
|
)
|
|
d = r.json()
|
|
if d.get("ok"):
|
|
return d["result"].get("message_id")
|
|
except Exception as e:
|
|
print("Error enviando:", e)
|
|
return None
|
|
|
|
|
|
def borrar(chat_id, message_id):
|
|
try:
|
|
requests.post(
|
|
f"https://api.telegram.org/bot{TOKEN}/deleteMessage",
|
|
data={"chat_id": chat_id, "message_id": message_id},
|
|
timeout=10,
|
|
)
|
|
except Exception as e:
|
|
print("Error borrando:", e)
|
|
|
|
|
|
def mandar_tv(mensaje, simple):
|
|
try:
|
|
url = f"{TV_API}?texto={urllib.parse.quote(mensaje)}"
|
|
if simple:
|
|
url += "&simple=1"
|
|
r = requests.get(url, timeout=8)
|
|
return r.status_code == 200
|
|
except Exception as e:
|
|
log(f"tv error: {e}")
|
|
return False
|
|
|
|
|
|
def mandar_youtube(url):
|
|
try:
|
|
r = requests.get(f"http://127.0.0.1:8600/tv/youtube?url={url}", timeout=10)
|
|
return r.status_code == 200
|
|
except Exception as e:
|
|
log(f"youtube error: {e}")
|
|
return False
|
|
|
|
|
|
def procesar(texto, chat_id):
|
|
t = texto.lower().strip()
|
|
log(f"RECIBIDO chat={chat_id} texto={texto!r}")
|
|
if t in ("estado", "/estado", "status", "/status"):
|
|
msg, _ = estado()
|
|
enviar(msg, chat_id)
|
|
elif "temperatura" in t or "temp" in t:
|
|
temp = sh("vcgencmd measure_temp")
|
|
enviar(f"🌡️ Temperatura de la Pi: <b>{temp}</b>", chat_id)
|
|
elif t.startswith("tv ") or t.startswith("/tv "):
|
|
msj = texto.split(" ", 1)[1].strip()
|
|
if not msj:
|
|
enviar("Uso: <b>tv <mensaje></b> (mensaje rapido a la tele)", chat_id)
|
|
else:
|
|
ok = mandar_tv(msj, simple=True)
|
|
enviar("📺 Mensaje enviado a la tele ✅" if ok
|
|
else "❌ No se pudo enviar a la tele", chat_id)
|
|
elif t.startswith("alarma ") or t.startswith("/alarma "):
|
|
msj = texto.split(" ", 1)[1].strip()
|
|
if not msj:
|
|
enviar("Uso: <b>alarma <mensaje></b> (secuencia completa: sirena x3)", chat_id)
|
|
else:
|
|
ok = mandar_tv(msj, simple=False)
|
|
enviar("🚨 Alarma lanzada en la tele ✅" if ok
|
|
else "❌ No se pudo lanzar la alarma", chat_id)
|
|
elif t.startswith("panorama") or t.startswith("/panorama"):
|
|
enviar("📷 Capturando snapshots de las cámaras...", chat_id)
|
|
try:
|
|
import subprocess as sp
|
|
r = sp.run(["python3", "/home/pi/minipc/vigilancia/panorama.py"],
|
|
capture_output=True, text=True, timeout=60, cwd="/home/pi/minipc/vigilancia")
|
|
log(f"panorama: {r.stdout.strip()[-200:]}")
|
|
except Exception as e:
|
|
log(f"panorama error: {e}")
|
|
elif t in ("limpieza", "/limpieza", "limpiar", "/limpiar"):
|
|
enviar("🧹 Ejecutando limpieza...", chat_id)
|
|
try:
|
|
from limpiar import limpiar
|
|
resultado = limpiar()
|
|
enviar(f"<pre>{resultado}</pre>", chat_id)
|
|
except Exception as e:
|
|
log(f"limpieza error: {e}")
|
|
enviar(f"❌ Error: {e}", chat_id)
|
|
elif t.startswith("youtube ") or t.startswith("/youtube "):
|
|
url = texto.split(" ", 1)[1].strip()
|
|
if not url:
|
|
enviar("Uso: <b>youtube <URL></b>", chat_id)
|
|
else:
|
|
ok = mandar_youtube(url)
|
|
enviar("🎬 YouTube lanzado en la TV ✅" if ok else "❌ No se pudo lanzar YouTube", chat_id)
|
|
elif t.startswith("descargar ") or t.startswith("/descargar "):
|
|
uri = texto.split(" ", 1)[1].strip()
|
|
if not uri:
|
|
enviar("Uso: <b>descargar <enlace|magnet|uri></b> (anade a Download Station del NAS)", chat_id)
|
|
else:
|
|
import nas_dl
|
|
ok = nas_dl.add_torrent(uri)
|
|
enviar("📥 Añadido a Download Station del NAS ✅" if ok
|
|
else "❌ No se pudo añadir al NAS", chat_id)
|
|
elif t in ("pelis", "/pelis"):
|
|
procesar_pelis(chat_id)
|
|
elif t in ("series", "/series"):
|
|
procesar_series(chat_id)
|
|
elif t.startswith("pelicula ") or t.startswith("/pelicula "):
|
|
nombre = texto.split(" ", 1)[1].strip()
|
|
procesar_buscador_pelicula(nombre, chat_id)
|
|
elif t.startswith("serie ") or t.startswith("/serie "):
|
|
nombre = texto.split(" ", 1)[1].strip()
|
|
procesar_buscador_serie(nombre, chat_id)
|
|
elif t in ("novedades", "/novedades"):
|
|
procesar_novedades(chat_id)
|
|
elif t.startswith("busca ") or t.startswith("/busca "):
|
|
nombre = texto.split(" ", 1)[1].strip()
|
|
procesar_busca(nombre, chat_id)
|
|
elif t.startswith("torrents ") or t.startswith("/torrents "):
|
|
n = _int_arg(texto)
|
|
procesar_torrents(n, chat_id)
|
|
elif t.startswith("bajar ") or t.startswith("/bajar "):
|
|
n = _int_arg(texto)
|
|
procesar_bajar(n, chat_id)
|
|
elif t in ("ayuda", "/ayuda", "help", "/help"):
|
|
enviar("Comandos:\n"
|
|
"<b>estado</b> — estado de la Pi\n"
|
|
"<b>temperatura</b> — temperatura\n"
|
|
"<b>tv <mensaje></b> — mensaje rápido a la tele\n"
|
|
"<b>alarma <mensaje></b> — secuencia completa (sirena x3)\n"
|
|
"<b>youtube <URL></b> — reproduce YouTube y apaga al terminar\n"
|
|
"<b>descargar <enlace></b> — añade a Download Station del NAS\n"
|
|
"<b>pelicula <nombre></b> — buscar pelicula y descargar\n"
|
|
"<b>serie <nombre></b> — buscar serie con temporadas/capitulos\n"
|
|
"<b>novedades</b> — ultimas novedades del catalogo\n"
|
|
"<b>busca <nombre></b> — buscar en TODO internet (miles de pelis)\n"
|
|
"<b>torrents <n></b> — ver torrents del resultado n de /busca\n"
|
|
"<b>bajar <n></b> — descargar al NAS el torrent n de /torrents\n"
|
|
"<b>panorama</b> — fotos de las cámaras\n"
|
|
"<b>limpieza</b> — limpia procesos atascados de la Pi\n"
|
|
"<b>reboot</b> — reinicia la Pi (necesita confirmar con /confirmar-reboot)\n"
|
|
"<b>servicios</b> — estado de los servicios del sistema",
|
|
chat_id)
|
|
elif t in ("servicios", "/servicios"):
|
|
estado_svc = sh("systemctl is-active pi-bot tv-api autossh-tunel")
|
|
nombres = "pi-bot\ntv-api\nautossh-tunel"
|
|
activos = estado_svc.strip().splitlines()
|
|
lineas = []
|
|
for n, e in zip(["pi-bot", "tv-api", "autossh-tunel"], activos):
|
|
icono = "✅" if e == "active" else "❌"
|
|
lineas.append(f"{icono} {n}: {e}")
|
|
envio = "\n".join(lineas)
|
|
enviar(f"📦 Servicios:\n{envio}\n\n🔌 Túnel VPS: {'OK' if activos and activos[2]=='active' else 'caído'}", chat_id)
|
|
elif t == "reboot" or t == "/reboot":
|
|
enviar("⚠️ Para reiniciar la Pi responde <b>/confirmar-reboot</b> en 30 segundos.", chat_id)
|
|
elif t == "confirmar-reboot" or t == "/confirmar-reboot":
|
|
enviar("🔄 Reiniciando la Pi... volveré en un momento.", chat_id)
|
|
log("REBOOT solicitado")
|
|
sh("echo 'raspberry' | sudo -S reboot")
|
|
|
|
|
|
def procesar_series(chat_id):
|
|
"""Comando 'series': series con buena calidad en castellano del catalogo,
|
|
con el comando 'descargar <url>' listo. Adultos efimeros (5 min)."""
|
|
try:
|
|
import pelis
|
|
except Exception as e:
|
|
log(f"series import error: {e}")
|
|
enviar("❌ No se pudo cargar el modulo pelis", chat_id)
|
|
return
|
|
try:
|
|
enviar("📺 Consultando series del catálogo...", chat_id)
|
|
mensajes, adultos = pelis.generar_series()
|
|
except Exception as e:
|
|
log(f"series generar error: {e}")
|
|
enviar(f"❌ Error consultando el catálogo: {e}", chat_id)
|
|
return
|
|
|
|
for m in mensajes:
|
|
enviar(m, chat_id)
|
|
|
|
if adultos:
|
|
lineas = [f"🔞 Contenido adulto ({len(adultos)} novedades) — se borrará en 5 min:"]
|
|
for it in adultos[:30]:
|
|
y = f" ({it['year']})" if it["year"] else ""
|
|
enlace = it.get("enlace") or ""
|
|
linea = f"{it['clean']}{y}"
|
|
if enlace:
|
|
linea += f"\n<code>descargar {enlace}</code>"
|
|
lineas.append(linea)
|
|
if len(adultos) > 30:
|
|
lineas.append(f"... y {len(adultos) - 30} más")
|
|
texto = "\n".join(lineas)
|
|
for parte in pelis.trocear_efimero(texto, adultos):
|
|
mid = enviar(parte, chat_id)
|
|
if mid:
|
|
threading.Timer(300, borrar, args=(chat_id, mid)).start()
|
|
|
|
|
|
def procesar_pelis(chat_id):
|
|
"""Comando 'pelis': novedades con buena calidad en castellano, con el
|
|
comando 'descargar <url>' listo para copiar. Los adultos se envian en
|
|
un mensaje efimero que se borra a los 5 minutos y NO se loguea."""
|
|
try:
|
|
import pelis
|
|
except Exception as e:
|
|
log(f"pelis import error: {e}")
|
|
enviar("❌ No se pudo cargar el modulo pelis", chat_id)
|
|
return
|
|
try:
|
|
enviar("🎬 Consultando novedades del catálogo...", chat_id)
|
|
mensajes, adultos = pelis.generar()
|
|
except Exception as e:
|
|
log(f"pelis generar error: {e}")
|
|
enviar(f"❌ Error consultando el catálogo: {e}", chat_id)
|
|
return
|
|
|
|
for m in mensajes:
|
|
enviar(m, chat_id)
|
|
|
|
# Adultos: efimeros (5 min), sin loguear, nunca persisten
|
|
if adultos:
|
|
lineas = [f"🔞 Contenido adulto ({len(adultos)} novedades) — se borrará en 5 min:"]
|
|
for it in adultos[:30]:
|
|
y = f" ({it['year']})" if it["year"] else ""
|
|
enlace = it.get("enlace") or ""
|
|
linea = f"{it['clean']}{y}"
|
|
if enlace:
|
|
linea += f"\n<code>descargar {enlace}</code>"
|
|
lineas.append(linea)
|
|
if len(adultos) > 30:
|
|
lineas.append(f"... y {len(adultos) - 30} más")
|
|
texto = "\n".join(lineas)
|
|
for parte in pelis.trocear_efimero(texto, adultos):
|
|
mid = enviar(parte, chat_id)
|
|
if mid:
|
|
threading.Timer(300, borrar, args=(chat_id, mid)).start()
|
|
|
|
|
|
def procesar_buscador_pelicula(nombre, chat_id):
|
|
"""Busca peliculas por nombre y muestra resultados numerados."""
|
|
try:
|
|
sys.path.insert(0, os.path.join(BASE, "..", "videoclub"))
|
|
import videoclub_buscador as vcb
|
|
except Exception as e:
|
|
log(f"videoclub_buscador import error: {e}")
|
|
enviar("❌ No se pudo cargar el modulo videoclub", chat_id)
|
|
return
|
|
enviar(f"🔎 Buscando <b>{nombre}</b> en el catálogo...", chat_id)
|
|
try:
|
|
resultados = vcb.buscar_peliculas(nombre)
|
|
mensajes = vcb.formatear_peliculas(resultados)
|
|
except Exception as e:
|
|
log(f"buscador pelicula error: {e}")
|
|
enviar(f"❌ Error consultando el catálogo: {e}", chat_id)
|
|
return
|
|
for m in mensajes:
|
|
enviar(m, chat_id)
|
|
if resultados:
|
|
log(f"BUSCADOR pelis '{nombre}': {len(resultados)} resultados")
|
|
|
|
|
|
def procesar_buscador_serie(nombre, chat_id):
|
|
"""Busca series por nombre y muestra temporadas/capitulos numerados."""
|
|
try:
|
|
sys.path.insert(0, os.path.join(BASE, "..", "videoclub"))
|
|
import videoclub_buscador as vcb
|
|
except Exception as e:
|
|
log(f"videoclub_buscador import error: {e}")
|
|
enviar("❌ No se pudo cargar el modulo videoclub", chat_id)
|
|
return
|
|
enviar(f"🔎 Buscando serie <b>{nombre}</b> en el catálogo...", chat_id)
|
|
try:
|
|
grupos = vcb.buscar_series(nombre)
|
|
mensajes = vcb.formatear_series(grupos)
|
|
except Exception as e:
|
|
log(f"buscador serie error: {e}")
|
|
enviar(f"❌ Error consultando el catálogo: {e}", chat_id)
|
|
return
|
|
for m in mensajes:
|
|
enviar(m, chat_id)
|
|
if grupos:
|
|
total_eps = sum(len(v) for v in grupos.values())
|
|
log(f"BUSCADOR series '{nombre}': {len(grupos)} series, {total_eps} capitulos")
|
|
|
|
|
|
def procesar_novedades(chat_id):
|
|
"""Muestra las ultimas novedades del catalogo."""
|
|
try:
|
|
sys.path.insert(0, os.path.join(BASE, "..", "videoclub"))
|
|
import videoclub_buscador as vcb
|
|
except Exception as e:
|
|
log(f"videoclub_buscador import error: {e}")
|
|
enviar("❌ No se pudo cargar el modulo videoclub", chat_id)
|
|
return
|
|
enviar("🎬 Consultando ultimas novedades...", chat_id)
|
|
try:
|
|
items = vcb.generar_novedades()
|
|
mensajes = vcb.formatear_novedades(items)
|
|
except Exception as e:
|
|
log(f"novedades error: {e}")
|
|
enviar(f"❌ Error consultando el catálogo: {e}", chat_id)
|
|
return
|
|
for m in mensajes:
|
|
enviar(m, chat_id)
|
|
|
|
|
|
def _int_arg(texto):
|
|
"""Extrae el numero de un comando tipo '/bajar 3'."""
|
|
partes = texto.split()
|
|
for p in partes[1:]:
|
|
if p.isdigit():
|
|
return int(p)
|
|
return None
|
|
|
|
|
|
def _import_global_buscar():
|
|
sys.path.insert(0, os.path.join(BASE, "..", "videoclub"))
|
|
import global_buscar as gol
|
|
return gol
|
|
|
|
|
|
def procesar_busca(nombre, chat_id):
|
|
"""Busqueda global (Cinemeta): texto -> titulos con id IMDb numerados."""
|
|
try:
|
|
gol = _import_global_buscar()
|
|
except Exception as e:
|
|
log(f"global_buscar import error: {e}")
|
|
enviar("❌ No se pudo cargar el modulo de busqueda global", chat_id)
|
|
return
|
|
enviar(f"🔎 Buscando <b>{nombre}</b> en todo el catalogo online...", chat_id)
|
|
try:
|
|
resultados = gol.buscar_titulos(nombre)
|
|
mensajes = gol.formatear_titulos(resultados)
|
|
except Exception as e:
|
|
log(f"busca error: {e}")
|
|
enviar(f"❌ Error en la busqueda: {e}", chat_id)
|
|
return
|
|
for m in mensajes:
|
|
enviar(m, chat_id)
|
|
if resultados:
|
|
ultima_titulos[chat_id] = {"query": nombre, "results": resultados}
|
|
log(f"BUSCA global '{nombre}': {len(resultados)} titulos")
|
|
|
|
|
|
def procesar_torrents(n, chat_id):
|
|
"""Muestra los torrents (Torrentio) del titulo numero n de la ultima busqueda."""
|
|
estado = ultima_titulos.get(chat_id)
|
|
if not estado or n is None or n < 1 or n > len(estado["results"]):
|
|
enviar("Primero usa <b>/busca <nombre></b> y luego "
|
|
"<b>/torrents <numero></b>.", chat_id)
|
|
return
|
|
try:
|
|
gol = _import_global_buscar()
|
|
except Exception as e:
|
|
log(f"global_buscar import error: {e}")
|
|
enviar("❌ No se pudo cargar el modulo", chat_id)
|
|
return
|
|
r = estado["results"][n - 1]
|
|
enviar(f"🧲 Buscando torrents de <b>{r['name']}</b>...", chat_id)
|
|
try:
|
|
torrents = gol.torrents_de(r["imdb_id"], r["type"])
|
|
torrents = gol.filtrar_torrents(torrents)
|
|
mensajes = gol.formatear_torrents(torrents, r["name"])
|
|
except Exception as e:
|
|
log(f"torrents error: {e}")
|
|
enviar(f"❌ Error obteniendo torrents: {e}", chat_id)
|
|
return
|
|
for m in mensajes:
|
|
enviar(m, chat_id)
|
|
if torrents:
|
|
ultimos_torrents[chat_id] = {"titulo": r["name"], "torrents": torrents}
|
|
log(f"TORRENTS '{r['name']}': {len(torrents)} torrents")
|
|
|
|
|
|
def procesar_bajar(n, chat_id):
|
|
"""Descarga el torrent numero n al NAS (Download Station via magnet)."""
|
|
estado = ultimos_torrents.get(chat_id)
|
|
if not estado or n is None or n < 1 or n > len(estado["torrents"]):
|
|
enviar("Primero usa <b>/busca <nombre></b> y luego "
|
|
"<b>/torrents <numero></b>.", chat_id)
|
|
return
|
|
try:
|
|
gol = _import_global_buscar()
|
|
except Exception as e:
|
|
log(f"global_buscar import error: {e}")
|
|
enviar("❌ No se pudo cargar el modulo", chat_id)
|
|
return
|
|
t = estado["torrents"][n - 1]
|
|
magnet = gol.magnet_de(t)
|
|
log(f"BAJAR '{estado['titulo']}' torrent {n}: {magnet[:60]}...")
|
|
try:
|
|
import nas_dl
|
|
ok = nas_dl.add_torrent(magnet)
|
|
except Exception as e:
|
|
log(f"bajar error: {e}")
|
|
enviar(f"❌ Error al anadir al NAS: {e}", chat_id)
|
|
return
|
|
if ok:
|
|
tamaño = f"{t['size']:.1f}GB" if t.get("size") else "?"
|
|
enviar(f"📥 Añadido al NAS: <b>{t['filename'] or estado['titulo']}</b> "
|
|
f"({t['calidad']}, {tamaño}).", chat_id)
|
|
else:
|
|
enviar("❌ No se pudo añadir al NAS.", chat_id)
|
|
|
|
|
|
def monitor_temperatura():
|
|
while True:
|
|
time.sleep(300)
|
|
msg, temp_c = estado()
|
|
if temp_c is not None and temp_c > ALERTA_TEMP:
|
|
enviar(f"🚨 ALERTA: la Pi está a <b>{temp_c:.1f}°C</b> "
|
|
f"(límite {ALERTA_TEMP}°C)\n{msg}", CHAT_ID)
|
|
|
|
|
|
def cargar_offset():
|
|
try:
|
|
with open(OFFSET_FILE) as f:
|
|
return int(f.read().strip())
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def guardar_offset(offset):
|
|
try:
|
|
with open(OFFSET_FILE, "w") as f:
|
|
f.write(str(offset))
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def main():
|
|
if not TOKEN:
|
|
print("Falta TELEGRAM_TOKEN en .env")
|
|
return
|
|
threading.Thread(target=monitor_temperatura, daemon=True).start()
|
|
offset = cargar_offset()
|
|
log("Bot iniciado" + (f" (offset {offset})" if offset else ""))
|
|
print("Bot iniciado. Esperando mensajes...")
|
|
while True:
|
|
try:
|
|
params = {"timeout": 25}
|
|
if offset:
|
|
params["offset"] = offset
|
|
r = requests.get(
|
|
f"https://api.telegram.org/bot{TOKEN}/getUpdates",
|
|
params=params, timeout=35,
|
|
).json()
|
|
for upd in r.get("result", []):
|
|
offset = upd["update_id"] + 1
|
|
guardar_offset(offset)
|
|
log(f"UPDATE {upd.get('update_id')}")
|
|
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)
|
|
except Exception as e:
|
|
log(f"ERROR {e}")
|
|
print("Error:", e)
|
|
time.sleep(3)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|