From 0483cd05348dd61cefc55fdefdc195afbc28c5ef Mon Sep 17 00:00:00 2001 From: TRaSH Date: Sat, 3 Oct 2020 17:03:59 +0200 Subject: [PATCH] Added: WtFnZb-Renamer Added: WtFnZb-Renamer --- NZBGet/scripts/README.md | 1 + .../scripts/WtFnZb-Renamer/WtFnZb-Renamer.py | 151 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 NZBGet/scripts/WtFnZb-Renamer/WtFnZb-Renamer.py diff --git a/NZBGet/scripts/README.md b/NZBGet/scripts/README.md index d7c342efd..e8158b5e5 100644 --- a/NZBGet/scripts/README.md +++ b/NZBGet/scripts/README.md @@ -4,4 +4,5 @@ - Clean = Cleans the NZB name by removing the retagged stuff (-Obfuscated, -postbox, etc). - HashRenamer = Renames hashed media files to match the source NZB. +- WtFnZb-Renamer = This extensions extracts obfuscated filenames from .nzb files diff --git a/NZBGet/scripts/WtFnZb-Renamer/WtFnZb-Renamer.py b/NZBGet/scripts/WtFnZb-Renamer/WtFnZb-Renamer.py new file mode 100644 index 000000000..5eadc8ef2 --- /dev/null +++ b/NZBGet/scripts/WtFnZb-Renamer/WtFnZb-Renamer.py @@ -0,0 +1,151 @@ +#!/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(u'[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.*\[PRiVATE\]-\[WtFnZb\]-)' + r'\[(?P\d+)\]-\[(?P\d+)\/(?P.{3,}?)\]' + r'\s+-\s+""\s+yEnc\s+', + re.MULTILINE | re.UNICODE), + re.compile(r'^(?P.*\[PRiVATE\]-\[WtFnZb\]-)' + r'\[(?P.{3,}?)\]-\[(?P\d+)/(?P\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(u'[ERROR] NZBGet setting FileNaming (under Download Queue) ' + u'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(u'[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(u'[DETAIL] No subject in , 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(u'[INFO] No pattern matching subject, exiting.') + sys.exit(POSTPROCESS_NONE) + elif len(matched) > 1: + print(u'[ERROR] Multiple patterns matched, exiting.') + sys.exit(POSTPROCESS_ERROR) + else: + match = matched[0].groupdict() + + if match['filename'].lower().endswith('.par2'): + print(u'[INFO] par2 exists, exiting') + sys.exit(POSTPROCESS_NONE) + + if int(match['segment']) > int(match['total']): + print(u'[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'] = u'{}.{}'.format(file_count, match['filename']) + + filenames.add(match['filename']) + + s = u'WtFnZb "{filename}" yEnc ({segment}/{total})'.format( + filename = match['filename'], + segment = match['segment'], + total = match['total']) + + print(u'[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(u'[WARNING] No subject changed, exiting.') + sys.exit(POSTPROCESS_NONE) + +if len(totals) != 1: + print(u'[WARNING] Mixed values for number of total segments, exiting.') + sys.exit(POSTPROCESS_NONE) + +if totals.pop() != file_count: + print(u'[WARNING] Listed segment count does not match count, exiting.') + sys.exit(POSTPROCESS_NONE) + +org = u'{}.wtfnzb.original.processed'.format(nzb) +exists_counter = 0 +while os.path.exists(org): + exists_counter += 1 + org = u'{}.{}.wtfnzb.original.processed'.format(nzb, exists_counter) + +print(u'[INFO] Preserving original nzb as {}'.format(org)) +os.rename(nzb, org) + +print(u'[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)