from io import BytesIO import requests import os from backend.utils import format_size, calculate_age YGG_PASSKEY = os.getenv("YGG_PASSKEY") ALLDEBRID_API_KEY = os.getenv("ALLDEBRID_API_KEY") NTFY_TOPIC_URL = os.getenv("NTFY_TOPIC_URL") NTFY_TOKEN = os.getenv("NTFY_TOKEN") MAX_SIZE_BYTES = 5*1024**3 NB_PAGES = 2 def check_alldebrid_status(): # Retourne True si premium actif, False sinon try: r = requests.get( "https://api.alldebrid.com/v4/user", params={"agent": "ygg-service", "apikey": ALLDEBRID_API_KEY}, timeout=5 ) data = r.json() return data.get("data", {}).get("user", {}).get("isPremium", False) except Exception as e: print("Erreur AllDebrid:", e) return False def send_ntfy(title, message): # Envoie une notification sur le topic ntfy, avec token si nécessaire headers = {"Title": title} if NTFY_TOKEN: headers["Authorization"] = f"Bearer {NTFY_TOKEN}" try: r = requests.post( NTFY_TOPIC_URL, data=message.encode("utf-8"), headers=headers, timeout=5 ) if r.status_code not in (200, 201): print(f"❌ Échec notification ({r.status_code}): {r.text}") else: print(f"✅ Notification envoyée : {title}") except Exception as e: print("Erreur ntfy:", e) def search_torrents(query: str, category_id: str | None = None) -> list[dict]: """Recherche des torrents sur l'API Yggtorrent, retourne la liste brute.""" url = "https://yggapi.eu/torrents" params = { "page": 1, "q": query, "order_by": "uploaded_at", "per_page": 100 } if category_id: params["category_id"] = category_id results = [] try: for page in range(1, NB_PAGES + 1): params['page'] = page r = requests.get(url, params=params, timeout=5) r.raise_for_status() data = r.json() results.extend(data) except requests.exceptions.RequestException as e: print("Erreur API Yggtorrent:", e) results = [] return results def filter_and_format_torrents(torrents: list[dict]) -> list[dict]: """Filtre les torrents trop gros et formate la taille et l'âge.""" filtered = [] for t in torrents: if t['size'] <= MAX_SIZE_BYTES: t['size'] = format_size(t['size']) days, human = calculate_age(t['uploaded_at']) t['age_days'] = days t['age_human'] = human filtered.append(t) return filtered def download_torrent_ygg(torrent_id: str) -> tuple[bytes, str]: # Télécharge le fichier .torrent depuis Yggtorrent url = f"https://yggapi.eu/torrent/{torrent_id}/download" params = { "passkey": YGG_PASSKEY, "tracker_domain": "tracker.p2p-world.net" } r = requests.get(url, params=params, timeout=10, allow_redirects=True) r.raise_for_status() filename = f"{torrent_id}.torrent" return r.content, filename def upload_to_alldebrid(torrent_content: bytes, filename: str) -> str: # Upload du torrent sur Alldebrid, retourne l'ID headers = {"Authorization": f"Bearer {ALLDEBRID_API_KEY}"} files = {'files[]': (filename, BytesIO(torrent_content))} r = requests.post("https://api.alldebrid.com/v4/magnet/upload/file", headers=headers, files=files, timeout=20) r.raise_for_status() data = r.json() if data.get("status") != "success": raise RuntimeError(f"Upload Alldebrid échoué : {data}") return data["data"]["files"][0]["id"] def get_alldebrid_links(debrid_id: str) -> list[dict]: # Récupère les liens directs Alldebrid à partir d'un ID headers = {"Authorization": f"Bearer {ALLDEBRID_API_KEY}"} # Récupération des fichiers du magnet r = requests.get("https://api.alldebrid.com/v4/magnet/files", headers=headers, params={"id[]": debrid_id}, timeout=10) r.raise_for_status() data = r.json() if data.get("status") != "success": raise RuntimeError(f"Récupération liens Alldebrid échouée : {data}") alldebrid_links = [] for magnet in data.get("data", {}).get("magnets", []): for file in magnet.get("files", []): if "e" in file: for entry in file["e"]: if "l" in entry: alldebrid_links.append(entry["l"]) elif "l" in file: alldebrid_links.append(file["l"]) # Débloquer les liens direct_links = [] for link in alldebrid_links: r2 = requests.get("https://api.alldebrid.com/v4/link/unlock", headers=headers, params={"link": link}, timeout=10) r2.raise_for_status() info = r2.json() if info.get("status") != "success": raise RuntimeError(f"Déblocage lien Alldebrid échoué : {info}") direct_links.append({ "name": info["data"]["filename"], "size": info["data"]["filesize"], "link": info["data"]["link"] }) return direct_links