Skip to content

Instantly share code, notes, and snippets.

@LukeChannings
Created February 13, 2022 20:21
Show Gist options
  • Save LukeChannings/49625879cb6310d68fb4cabb4ca98766 to your computer and use it in GitHub Desktop.
Save LukeChannings/49625879cb6310d68fb4cabb4ca98766 to your computer and use it in GitHub Desktop.
WtFnZb-Renamer.py
#!/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<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),
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(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 <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(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 <file> 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)
@sebastian-burlacu
Copy link

Wow thanks for the quick reply! Unfortunately I don't seem to have that option. When I look at the history, I can click on an item to view more details, but there's no actions there, and then the only possible action for it is to delete it from the history. I should be able to set those variables and run it myself right? I'll poke around and see if I can figure it out.

@Clancytwice
Copy link

Clancytwice commented Mar 2, 2024

Many thanks for the script.
Yet, for nzb to download full bluray, once all the files are properly renamed, they are all in the same folder and not in a proper blu-ray folder structure.
Any idea how to get the file automatically located in the right folder?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment