03-sep: [videoclub] Busqueda global (miles de pelis) via Cinemeta+Torrentio con /busca /torrents /bajar a NAS
This commit is contained in:
67
documentacion/guia-busqueda-global-videoclub-2026-09-03.md
Normal file
67
documentacion/guia-busqueda-global-videoclub-2026-09-03.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Guía — Búsqueda global del videoclub (miles de películas)
|
||||||
|
|
||||||
|
**Fecha:** 3 Septiembre 2026
|
||||||
|
**Autor:** asistente laboratorio
|
||||||
|
|
||||||
|
## Qué resuelve
|
||||||
|
|
||||||
|
El catálogo de Torrentio/RealDebrid (`/pelicula`, `/serie`) solo muestra lo que
|
||||||
|
**ya tienes** en tu cuenta de RealDebrid (tus 51 items). Para buscar películas y
|
||||||
|
series que **NO tienes todavía** —es decir, "miles de películas" de todo
|
||||||
|
internet— se añade la **búsqueda global** con los comandos `/busca`, `/torrents`
|
||||||
|
y `/bajar`.
|
||||||
|
|
||||||
|
## Cómo funciona (2 pasos internos)
|
||||||
|
|
||||||
|
```
|
||||||
|
/busca <texto>
|
||||||
|
↓ Cinemeta (Stremio, sin clave): texto → títulos + id IMDb
|
||||||
|
1. Interstellar tt0816692
|
||||||
|
2. The Science of... tt4415360
|
||||||
|
↓ /torrents <n>
|
||||||
|
1. 4K | 7.5GB | 👤37 | Interstellar...2160p...x265-QTZ.mkv
|
||||||
|
2. 1080p| 4.2GB | 👤511| Interstellar.2014.PROPER.IMAX.1080p...
|
||||||
|
↓ /bajar <n>
|
||||||
|
Magnet → Download Station del NAS (baja y deja sembrando)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Texto → título:** `Cinemeta` (v3-cinemeta.strem.io) resuelve tu texto a los
|
||||||
|
títulos top con su id IMDb. Sin API key.
|
||||||
|
2. **Título → torrents:** `Torrentio` (/stream/movie|series/{imdb}.json) escanea
|
||||||
|
en tiempo real **1337x, PirateBay, TorrentGalaxy, Wolfmax4k, MejorTorrent...**
|
||||||
|
y devuelve decenas/cientos de torrents reales por título (de ahí las
|
||||||
|
"miles de pelis").
|
||||||
|
3. **Torrent → NAS:** construimos el `magnet` desde el `infoHash` y lo enviamos a
|
||||||
|
Synology Download Station, que se descarga la película.
|
||||||
|
|
||||||
|
## Cómo usarlo (desde Telegram)
|
||||||
|
|
||||||
|
- `/busca `<b>interstellar</b> → lista de títulos numerados
|
||||||
|
- `/torrents `2` → torrents reales del título 2 (calidad, tamaño, seeders)
|
||||||
|
- `/bajar `1` → descarga al NAS el torrent 1
|
||||||
|
|
||||||
|
Cada número se elige en un comando nuevo. El bot recuerda tu última búsqueda por
|
||||||
|
chat, así que no hace falta repetir el nombre.
|
||||||
|
|
||||||
|
## Archivos nuevos/modificados
|
||||||
|
|
||||||
|
- `videoclub/global_buscar.py` — módulo nuevo de búsqueda global
|
||||||
|
- `buscar_titulos(texto)` → Cinemeta
|
||||||
|
- `torrents_de(imdb_id, tipo)` → Torrentio
|
||||||
|
- `filtrar_torrents()` → filtra calidad mala, ruso/tamil/otros idiomas
|
||||||
|
- `magnet_de(torrent)` → magnet a partir de infoHash
|
||||||
|
- `formatear_titulos()` / `formatear_torrents()` → mensajes numerados
|
||||||
|
- `vigilancia/pi_bot.py` — comandos `/busca`, `/torrents`, `/bajar` +
|
||||||
|
estado por chat
|
||||||
|
- Reutiliza `vigilancia/nas_dl.py` (Download Station) y
|
||||||
|
`videoclub/videoclub_buscador.py` (filtros de idioma/calidad)
|
||||||
|
|
||||||
|
## Notas
|
||||||
|
|
||||||
|
- Los filtros quitan CAMrips, y releases en ruso/tamil/hindi/etc. para quedarse
|
||||||
|
con contenido en **castellano o inglés**.
|
||||||
|
- Los resultados se ordenan por calidad (4K → 1080p → 720p) y luego por seeders.
|
||||||
|
- Torrentio consulta muchos proveedores en tiempo real: para títulos raros puede
|
||||||
|
tardar unos segundos o devolver pocos resultados.
|
||||||
|
- Para desplegar en la Pi: `git pull` + reiniciar el servicio `pi-bot`
|
||||||
|
(la búsqueda global necesita que `np`/`python` tenga salida a internet).
|
||||||
223
videoclub/global_buscar.py
Normal file
223
videoclub/global_buscar.py
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
"""
|
||||||
|
global_buscar.py — Busqueda GLOBAL de peliculas/series que NO estan en tu
|
||||||
|
biblioteca RealDebrid. Busca "miles de pelis" en internet.
|
||||||
|
|
||||||
|
Flujo (2 pasos, sin estado persistente):
|
||||||
|
1) Texto -> titulo: Cinemeta (Stremio, sin clave) devuelve los titulos
|
||||||
|
mas relevantes con su id IMDb (ttXXXXXXX).
|
||||||
|
2) Titulo -> torrente: Torrentio (Stremio) devuelve los torrents reales
|
||||||
|
scaneados de 1337x, TPB, TorrentGalaxy, Wolfmax4k, ...
|
||||||
|
cada uno con infoHash para montar el magnet.
|
||||||
|
|
||||||
|
Zona "miles de peliculas": Torrentio consulta decenas de proveedores en
|
||||||
|
tiempo real y devuelve cientos de stream por titulo, no solo tu biblioteca.
|
||||||
|
|
||||||
|
Bajar a NAS: ./nas_dl.py "<magnet>" (Download Station se encarga).
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BASE = Path(__file__).resolve().parent
|
||||||
|
sys.path.insert(0, str(BASE))
|
||||||
|
|
||||||
|
CINEMETA = "https://v3-cinemeta.strem.io"
|
||||||
|
TORRENTIO = "https://torrentio.strem.fun/language=spanish"
|
||||||
|
|
||||||
|
HEADERS = {"User-Agent": "Mozilla/5.0"}
|
||||||
|
|
||||||
|
# Utilidades de clasificacion reutilizadas de videoclub_buscador
|
||||||
|
import videoclub_buscador as vcb
|
||||||
|
|
||||||
|
# Idiomas que no interesan en el catalogo global (ruso, tamil, hindi, etc.)
|
||||||
|
OTRO_IDIOMA_GLOBAL = re.compile(
|
||||||
|
r"(Tamil|Hindi|Telugu|Malayalam|Turkish|Tur[cç]e|Zulu|Arabic|"
|
||||||
|
r"Cyrillic|Russian|Greek|Korean|Chinese|Japanese|Thai)",
|
||||||
|
re.IGNORECASE)
|
||||||
|
RUSO = re.compile(r"[а-яА-ЯёЁ]")
|
||||||
|
|
||||||
|
|
||||||
|
def _get_json(url, timeout=35):
|
||||||
|
req = urllib.request.Request(url, headers=HEADERS)
|
||||||
|
with urllib.request.urlopen(req, timeout=timeout) as r:
|
||||||
|
return json.loads(r.read().decode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def buscar_titulos(termino, limite=10):
|
||||||
|
"""Texto -> lista de {name, type, imdb_id, year}. Usa Cinemeta (sin clave)."""
|
||||||
|
term = (termino or "").strip()
|
||||||
|
if not term:
|
||||||
|
return []
|
||||||
|
resultado, lista = [], []
|
||||||
|
for _type in ("movie", "series"):
|
||||||
|
url = (f"{CINEMETA}/catalog/{_type}/top/"
|
||||||
|
f"search={urllib.parse.quote(term)}.json")
|
||||||
|
try:
|
||||||
|
metas = _get_json(url).get("metas", [])
|
||||||
|
except Exception:
|
||||||
|
metas = []
|
||||||
|
for m in metas[:limite]:
|
||||||
|
imdb = m.get("id", "")
|
||||||
|
if not re.match(r"^tt\d+$", imdb):
|
||||||
|
continue
|
||||||
|
name = m.get("name", "")
|
||||||
|
year = m.get("year") or None
|
||||||
|
resultado.append({
|
||||||
|
"name": name,
|
||||||
|
"type": _type,
|
||||||
|
"imdb_id": imdb,
|
||||||
|
"year": str(year) if year else None,
|
||||||
|
})
|
||||||
|
# Intercalamos movie/series y deduplicamos por imdb_id
|
||||||
|
vistos = set()
|
||||||
|
for r in resultado:
|
||||||
|
if r["imdb_id"] in vistos:
|
||||||
|
continue
|
||||||
|
vistos.add(r["imdb_id"])
|
||||||
|
lista.append(r)
|
||||||
|
return lista[:20]
|
||||||
|
|
||||||
|
|
||||||
|
def torrents_de(imdb_id, tipo="movie"):
|
||||||
|
"""IMDb id -> lista de torrents reales de Torrentio.
|
||||||
|
Cada item: {name, title, info_hash, file_id, filename, seeders, size}."""
|
||||||
|
if not re.match(r"^tt\d+$", imdb_id or ""):
|
||||||
|
return []
|
||||||
|
url = f"{TORRENTIO}/stream/{tipo}/{imdb_id}.json"
|
||||||
|
try:
|
||||||
|
data = _get_json(url)
|
||||||
|
except Exception:
|
||||||
|
return []
|
||||||
|
torrents = []
|
||||||
|
for s in data.get("streams", []):
|
||||||
|
if not s.get("infoHash"):
|
||||||
|
continue
|
||||||
|
filename = (s.get("behaviorHints", {}) or {}).get("filename") or ""
|
||||||
|
title = (s.get("title") or "").replace("\n", " ")
|
||||||
|
torrents.append({
|
||||||
|
"name": s.get("name", "").replace("\n", " "),
|
||||||
|
"title": title,
|
||||||
|
"info_hash": s["infoHash"],
|
||||||
|
"file_id": s.get("fileIdx", 0),
|
||||||
|
"filename": filename,
|
||||||
|
"seeders": _seeders(title),
|
||||||
|
"size": _size(title),
|
||||||
|
"calidad": _calidad(filename + " " + title),
|
||||||
|
})
|
||||||
|
return torrents
|
||||||
|
|
||||||
|
|
||||||
|
def _seeders(title):
|
||||||
|
m = re.search(r"👤\s*(\d+)", title)
|
||||||
|
return int(m.group(1)) if m else 0
|
||||||
|
|
||||||
|
|
||||||
|
def _size(title):
|
||||||
|
m = re.search(r"💾\s*([\d.]+)\s*(TB|GB|MB)", title)
|
||||||
|
if not m:
|
||||||
|
return None
|
||||||
|
val = float(m.group(1))
|
||||||
|
if m.group(2) == "TB":
|
||||||
|
return val * 1024
|
||||||
|
if m.group(2) == "MB":
|
||||||
|
return val / 1024
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
def _calidad(texto):
|
||||||
|
t = " " + texto.lower() + " "
|
||||||
|
if "2160p" in t or ("4k" in t and "1080p" not in t):
|
||||||
|
return "4K"
|
||||||
|
if "1080p" in t or "1080" in t:
|
||||||
|
return "1080p"
|
||||||
|
if "720p" in t:
|
||||||
|
return "720p"
|
||||||
|
if "4k" in t or "uhd" in t:
|
||||||
|
return "4K"
|
||||||
|
return "?"
|
||||||
|
|
||||||
|
|
||||||
|
def filtrar_torrents(torrents, limite=20):
|
||||||
|
"""Descarta calidad mala y contenido claramente no en castellano/ingles."""
|
||||||
|
utiles = []
|
||||||
|
for t in torrents:
|
||||||
|
if vcb.CALIDAD_MALA.search(t["title"]):
|
||||||
|
continue
|
||||||
|
if vcb.OTRO_IDIOMA.search(t["title"]) or OTRO_IDIOMA_GLOBAL.search(t["title"]):
|
||||||
|
continue
|
||||||
|
if RUSO.search(t["title"]):
|
||||||
|
continue
|
||||||
|
if not (vcb.CASTELLANO.search(t["title"]) or vcb.INGLES.search(t["title"])):
|
||||||
|
continue
|
||||||
|
utiles.append(t)
|
||||||
|
# Ordenar: mejor calidad, mas seeders
|
||||||
|
orden = {"4K": 0, "1080p": 1, "720p": 2, "?": 3}
|
||||||
|
utiles.sort(key=lambda t: (orden.get(t["calidad"], 3), -t["seeders"]))
|
||||||
|
return utiles[:limite]
|
||||||
|
|
||||||
|
|
||||||
|
def magnet_de(t):
|
||||||
|
"""Construye el magnet a partir del infoHash y nombre de fichero."""
|
||||||
|
dn = urllib.parse.quote((t.get("filename") or t.get("title") or "video"))
|
||||||
|
return f"magnet:?xt=urn:btih:{t['info_hash']}&dn={dn}"
|
||||||
|
|
||||||
|
|
||||||
|
def formatear_titulos(resultados):
|
||||||
|
"""Formatea resultados de Cinemeta numerados para Telegram."""
|
||||||
|
if not resultados:
|
||||||
|
return ["No se encontraron resultados para ese termino."]
|
||||||
|
lineas = [f"🎬 <b>Resultados globales ({len(resultados)}):</b>",
|
||||||
|
"Responde <b>/bajar <numero></b> para ver torrents.", ""]
|
||||||
|
for i, r in enumerate(resultados, 1):
|
||||||
|
icono = "📺" if r["type"] == "series" else "🎬"
|
||||||
|
y = f" ({r['year']})" if r.get("year") else ""
|
||||||
|
lineas.append(f"<b>{i}.</b> {icono} {r['name']}{y}")
|
||||||
|
lineas.append(f" <code>{r['imdb_id']}</code>")
|
||||||
|
return vcb.trocear_texto(lineas)
|
||||||
|
|
||||||
|
|
||||||
|
def formatear_torrents(torrents, titulo):
|
||||||
|
"""Formatea los torrents de un titulo numerados con calidad/size/seeders."""
|
||||||
|
if not torrents:
|
||||||
|
return [f"No se encontraron torrents utiles para <b>{titulo}</b>."]
|
||||||
|
lineas = [
|
||||||
|
f"🧲 <b>{titulo}</b> — {len(torrents)} torrents.",
|
||||||
|
"Responde <b>/bajar <numero></b> de estos para descargarlo al NAS.",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
for i, t in enumerate(torrents, 1):
|
||||||
|
size = f"{t['size']:.1f}GB" if t.get("size") else "?"
|
||||||
|
lineas.append(
|
||||||
|
f"<b>{i}.</b> {t['calidad']} | {size} | 👤 {t['seeders']} | {t['filename'] or t['name']}")
|
||||||
|
return vcb.trocear_texto(lineas)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Uso:")
|
||||||
|
print(" python global_buscar.py busca <texto>")
|
||||||
|
print(" python global_buscar.py torrents <imdb_id> [movie|series]")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
cmd = sys.argv[1]
|
||||||
|
if cmd == "busca":
|
||||||
|
q = " ".join(sys.argv[2:])
|
||||||
|
for m in formatear_titulos(buscar_titulos(q)):
|
||||||
|
print(m)
|
||||||
|
print("---")
|
||||||
|
elif cmd == "torrents":
|
||||||
|
imdb = sys.argv[2]
|
||||||
|
tipo = sys.argv[3] if len(sys.argv) > 3 else "movie"
|
||||||
|
res = torrents_de(imdb, tipo)
|
||||||
|
res = filtrar_torrents(res)
|
||||||
|
for m in formatear_torrents(res, imdb):
|
||||||
|
print(m)
|
||||||
|
print("---")
|
||||||
@@ -8,6 +8,10 @@ import urllib.parse
|
|||||||
|
|
||||||
import requests
|
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__))
|
BASE = os.path.dirname(os.path.abspath(__file__))
|
||||||
LOG = os.path.join(BASE, "bot.log")
|
LOG = os.path.join(BASE, "bot.log")
|
||||||
OFFSET_FILE = os.path.join(BASE, "bot.offset")
|
OFFSET_FILE = os.path.join(BASE, "bot.offset")
|
||||||
@@ -191,6 +195,15 @@ def procesar(texto, chat_id):
|
|||||||
procesar_buscador_serie(nombre, chat_id)
|
procesar_buscador_serie(nombre, chat_id)
|
||||||
elif t in ("novedades", "/novedades"):
|
elif t in ("novedades", "/novedades"):
|
||||||
procesar_novedades(chat_id)
|
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"):
|
elif t in ("ayuda", "/ayuda", "help", "/help"):
|
||||||
enviar("Comandos:\n"
|
enviar("Comandos:\n"
|
||||||
"<b>estado</b> — estado de la Pi\n"
|
"<b>estado</b> — estado de la Pi\n"
|
||||||
@@ -202,6 +215,9 @@ def procesar(texto, chat_id):
|
|||||||
"<b>pelicula <nombre></b> — buscar pelicula y descargar\n"
|
"<b>pelicula <nombre></b> — buscar pelicula y descargar\n"
|
||||||
"<b>serie <nombre></b> — buscar serie con temporadas/capitulos\n"
|
"<b>serie <nombre></b> — buscar serie con temporadas/capitulos\n"
|
||||||
"<b>novedades</b> — ultimas novedades del catalogo\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>panorama</b> — fotos de las cámaras\n"
|
||||||
"<b>limpieza</b> — limpia procesos atascados de la Pi\n"
|
"<b>limpieza</b> — limpia procesos atascados de la Pi\n"
|
||||||
"<b>reboot</b> — reinicia la Pi (necesita confirmar con /confirmar-reboot)\n"
|
"<b>reboot</b> — reinicia la Pi (necesita confirmar con /confirmar-reboot)\n"
|
||||||
@@ -371,6 +387,105 @@ def procesar_novedades(chat_id):
|
|||||||
enviar(m, chat_id)
|
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():
|
def monitor_temperatura():
|
||||||
while True:
|
while True:
|
||||||
time.sleep(300)
|
time.sleep(300)
|
||||||
|
|||||||
Reference in New Issue
Block a user