You may not want to have heavy software running on your machine for newsgroups. That’s when a friend told me about SABnzbd. After looking at how it works, it turns out that it’s particularly powerful.
I decided to write a small documentation for setting it up on Debian Squeeze.
cd /var/www
wget "http://downloads.sourceforge.net/project/sabnzbdplus/sabnzbdplus/sabnzbd-0.6.15/SABnzbd-0.6.15-src.tar.gz?r=http%3A%2F%2Fsabnzbd.org%2Fdownload%2F&ts=1332934860&use_mirror=freefr" -o sab.tgz
tar -xzf sab.tgz
mv SABnzbd-0.6.15 sabnzbd
cd sabnzbd
You may not want to have to type another port to access the web interface. The goal is to put it behind Apache which will redirect requests itself. First, we need to activate the Apache proxy module:
You might want an action to happen automatically after each download. In my case, I want the files present to not stay more than 15 days. So I have a script that cleans up, which I placed in crontab:
The problem is that it removes files that were created more than 15 days ago but that I downloaded less than 15 days ago.
Example: I download an Ubuntu ISO that is 5 months old. It’s in a compressed file (zip for example) that I download, Sabnzbd takes care of decompressing it, but the final file dates from 5 months ago and not from the date of decompression. So we need a solution to modify the file date to today. Let’s create a scripts folder for example:
This script renames folders containing a - or spaces with _. And it concatenates multiple _ into a single one. Then it changes the date of files and folders. Why do this when renaming options are available directly in SABnzbd? Simply because these operations are done when importing an nzb and not when renaming. But since it causes problems for the find command, I chose to do renaming.
Set the proper permissions:
1
chmod 755 /etc/scripts/sabnzbd/postscript.sh
To understand how it works, I invite you to read this link1
Then, configure Sabnzbd (from the web interface) so it knows where your scripts are and uses them automatically:
By default, downloading and yencode happens on disk. It is possible to do everything in RAM. Obviously this consumes RAM, but the difference in speed is phenomenal! That means you will at least double the performance! Personally, I quadrupled the download speeds :-). Here’s how I did it, go to the graphical interface then:
Configuration -> General -> Settings -> Article Cache Limit -> 250M
I wrote a Python script to work with the API provided by Sabnzbd. I created it with the idea that it should be easy to add functionality via the API. This script allows:
To see the elements provided by the XML API
To delete a certain number of elements in the history
Here’s the script. Edit the beginning of the script and insert the URL, as well as the API key:
#!/usr/bin/env python# Made by Deimos <xxx@mycompany.com># Under GPL2 licence# Set Sabnzbd URLsabnzbd_url='http://127.0.0.1:8080/sabnzbd'# Set Sabnzbd APIsabnzbd_api='2d872eb6257123a9579da906b487e1de'############################################################## Load modulesimportargparsefromurllib2importRequest, urlopen, URLErrorfromlxmlimportetreeimportsysdefDebug(debug_text):
"""Debug function"""ifdebug_mode==True:
printdebug_textdefargs():
"""Command line parameters"""# Define globla varsglobalsabnzbd_url, sabnzbd_api, debug_mode, mode, keep_history# Main informationsparser=argparse.ArgumentParser(description="Sabnzbd API usage in python")
subparsers=parser.add_subparsers(title='Available sub-commands', help='Choose a subcommand (-h for help)', description='Set a valid subcommand', dest="subcmd_name")
# Default argsparser.add_argument('-u', '--url', action='store', dest='url', type=str, default=sabnzbd_url, help='Set Sabnzbd URL (default : %(default)s)')
parser.add_argument('-a', '--api', action='store', dest='api', type=str, default=sabnzbd_api, help='Set Sabnzbd API key')
parser.add_argument('-v', '--version', action='version', version='v0.1 Licence GPLv2', help='Version 0.1')
parser.add_argument('-d', '--debug', action='store_true', default=False, help='Debug mode')
# Show XML APIparser_xa=subparsers.add_parser('xa', help='Show XML Elements from API')
# Delete historyparser_dh=subparsers.add_parser('dh', help='Delete old history')
parser_dh.add_argument('-k', '--keep', action='store', dest='num', type=int, default=150, help='Number of items to keep in history (default : %(default)s)')
result=parser.parse_args()
# Set debug to True if requested by command lineif (result.debug==True):
debug_mode=Trueelse:
debug_mode=False# Send debug informationsDebug('Command line : '+str(sys.argv))
Debug('Command line vars : '+str(parser.parse_args()))
# Check defaults optionsifresult.url!=sabnzbd_url:
sabnzbd_url=result.urlelifresult.api!=sabnzbd_api:
sabnzbd_api=result.api# Managing optionsmode=result.subcmd_nameif (mode=='dh'):
keep_history=result.numdefGetSabUrl(sabnzbd_url, sabnzbd_api):
"""Concat Sabnzbd URL
Check that the connection to URL is correct and TCP is OK"""# Concatsab_url=sabnzbd_url+'/api?mode=history&output=xml&apikey='+sabnzbd_apiDebug('Concatened Sabnzbd URL : '+str(sab_url))
# Connectivity testrequest=Request(sab_url)
try:
response=urlopen(request)
exceptURLError, e:
ifhasattr(e, 'reason'):
print'Can\'t connect to server : '+str(e.reason)
sys.exit(1)
elifhasattr(e, 'code'):
print'The server couldn\'t fulfill the request.'+str(e.code)
sys.exit(1)
else:
Debug('Sabnzbd TCP connection OK')
returnsab_urldefGetXmlHistory(sab_url):
"""Get XML nzo_id entries"""xml_history= []
# Parse XML from given urlxml_content=etree.parse(sab_url)
# Select only the wished tag and push it in xml_history listfornodeinxml_content.xpath("///*"):
if (node.tag=='nzo_id'):
# Reencode value to avoid errorstag_value=unicode(node.text).encode('utf8')
#Debug(node.tag + ' : ' + tag_value)xml_history.append(tag_value)
Debug('XML history has '+str(len(xml_history)) +' entries')
# If there were no entry in the list, check if the API failediflen(xml_history) ==0:
Debug('Checking why there is no datas')
xml_content=etree.parse(sab_url)
fornodeinxml_content.xpath("//*"):
if (node.tag=='error'):
print'Can\'t connect to server : '+unicode(node.text).encode('utf8')
sys.exit(1)
returnxml_historydefDeleteHistory(xml_history,keep_history):
"""Delete old history"""# Create a new list contaning elements to removeelements2delete= []
element_number=1forelementinxml_history:
ifelement_number>keep_history:
elements2delete.append(element)
element_number+=1queue_elements2remove=','.join(elements2delete)
Debug('Elements to delete ('+str(len(xml_history)) +' - '+str(keep_history) +' = '+str(len(elements2delete)) +')')
# Concat URL with elements to remove and then removesab_url_remove=sabnzbd_url+'/api?mode=history&name=delete&value='+queue_elements2remove+'&apikey='+sabnzbd_apiurlopen(sab_url_remove)
defShowXMLElements(sab_url):
"""Show XML code from URL"""xml_content=etree.parse(sab_url)
fornodeinxml_content.xpath("//*"):
printnode.tag+' : '+unicode(node.text).encode('utf8')
defmain():
"""Main function that launch all of them"""# Set args and get debug modeargs()
# Get Sabnzbd URL and check connectivitysab_url=GetSabUrl(sabnzbd_url, sabnzbd_api)
# Delete old historyifmode=='dh':
xml_history=GetXmlHistory(sab_url)
DeleteHistory(xml_history,keep_history)
elifmode=='xa':
ShowXMLElements(sab_url)
if__name__=="__main__":
main()
For the usage part, it’s divided into 2:
The main commands
The subcommands (requested functions)
Here’s how to use it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> sabnzbd_api.py -h
usage: sabnzbd_api.py [-h][-u URL][-a API][-v][-d]{xa,dh} ...
Sabnzbd API usage in python
optional arguments:
-h, --help show this help message and exit -u URL, --url URL Set Sabnzbd URL (default : http://127.0.0.1:8080/sabnzbd) -a API, --api API Set Sabnzbd API key
-v, --version Version 0.1
-d, --debug Debug mode
Available sub-commands:
Set a valid subcommand
{xa,dh} Choose a subcommand (-h forhelp) xa Show XML Elements from API
dh Delete old history
To use the dh subcommand that allows you to delete history:
1
2
3
4
5
6
> sabnzbd_api.py dh -h
usage: sabnzbd_api.py dh [-h][-k NUM]optional arguments:
-h, --help show this help message and exit -k NUM, --keep NUM Number of items to keep in history(default : 150)
Here, if I remove -h, it will delete the history queue larger than 150 entries.