Skip to content

Instantly share code, notes, and snippets.

@t0phr
Last active May 4, 2023 11:06
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save t0phr/c76496968e3a4b8e7fc2 to your computer and use it in GitHub Desktop.
Save t0phr/c76496968e3a4b8e7fc2 to your computer and use it in GitHub Desktop.
Scan script for nzbget.
#!/usr/bin/python2.7
##############################################################################
### NZBGET SCAN SCRIPT ###
#
# Scans filename of incoming NZBs for embedded passwords.
#
##############################################################################
### OPTIONS ###
# The RegEx to match the password in the filename.
#regex=(.*)\{\{(.*)\}\}.nzb
### NZBGET SCAN SCRIPT ###
##############################################################################
import re
import getopt
import sys
import os
nzbfile = os.environ.get('NZBNP_NZBNAME')
regex = os.environ.get('NZBPO_REGEX')
if nzbfile:
pattern = re.compile(regex)
match = pattern.search(nzbfile)
password = ""
name = nzbfile
if match:
name = match.group(1)
password = match.group(2)
print "[NZB] NZBNAME=" + name
if password:
print "[NZB] NZBPR_*Unpack:Password=" + password
#!/usr/bin/env python
#
# Modified E-Mail post-processing script for sending Pushbullet notifications NZBGet.
# Modified for Pushbullet on 8 October 2014.
# Copyright (C) 2014 JVM <jvmed@users.sourceforge.net>
# Copyright (C) 2014 binreader
# # # Copyright (C) 2013-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
# # #
# # # This program is free software; you can redistribute it and/or modify
# # # it under the terms of the GNU General Public License as published by
# # # the Free Software Foundation; either version 2 of the License, or
# # # (at your option) any later version.
# # #
# # # This program is distributed in the hope that it will be useful,
# # # but WITHOUT ANY WARRANTY; without even the implied warranty of
# # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# # # GNU General Public License for more details.
# # #
# # # You should have received a copy of the GNU General Public License
# # # along with this program; if not, write to the Free Software
# # # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# # #
# # # $Revision: 1031 $
# # # $Date: 2014-05-29 00:19:39 +0200 (Thu, 29 May 2014) $
# # #
##############################################################################
### NZBGET SCAN/POST-PROCESSING SCRIPT ###
# Sends Pushbullet notification.
#
# This script sends Pushbullet notification before nzb-file is added to queue and/or when the job is done.
#
# NOTE: This script requires Python installed on your system. Requires NZBGet v14+.
#
# PP-Script version: 1.1.
#
# Further discussion at: nzbget.net/forum/viewtopic.php?f=8&t=1205
#
##############################################################################
### OPTIONS ###
# Your Pushbullet Access Token.
#
# Find your Access Token at <a href="https://www.pushbullet.com/account">https://www.pushbullet.com/account</a>
#AccessToken=
# Pushbullet device(s) to send to.
#
# Leave empty to push to all devices. Can also push to individual devices by device IDs, separate each device ID by a space.
# Device IDs can be found by using cURL: curl -u your_api_key_here: https://api.pushbullet.com/api/devices
#
# More info at <a href="https://www.pushbullet.com/api">https://www.pushbullet.com/api</a>
#DeviceID=
# Pushbullet push title.
#Title=NZBGet
# Add status to title (yes, no).
#
# Adds [Received], [Success], [Failure], [Paused] states to the Pushbullet title.
#
#TitleStatus=yes
# Add NZB name to title (yes, no).
#
# Adds full NZB name to Pushbullet title, may be shortened.
#
#TitleNZB=yes
# Pushbullet push type.
#
# Leave as default. More info at <a href="https://www.pushbullet.com/api">https://www.pushbullet.com/api</a>
#Type=note
# Pushbullet API URL.
#
# Leave as default. More info at <a href="https://www.pushbullet.com/api">https://www.pushbullet.com/api</a>
#URL=https://api.pushbullet.com/api/pushes
# Enable Scan Script notification (yes, no).
#
# Send Pushbullet notification before nzb-file is added to queue.
#
# NOTE: Following options defined only when ScanScript is enabled.
#
#ScanScript=yes
# Skip certain category.
#
# Specify a category to skip for scan notifications. Pushbullet notification will not be sent when this
# category is detected. Note that post processing notifications can be set for individual categories on the
# "CATEGORIES" settings page.
# Can also put multiple categories comma separated.
#
#SkipCategory=
# Append top of queue (yes, no).
#
# Notify if added to top of queue.
#
#Top=yes
# Append added paused (yes, no).
#
# Notify if added to queue paused.
#
#Paused=yes
# Append category (yes, no).
#
#Category=yes
# Append priority (yes, no).
#
#Priority=yes
# Append source nzb URL (yes, no).
#
#SourceURL=yes
# Enable Post-Processing Script notification (yes, no).
#
# Send Pushbullet notification before nzb-file is added to queue.
#
# NOTE: Following options defined only when PPScript is enabled.
#
#PPScript=yes
# Append average download speed (yes, no).
#
#AveDownSpeed=yes
# Append download size (yes, no).
#
#DownloadSize=yes
# Append download time (yes, no).
#
#DownloadTime=yes
# Append par time (yes, no).
#
#ParTime=yes
# Append repair time (yes, no).
#
#RepairTime=yes
# Append unpack time (yes, no).
#
#UnpackTime=yes
# Append total post processing script time (yes, no).
#
#PPTime=yes
# Append total time (yes, no).
#
#TotalTime=yes
# Append list of files to the message (yes, no).
#
# Add the list of downloaded files (the content of destination directory).
#FileList=yes
# Append broken-log to the message (yes, no).
#
# Add the content of file _brokenlog.txt. This file contains the list of damaged
# files and the result of par-check/repair. For successful downloads the broken-log
# is usually deleted by cleanup-script and therefore is not sent.
#BrokenLog=yes
# Append post-processing log to the message (Always, Never, OnFailure).
#
# Add the post-processing log of active job.
#PostProcessLog=OnFailure
### NZBGET SCAN/POST-PROCESSING SCRIPT ###
##############################################################################
import os
import sys
import datetime
import urllib2
import urllib
try:
from xmlrpclib import ServerProxy # python 2
except ImportError:
from xmlrpc.client import ServerProxy # python 3
# Exit codes used by NZBGet
POSTPROCESS_SUCCESS=93
POSTPROCESS_ERROR=94
# Check if the script is called from nzbget 11.0 or later
if not 'NZBOP_SCRIPTDIR' in os.environ:
print('*** NZBGet post-processing script ***')
print('This script is supposed to be called from nzbget (11.0 or later).')
sys.exit(POSTPROCESS_ERROR)
print('[DETAIL] Script successfully started')
sys.stdout.flush()
required_options = ( 'NZBPO_SCANSCRIPT', 'NZBPO_PPSCRIPT', 'NZBPO_FILELIST', 'NZBPO_BROKENLOG', 'NZBPO_POSTPROCESSLOG',
'NZBPO_URL', 'NZBPO_ACCESSTOKEN', 'NZBPO_TYPE', 'NZBPO_TITLE', 'NZBPO_TOP', 'NZBPO_PAUSED', 'NZBPO_CATEGORY', 'NZBPO_PRIORITY',
'NZBPO_SOURCEURL', 'NZBPO_AVEDOWNSPEED', 'NZBPO_DOWNLOADTIME', 'NZBPO_DOWNLOADSIZE', 'NZBPO_PARTIME', 'NZBPO_REPAIRTIME',
'NZBPO_UNPACKTIME', 'NZBPO_PPTIME', 'NZBPO_TOTALTIME')
for optname in required_options:
if (not optname in os.environ):
print('[ERROR] Option %s is missing in configuration file. Please check script settings' % optname[6:])
sys.exit(POSTPROCESS_ERROR)
# Scan Script Notification
if 'NZBNP_DIRECTORY' in os.environ:
if os.environ['NZBPO_SCANSCRIPT'] == 'no':
print('[DETAIL] ScanScript Notification not enabled')
sys.exit(POSTPROCESS_SUCCESS)
skip_category = os.environ['NZBPO_SKIPCATEGORY'].split(',')
if len( skip_category ) > 0:
for cat in skip_category:
if os.environ['NZBNP_CATEGORY'] == cat:
print('[DETAIL] ScanScript Notification skipped')
sys.exit(POSTPROCESS_SUCCESS)
elif os.environ['NZBNP_CATEGORY'] == os.environ['NZBPO_SKIPCATEGORY']:
print('[DETAIL] ScanScript Notification skipped')
sys.exit(POSTPROCESS_SUCCESS)
print('[DETAIL] ScanScript Notification')
subject = ''
if os.environ['NZBPO_TitleStatus'] == 'yes':
subject = ' [Received]'
text = 'Received: ' + os.environ['NZBNP_NZBNAME']
if os.environ['NZBPO_TOP'] == 'yes':
if os.environ['NZBNP_TOP'] == '1':
text += '\nAdded to top of queue.'
elif os.environ['NZBNP_TOP'] == '0':
text += '\nNot added to top of queue.'
if os.environ['NZBPO_PAUSED'] == 'yes':
if os.environ['NZBNP_PAUSED'] == '1':
text += '\nNZB added as paused.'
if os.environ['NZBPO_TitleStatus'] == 'yes':
subject = ' [Paused]'
elif os.environ['NZBNP_PAUSED'] == '0':
text += '\nNZB is allowed to begin.'
if os.environ['NZBPO_CATEGORY'] == 'yes':
if len(os.environ['NZBNP_CATEGORY']) > 0:
text += '\nCategory: ' + os.environ['NZBNP_CATEGORY']
if os.environ['NZBPO_PRIORITY'] == 'yes':
if len(os.environ['NZBNP_PRIORITY']) > 0:
text += '\nPriority: ' + os.environ['NZBNP_PRIORITY']
if os.environ['NZBPO_SOURCEURL'] == 'yes':
text += '\nURL: ' + os.environ['NZBNP_URL']
if os.environ['NZBPO_TitleNZB'] == 'yes':
subject += ' ' + os.environ['NZBNP_NZBNAME']
# Post-Processing Notification
if 'NZBPP_DIRECTORY' in os.environ:
if os.environ['NZBPO_PPSCRIPT'] == 'no':
print('[DETAIL] PPScript Notification not enabled')
sys.exit(POSTPROCESS_SUCCESS)
print('[DETAIL] PPScript Notification')
###### EMail.py
success = os.environ['NZBPP_TOTALSTATUS'] == 'SUCCESS'
subject = ''
if success:
if os.environ['NZBPO_TitleStatus'] == 'yes':
subject = ' [Success]'
text = 'Download of "%s" has successfully completed.' % (os.environ['NZBPP_NZBNAME'])
else:
if os.environ['NZBPO_TitleStatus'] == 'yes':
subject = ' [Failure]'
text = 'Download of "%s" has failed.' % (os.environ['NZBPP_NZBNAME'])
if os.environ['NZBPO_TitleNZB'] == 'yes':
subject += ' ' + os.environ['NZBPP_NZBNAME']
text += '\nStatus: %s' % os.environ['NZBPP_STATUS']
# # add list of downloaded files
# if os.environ['NZBPO_FILELIST'] == 'yes':
# text += '\n\nFiles:'
# for dirname, dirnames, filenames in os.walk(os.environ['NZBPP_DIRECTORY']):
# for filename in filenames:
# text += '\n' + os.path.join(dirname, filename)[len(os.environ['NZBPP_DIRECTORY']) + 1:]
# # add _brokenlog.txt (if exists)
# if os.environ['NZBPO_BROKENLOG'] == 'yes':
# brokenlog = '%s/_brokenlog.txt' % os.environ['NZBPP_DIRECTORY']
# if os.path.exists(brokenlog):
# text += '\n\nBrokenlog:\n' + open(brokenlog, 'r').read().strip()
# add post-processing log
# if os.environ['NZBPO_POSTPROCESSLOG'] == 'Always' or \
# (os.environ['NZBPO_POSTPROCESSLOG'] == 'OnFailure' and not success):
# To get the post-processing log we connect to NZBGet via XML-RPC
# and call method "postqueue", which returns the list of post-processing job.
# The first item in the list is current job. This item has a field 'Log',
# containing an array of log-entries.
# For more info visit http://nzbget.net/RPC_API_reference
# First we need to know connection info: host, port and password of NZBGet server.
# NZBGet passes all configuration options to post-processing script as
# environment variables.
host = os.environ['NZBOP_CONTROLIP'];
port = os.environ['NZBOP_CONTROLPORT'];
username = os.environ['NZBOP_CONTROLUSERNAME'];
password = os.environ['NZBOP_CONTROLPASSWORD'];
if host == '0.0.0.0': host = '127.0.0.1'
# Build an URL for XML-RPC requests
rpcUrl = 'http://%s:%s@%s:%s/xmlrpc' % (username, password, host, port);
# Create remote server object
server = ServerProxy(rpcUrl)
###### Non EMail.py
groups = server.listgroups(0)
# Find correct nzb in method listgroups
nzbID = int(os.environ['NZBPP_NZBID'])
for i in xrange(len(groups)):
nzbGroup = groups[i]
if nzbGroup['NZBID'] == nzbID:
break
# add average download speed
if os.environ['NZBPO_AVEDOWNSPEED'] == 'yes':
DownloadedSizeMB = float(nzbGroup['DownloadedSizeMB'])
DownloadTimeSec = float(nzbGroup['DownloadTimeSec'])
if DownloadTimeSec > 0: # check x/0 errors
avespeed = (DownloadedSizeMB/DownloadTimeSec) # MB/s
unit = ' MB/s'
if avespeed < 1:
avespeed = avespeed * 1024 # KB/s
unit = ' KB/s'
text += '\nAverage download speed: %.1f' % (avespeed) + unit
# add download size
if os.environ['NZBPO_DOWNLOADSIZE'] == 'yes':
DownloadedSize = float(nzbGroup['DownloadedSizeMB'])
unit = ' MB'
if DownloadedSize > 1024:
DownloadedSize = DownloadedSize / 1024 # GB
unit = ' GB'
text += '\nDownload size: %.1f' % (DownloadedSize) + unit
# add DownloadTime
if os.environ['NZBPO_DOWNLOADTIME'] == 'yes':
DownloadTimeSec = int(nzbGroup['DownloadTimeSec'])
Hour = DownloadTimeSec/3600
Min = (DownloadTimeSec - (DownloadTimeSec/3600)*3600)/60
Sec = (DownloadTimeSec - (DownloadTimeSec/3600)*3600)%60
text += '\nDownload time: %d:%02d:%02d' % (Hour,Min,Sec)
# add ParTime
if os.environ['NZBPO_PARTIME'] == 'yes':
ParTimeSec = int(nzbGroup['ParTimeSec'])
Hour = ParTimeSec/3600
Min = (ParTimeSec - (ParTimeSec/3600)*3600)/60
Sec = (ParTimeSec - (ParTimeSec/3600)*3600)%60
text += '\nPar time: %d:%02d:%02d' % (Hour,Min,Sec)
# add RepairTime
if os.environ['NZBPO_REPAIRTIME'] == 'yes':
RepairTimeSec = int(nzbGroup['RepairTimeSec'])
Hour = RepairTimeSec/3600
Min = (RepairTimeSec - (RepairTimeSec/3600)*3600)/60
Sec = (RepairTimeSec - (RepairTimeSec/3600)*3600)%60
text += '\nRepair time: %d:%02d:%02d' % (Hour,Min,Sec)
# add UnpackTime
if os.environ['NZBPO_UNPACKTIME'] == 'yes':
UnpackTimeSec = int(nzbGroup['UnpackTimeSec'])
Hour = UnpackTimeSec/3600
Min = (UnpackTimeSec - (UnpackTimeSec/3600)*3600)/60
Sec = (UnpackTimeSec - (UnpackTimeSec/3600)*3600)%60
text += '\nUnpack time: %d:%02d:%02d' % (Hour,Min,Sec)
# add PP script, renaming and moving total time
if os.environ['NZBPO_PPTIME'] == 'yes':
PostTotalTimeSec = int(nzbGroup['PostTotalTimeSec']) - \
int(nzbGroup['ParTimeSec']) - \
int(nzbGroup['UnpackTimeSec'])
if PostTotalTimeSec < 0: # if -ve, script may not be on first run after download
PostTotalTimeSec = int(nzbGroup['PostTotalTimeSec'])
Hour = PostTotalTimeSec/3600
Min = (PostTotalTimeSec - (PostTotalTimeSec/3600)*3600)/60
Sec = (PostTotalTimeSec - (PostTotalTimeSec/3600)*3600)%60
text += '\nPP script, renaming and moving total time: %d:%02d:%02d' % (Hour,Min,Sec)
# add TotalTime
if os.environ['NZBPO_TOTALTIME'] == 'yes':
TotalTimeSec = int(nzbGroup['DownloadTimeSec']) + \
int(nzbGroup['PostTotalTimeSec'])
Hour = TotalTimeSec/3600
Min = (TotalTimeSec - (TotalTimeSec/3600)*3600)/60
Sec = (TotalTimeSec - (TotalTimeSec/3600)*3600)%60
text += '\nTotal time: %d:%02d:%02d' % (Hour,Min,Sec)
# print server.listgroups(0)[0]['TotalTimeSec']
###### EMail.py
# add list of downloaded files
if os.environ['NZBPO_FILELIST'] == 'yes':
text += '\n\nFiles:'
for dirname, dirnames, filenames in os.walk(os.environ['NZBPP_DIRECTORY']):
for filename in filenames:
text += '\n' + os.path.join(dirname, filename)[len(os.environ['NZBPP_DIRECTORY']) + 1:]
# add _brokenlog.txt (if exists)
if os.environ['NZBPO_BROKENLOG'] == 'yes':
brokenlog = '%s/_brokenlog.txt' % os.environ['NZBPP_DIRECTORY']
if os.path.exists(brokenlog):
text += '\n\nBrokenlog:\n' + open(brokenlog, 'r').read().strip()
# add post-processing log
if os.environ['NZBPO_POSTPROCESSLOG'] == 'Always' or \
(os.environ['NZBPO_POSTPROCESSLOG'] == 'OnFailure' and not success):
postqueue = server.postqueue(10000)
# Get field 'Log' from the first post-processing job
log = postqueue[0]['Log']
# Now iterate through entries and save them to message text
if len(log) > 0:
text += '\n\nPost-processing log:';
for entry in log:
text += '\n%s\t%s\t%s' % (entry['Kind'], datetime.datetime.fromtimestamp(int(entry['Time'])), entry['Text'])
# Send message
print('[DETAIL] Sending to Pushbullet')
sys.stdout.flush()
newstr = text.replace("(", "") # these brackets cause errors with cURL, don't know why, occurs with CP entries
text = newstr.replace(")", "")
try:
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, os.environ['NZBPO_URL'], os.environ['NZBPO_ACCESSTOKEN'], '')
handler = urllib2.HTTPBasicAuthHandler(password_mgr)
opener = urllib2.build_opener(handler)
opener.open(os.environ['NZBPO_URL'])
urllib2.install_opener(opener)
device_id = os.environ['NZBPO_DEVICEID'].split( )
if len( device_id ) > 0:
for i in device_id:
values = {'device_iden' : i,
'title' : os.environ['NZBPO_TITLE'] + subject,
'body' : text,
'type' : os.environ['NZBPO_TYPE'] }
data = urllib.urlencode(values)
req = urllib2.Request(os.environ['NZBPO_URL'], data)
urllib2.urlopen(req)
else:
values = {'title' : os.environ['NZBPO_TITLE'] + subject,
'body' : text,
'type' : os.environ['NZBPO_TYPE'] }
data = urllib.urlencode(values)
req = urllib2.Request(os.environ['NZBPO_URL'], data)
urllib2.urlopen(req)
print('[DETAIL] Sent to Pushbullet')
except Exception as err:
print('[ERROR] %s' % err)
sys.exit(POSTPROCESS_ERROR)
# All OK, returning exit status 'POSTPROCESS_SUCCESS' (int <93>) to let NZBGet know
# that our script has successfully completed.
sys.exit(POSTPROCESS_SUCCESS)
@t0phr
Copy link
Author

t0phr commented Aug 16, 2014

GetPw.py

Scan script for nzbget. Put it in your script directory and it will scan the names of incoming NZB files and extract password when it is surrounded by curly brackets {{<password>}}. The filename is cleaned up and the file added to the nzbget queue afterwards.

@Mr-Flummi
Copy link

Hello,

thanks for your great GetPW.py Script. I use it since a long time, and on my PC it is working great. But since a few time, on the Laptop of my Mom, it will not works right. We use both the same System, it is Debian 9 stretch. Today I look in my synaptic and look, which python packages are installed. I look after that on the Laptop of my mother and there is the same. But I have no idea, why now the Script not works again and detect the password in the nzb file in {{password}}

Do you have an idea?

Best regards
Mr-Flummi

@JamborJan
Copy link

JamborJan commented Mar 3, 2022

Just in case someone wants to make use of a good old plane sh script, one additional example to extract a {{password}} and / or [[category]] from the file name.

Extra: if you are making use of nzbget within a docker container and mount the script in a folder, ensure you add the execute permission with e.g. chmod +x myscript.sh.

#!/bin/sh 

###########################################
### NZBGET SCAN SCRIPT                  ###

# Extract password and category
#
# This a sh shell script takes the password and category from the NZB file name if present.
#
# Example: [[Computer]]Debian8-Final.iso{{12345}}.nzb
#
# It switches the Category to "Computer" and set the password "12345".

### NZBGET SCAN SCRIPT                  ###
###########################################

newname=$(echo "$NZBNP_FILENAME" | sed -e 's/.*\]//g' -e 's/{.*//g' -e 's/.nzb//g')

case "$NZBNP_FILENAME" in
*[[*)
  category=$(echo "$NZBNP_FILENAME"  | sed -e 's/.*\[//g' -e 's/\].*//g')
  echo "[NZB] CATEGORY=$category";
  ;;
*       ) 
  category="" ;;
esac

case "$NZBNP_FILENAME" in
*{{*)
  passwd=$(echo "$NZBNP_FILENAME" | sed -e 's/.*{//g' -e 's/}.*//g')
  echo "[NZB] NZBPR_*Unpack:Password=$passwd";
  ;;
*       )
  passwd="" ;;
esac

echo "[NZB] NZBNAME=$newname";

exit 93

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