Files

149 lines
5.1 KiB
Python

"""
nas_dl.py — Anade descargas al NAS Synology via API de Download Station.
Usado por pi_bot.py (comando 'descargar') y por videoclub.py.
Login: POST /webapi/auth.cgi (SYNO.API.Auth, version 6, session DownloadStation)
Crear: POST /webapi/DownloadStation/task.cgi (SYNO.DownloadStation.Task, create)
La URI puede ser un enlace HTTP directo (p. ej. enlace de RealDebrid),
un magnet o una URL de fichero .torrent.
"""
import json
import os
import urllib.parse
import urllib.request
# Carga .env del directorio del script si existe (no requiere python-dotenv)
BASE = os.path.dirname(os.path.abspath(__file__))
def _load_env(path):
env = {}
try:
for line in open(path):
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(os.path.join(BASE, ".env"))
# Respaldo: si no hay credenciales NAS aqui, probar el .env de videoclub/
_VIDEOCLUB_ENV = _load_env(os.path.join(BASE, "..", "videoclub", ".env"))
for _k in ("NAS_HOST", "NAS_PORT", "NAS_USER", "NAS_PASS", "NAS_HTTPS",
"TORRENTIO_RD_TOKEN"):
if not ENV.get(_k):
ENV[_k] = _VIDEOCLUB_ENV.get(_k, "")
NAS_HOST = os.getenv("NAS_HOST", ENV.get("NAS_HOST", "192.168.50.31")).strip().rstrip("/")
NAS_PORT = os.getenv("NAS_PORT", ENV.get("NAS_PORT", "5000")).strip()
NAS_USER = os.getenv("NAS_USER", ENV.get("NAS_USER", "")).strip()
NAS_PASS = os.getenv("NAS_PASS", ENV.get("NAS_PASS", "")).strip()
NAS_HTTPS = os.getenv("NAS_HTTPS", ENV.get("NAS_HTTPS", "0")).strip() == "1"
RD_TOKEN = os.getenv("TORRENTIO_RD_TOKEN", ENV.get("TORRENTIO_RD_TOKEN", "")).strip()
BASE_URL = f"{'https' if NAS_HTTPS else 'http'}://{NAS_HOST}:{NAS_PORT}"
def unrestrict_rd(uri):
"""Convierte un enlace real-debrid.com/d/XXX en el enlace directo descargable.
Si el enlace no es de RealDebrid, lo devuelve tal cual."""
if "real-debrid.com/" not in uri:
return uri
if not RD_TOKEN:
print("[RD] Falta TORRENTIO_RD_TOKEN en .env")
return uri
try:
data = urllib.parse.urlencode({"link": uri}).encode()
req = urllib.request.Request(
"https://api.real-debrid.com/rest/1.0/unrestrict/link",
data=data, headers={"Authorization": f"Bearer {RD_TOKEN}"})
with urllib.request.urlopen(req, timeout=30) as r:
d = json.loads(r.read().decode("utf-8"))
directo = d.get("download")
if directo:
print(f"[RD] Desrestrict OK: {directo[:80]}")
return directo
print(f"[RD] No devolvio enlace directo: {d.get('error', d)}")
except Exception as e:
print(f"[RD] Error desrestrict: {e}")
return uri
def _api(path, params, session=None):
"""Llama a la API del NAS. DSM 7 exige GET con `_sid` en la query string.
Si `session` viene como 'sid=<x>' se extrae y se anade a la query."""
sid = None
if session:
if session.startswith("sid="):
sid = session[4:]
elif session.startswith("_sid="):
sid = session[5:]
if sid:
params = dict(params)
params["_sid"] = sid
qs = urllib.parse.urlencode(params)
req = urllib.request.Request(f"{BASE_URL}{path}?{qs}",
headers={"Cookie": session or ""})
with urllib.request.urlopen(req, timeout=20) as r:
return json.loads(r.read().decode())
def login():
"""Devuelve la cookie de sesion DownloadStation o None."""
if not NAS_USER or not NAS_PASS:
print("[NAS] Faltan NAS_USER/NAS_PASS en .env")
return None
try:
r = _api("/webapi/auth.cgi", {
"api": "SYNO.API.Auth",
"version": "6",
"method": "login",
"account": NAS_USER,
"passwd": NAS_PASS,
"session": "DownloadStation",
"format": "cookie",
})
if r.get("success"):
sid = r.get("data", {}).get("sid")
return f"sid={sid}" if sid else None
print(f"[NAS] Login fallido: {r.get('error')}")
except Exception as e:
print(f"[NAS] Error de login: {e}")
return None
def add_torrent(uri, session=None):
"""Anade una URI (http/magnet/.torrent) a Download Station.
Si es enlace de RealDebrid, primero se desrestricta a enlace directo."""
uri = unrestrict_rd(uri)
if not session:
session = login()
if not session:
return False
try:
r = _api("/webapi/DownloadStation/task.cgi", {
"api": "SYNO.DownloadStation.Task",
"version": "3",
"method": "create",
"uri": uri,
}, session=session)
if r.get("success"):
print(f"[NAS] Tarea anadida: {uri[:80]}")
return True
print(f"[NAS] Error al anadir tarea: {r.get('error')}")
except Exception as e:
print(f"[NAS] Error: {e}")
return False
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Uso: python nas_dl.py <uri|magnet|enlace>")
sys.exit(1)
ok = add_torrent(sys.argv[1])
sys.exit(0 if ok else 1)