#!/usr/bin/env python3 """ SABnzbd Post-Processing Script — UNFR Mark HS ===================================================== En cas d'échec de vérification/réparation (statut 1), parse le NZB original (gzippé) pour extraire le randomid depuis et appelle l'API UNFR markhs. Installation : 1. Éditez la variable API_KEY ci-dessous avec votre clé UNFR. 2. Copiez ce script dans le dossier "scripts" de SABnzbd. 3. Rendez le script exécutable (chmod +x sabnzbd_markhs.py) si vous êtes sous Linux/macOS. 4. Dans SABnzbd → Config → Dossiers → Dossier des scripts, assurez-vous que le dossier est correct. 5. Assignez ce script à la catégorie voulue (ou en post-processing par défaut). Variables d'environnement SABnzbd utilisées : SAB_ORIG_NZB_GZ = Chemin vers le NZB original compressé (.nzb.gz) Arguments positionnels SABnzbd : 7 = Statut post-processing (1 = échec vérification/réparation) """ import sys import os import gzip import xml.etree.ElementTree as ET import urllib.request import urllib.parse import urllib.error # ────────────────────────────────────────────── # CONFIGURATION UNFR # ────────────────────────────────────────────── # Remplacez "METTRE_VOTRE_CLE_ICI" par votre clé API UNFR API_KEY = "METTRE_VOTRE_CLE_ICI" API_BASE_URL = "https://unfr.pw/api_verif_hs.php" # ────────────────────────────────────────────── def log_info(msg): """Affiche un message d'information visible dans les logs SABnzbd.""" print(f"[INFO] {msg}", flush=True) def log_error(msg): """Affiche un message d'erreur visible dans les logs SABnzbd.""" print(f"[ERROR] {msg}", flush=True) def extract_randomid(nzb_gz_path): """ Décompresse le NZB gzippé, parse le XML et retourne la valeur de .... """ log_info(f"Lecture NZB : {nzb_gz_path}") with gzip.open(nzb_gz_path, "rb") as f: xml_data = f.read() root = ET.fromstring(xml_data) # Le namespace NZB standard ns = {"nzb": "http://www.newzbin.com/DTD/2003/nzb"} # Cherche value avec namespace for meta in root.findall(".//nzb:head/nzb:meta", ns): if meta.get("type") == "tag" and meta.text: return meta.text.strip() # Fallback sans namespace (certains NZB n'en ont pas) for meta in root.findall(".//head/meta"): if meta.get("type") == "tag" and meta.text: return meta.text.strip() # Dernier fallback : chercher partout for meta in root.iter(): tag_local = meta.tag.split("}")[-1] if "}" in meta.tag else meta.tag if tag_local == "meta" and meta.get("type") == "tag" and meta.text: return meta.text.strip() return None def call_markhs(randomid, extra_info=""): """Appelle l'API UNFR pour marquer la release HS.""" params = { "apikey": API_KEY, "action": "markhs", "randomid": randomid, } if extra_info: params["extra_info"] = extra_info query = urllib.parse.urlencode(params, quote_via=urllib.parse.quote) url = f"{API_BASE_URL}?{query}" # Masquage de la clé API et décodage pour un affichage propre dans les logs log_url = url.replace(API_KEY, "***") log_info(f"Appel API : {urllib.parse.unquote(log_url)}") try: req = urllib.request.Request(url, method="GET") with urllib.request.urlopen(req, timeout=30) as resp: body = resp.read().decode("utf-8", errors="replace") log_info(f"Réponse API ({resp.status}) : {body[:500]}") return resp.status == 200 except urllib.error.HTTPError as e: body = e.read().decode("utf-8", errors="replace") log_error(f"Erreur HTTP {e.code} : {e.reason} | body={body[:500]}") except urllib.error.URLError as e: log_error(f"Erreur réseau : {e.reason}") except Exception as e: log_error(f"Erreur inattendue : {e}") return False def main(): log_info(f"Script démarré - python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}") if len(sys.argv) < 8: log_error("Pas assez d'arguments — ce script doit être lancé par SABnzbd lors du post-processing.") sys.exit(0) clean_name = sys.argv[3] category = sys.argv[5] status = sys.argv[7] log_info(f"Job : {clean_name}") log_info(f"Catégorie : {category}") log_info(f"Statut : {status}") # ── Seul le statut 1 (échec vérification/réparation) nous intéresse ── if status != "1": log_info("Statut non concerné (téléchargement réussi) — rien à signaler.") sys.exit(0) if API_KEY == "METTRE_VOTRE_CLE_ICI" or not API_KEY: log_error("L'API Key n'a pas été configurée dans le script. Veuillez éditer sabnzbd_markhs.py.") sys.exit(0) # ── Récupérer le chemin du NZB gzippé ── nzb_gz_path = os.environ.get("SAB_ORIG_NZB_GZ", "") if not nzb_gz_path or not os.path.isfile(nzb_gz_path): log_error(f"SAB_ORIG_NZB_GZ introuvable ou invalide ({nzb_gz_path})") sys.exit(0) # ── Extraire le randomid depuis ── try: randomid = extract_randomid(nzb_gz_path) except Exception as e: log_error(f"Erreur lors du parsing du fichier NZB : {e}") sys.exit(0) if not randomid: log_info("Aucune balise trouvée dans le NZB. Abandon.") sys.exit(0) log_info(f"Random ID : {randomid}") # ── Appel API ── extra_info = f"SABnzbd: Echec verification / reparation | job={clean_name}" success = call_markhs(randomid, extra_info) if success: log_info("Release marquée HS avec succès sur UNFR.") else: log_error("Impossible de marquer la release HS sur UNFR.") sys.exit(0) if __name__ == "__main__": main()