Skip to content

Instantly share code, notes, and snippets.

@LukeChannings
Created February 13, 2022 20:21
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • 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)
@SteffanCline
Copy link

SteffanCline commented Nov 15, 2022

Seemingly stupid question but any instructions where to drop it/configs to make in NZBGet?

I'm really hoping this solves it for me. I've had a LOT of these types of downloads that sit there waiting for me to rename the files. Do you know if for the existing ones I have, are they numbered how they fall in alphabetical order?

@LukeChannings
Copy link
Author

Not stupid. It goes in ScriptDir, the config for which can be found in nzbget’s Settings -> Paths.

In my case, it’s in ${MainDir}/scripts.

@sebastian-burlacu
Copy link

Any way to use this after the fact? I've downloaded some files and now realize they're obfuscated in this way. Can I use this script manually? Do I just have to set those environment variables myself?

@LukeChannings
Copy link
Author

History > Click on the name of the item > Actions > Post-process again

Should work, haven't tried it tho.

@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