From 603cbe9c3417813e9d095040e26115affc0ba291 Mon Sep 17 00:00:00 2001 From: UNFR Date: Thu, 2 Apr 2026 08:38:56 +0000 Subject: [PATCH] Ajouter markhs.py --- markhs.py | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 markhs.py diff --git a/markhs.py b/markhs.py new file mode 100644 index 0000000..1e85045 --- /dev/null +++ b/markhs.py @@ -0,0 +1,169 @@ +#!/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() \ No newline at end of file