TRaSH-Guides/docs/Downloaders/NZBGet/scripts/WtFnZb-Renamer/WtFnZb-Renamer.py

164 lines
4.7 KiB
Python

#!/usr/bin/env python3
### NZBGET SCAN SCRIPT
# Extract filenames from subjects containing [PRiVATE]-[WtFnZb]
#
# This extensions extracts obfuscated filenames from .nzb files
# created by WtFnZb.
#
# Supported subject formats:
#
# - [PRiVATE]-[WtFnZb]-[filename]-[1/5] - "" yEnc 0 (1/1)"
#
# - [PRiVATE]-[WtFnZb]-[5]-[1/filename] - "" yEnc
#
#
# NOTE: Requires Python and lxml (sudo apt install python3-lxml python-lxml)
#
### NZBGET SCAN SCRIPT
import sys
import os
import re
# Exit codes used by NZBGet
POSTPROCESS_SUCCESS = 93
POSTPROCESS_NONE = 95
POSTPROCESS_ERROR = 94
try:
from lxml import etree
except ImportError:
print(
'[ERROR] Python lxml required. Please install with "sudo apt install python-lxml" or "pip install lxml".'
)
sys.exit(POSTPROCESS_ERROR)
patterns = (
re.compile(
r"^(?P<prefix>.*\[PRiVATE\]-\[WtFnZb\]-)"
r"\[(?P<total>\d+)\]-\[(?P<segment>\d+)\/(?P<filename>.{3,}?)\]"
r'\s+-\s+""\s+yEnc\s+',
re.MULTILINE | re.UNICODE,
),
re.compile(
r"^(?P<prefix>.*\[PRiVATE\]-\[WtFnZb\]-)"
r"\[(?P<filename>.{3,}?)\]-\[(?P<segment>\d+)/(?P<total>\d+)\]"
r'\s+-\s+""\s+yEnc\s+',
re.MULTILINE | re.UNICODE,
),
)
nzb_dir = os.getenv("NZBNP_DIRECTORY")
nzb_filename = os.getenv("NZBNP_FILENAME")
nzb_name = os.getenv("NZBNP_NZBNAME")
nzb_file_naming = os.getenv("NZBOP_FILENAMING")
if nzb_dir is None or nzb_filename is None or nzb_name is None:
print("Please run as NZBGet plugin")
sys.exit(POSTPROCESS_ERROR)
if nzb_file_naming is not None and nzb_file_naming.lower() != "nzb":
print(
"[ERROR] NZBGet setting FileNaming (under Download Queue) "
'must be set to "Nzb" for this extension to work correctly, exiting.'
)
sys.exit(POSTPROCESS_ERROR)
if not os.path.exists(nzb_dir):
print("[ERROR] NZB directory doesn't exist, exiting")
sys.exit(POSTPROCESS_ERROR)
if not nzb_filename.lower().endswith(".nzb"):
print("[ERROR] {} is not a .nzb file.".format(nzb_filename))
sys.exit(POSTPROCESS_ERROR)
nzb = os.path.join(nzb_dir, nzb_filename)
if not os.path.exists(nzb):
print("[ERROR] {nzb} doesn't exist, exiting".format(nzb=nzb))
sys.exit(POSTPROCESS_ERROR)
with open(nzb, mode="rb") as infile:
tree = etree.parse(infile)
changed = False
file_count = 0
totals = set()
filenames = set()
for f in tree.getiterator("{http://www.newzbin.com/DTD/2003/nzb}file"):
subject = f.get("subject")
if subject is None:
print("[DETAIL] No subject in <file>, skipping")
continue
file_count += 1
result = [re.match(pattern, subject) for pattern in patterns]
matched = [m for m in result if m is not None]
if len(matched) == 0:
print("[INFO] No pattern matching subject, exiting.")
sys.exit(POSTPROCESS_NONE)
elif len(matched) > 1:
print("[ERROR] Multiple patterns matched, exiting.")
sys.exit(POSTPROCESS_ERROR)
else:
match = matched[0].groupdict()
if match["filename"].lower().endswith(".par2"):
print("[INFO] par2 exists, exiting")
sys.exit(POSTPROCESS_NONE)
if int(match["segment"]) > int(match["total"]):
print("[DETAIL] Segment index is greater then total, skipping")
continue
# NZBGet subject parsing changes when duplicate filenames are present
# prefix duplicates to avoid that
if match["filename"] in filenames:
match["filename"] = "{}.{}".format(file_count, match["filename"])
filenames.add(match["filename"])
s = 'WtFnZb "{filename}" yEnc ({segment}/{total})'.format(
filename=match["filename"], segment=match["segment"], total=match["total"]
)
print("[INFO] New subject {subject}".format(subject=s.encode("ascii", "ignore")))
f.set("subject", s)
changed = True
totals.add(int(match["total"]))
if not changed:
print("[WARNING] No subject changed, exiting.")
sys.exit(POSTPROCESS_NONE)
if len(totals) != 1:
print("[WARNING] Mixed values for number of total segments, exiting.")
sys.exit(POSTPROCESS_NONE)
if totals.pop() != file_count:
print("[WARNING] Listed segment count does not match <file> count, exiting.")
sys.exit(POSTPROCESS_NONE)
org = "{}.wtfnzb.original.processed".format(nzb)
exists_counter = 0
while os.path.exists(org):
exists_counter += 1
org = "{}.{}.wtfnzb.original.processed".format(nzb, exists_counter)
print("[INFO] Preserving original nzb as {}".format(org))
os.rename(nzb, org)
print("[INFO] Writing {}".format(nzb))
with open(nzb, mode="wb") as outfile:
outfile.write(
etree.tostring(
tree,
xml_declaration=True,
encoding=tree.docinfo.encoding,
doctype=tree.docinfo.doctype,
)
)
sys.exit(POSTPROCESS_SUCCESS)