Compare commits

...

78 Commits

Author SHA1 Message Date
ShyPike
d06f957a0f Fix api call "addfile" (for adding local NZB file). 2012-02-03 20:19:51 +01:00
ShyPike
1e10308d39 OSX troubleshoot menu: when using 127.0.0.1 also reset http and https ports. 2012-02-01 22:34:04 +01:00
ShyPike
6a87a9c8ab Update text files for 0.6.15 final. 2012-02-01 21:12:10 +01:00
ShyPike
2f26bb5273 Flag post-processing as failed when files cannot be moved/copied to destination. 2012-01-28 22:18:20 +01:00
ShyPike
6da8a83f7c Fix two more newzbin links. 2012-01-27 00:39:59 +01:00
ShyPike
1e5bcc9796 Update text files for 0.6.15RC1 2012-01-26 20:01:47 +01:00
ShyPike
38d4415545 Fix newzbin-url detection regex. 2012-01-26 19:56:49 +01:00
ShyPike
345649690a Replace newzbin.com with newzbin2.es
Add an INI setting for its base URL.
2012-01-25 22:50:37 +01:00
ShyPike
4644a7151f Don't keep Windows awake when there are only 'paused' items in the queue. 2012-01-25 20:12:07 +01:00
ShyPike
5404b2ce42 Add special setting to use "pickle" library instead of cPickle. 2012-01-15 14:27:09 +01:00
ShyPike
7c42020713 Suppress "incompatible feed" error when doing a scheduled/automatic RSS read-out. 2012-01-15 14:21:34 +01:00
ShyPike
9f1436cd64 Fix "Repair" button on smpl Connection page. Current path fails when using a reverse proxy. 2012-01-06 21:52:11 +01:00
ShyPike
31c433a664 Prevent crash on restoring URL-fetches when using --repair-all option. 2012-01-06 21:23:24 +01:00
ShyPike
72be50d8e2 Ignore whitespace around regular expressions in RSS filters. 2011-12-31 18:44:53 +01:00
ShyPike
4bb12514b6 Add trailing slashes to internal Plush paths to support reverse proxies better. 2011-12-27 15:10:27 +01:00
shypike
05ae5b3e34 Improve OSX version detection and give Leopard image the name "*-osx-leopard.dmg". 2011-12-24 11:59:41 +01:00
shypike
f3751a279c Extend OSX menu with Troubleshoot items and "Scan watched folder". 2011-12-24 11:59:29 +01:00
shypike
f5d0995556 SFV check should fail on missing files too. 2011-12-24 11:08:44 +01:00
ShyPike
dd67e06a47 Move "locale" construction from Plush skin to Python code.
Some embedded Linux platforms show bizarre behavior with the original construction.
2011-12-21 19:25:20 +01:00
shypike
3eed004ed3 Prevent setting watched-folder speed to 0 (while having no watched-folder) from triggering an inifinite loop. 2011-12-10 00:31:40 +01:00
ShyPike
5bc41d9008 Update text files for 0.6.14 2011-12-09 20:37:14 +01:00
ShyPike
3ea80c30ae Prevent "watched folder" from being reset to default when it cannot be created at startup time. 2011-12-09 19:38:17 +01:00
ShyPike
245b5973f6 Update text files for 0.6.13 2011-12-08 21:13:52 +01:00
ShyPike
1d0eec4d1c Prevent potential crash in RSS link analysis. 2011-12-08 20:41:39 +01:00
shypike
fac4e0855f Add --console option to force console logging for OSX app. This will help diagnose startup problems. 2011-12-08 18:46:33 +01:00
ShyPike
4a9f17e3cc Update text files for 0.6.13 2011-12-07 23:20:48 +01:00
ShyPike
98b7739383 Make sure that paths coming from Sorting are normalized. 2011-12-07 23:17:43 +01:00
ShyPike
d727b4d370 Fix reference to Config->Switches Wiki page. 2011-12-06 22:48:13 +01:00
ShyPike
5b989e4726 Update text files for 0.6.13 2011-12-06 21:59:08 +01:00
ShyPike
ecdea06411 Update text files for 0.6.13 2011-12-06 20:16:12 +01:00
ShyPike
a8bbcb4cf2 When retrying an URL fetch from History, remove the History entry and don't show a re-queue message anymore. 2011-12-06 19:53:37 +01:00
shypike
d3c1ccf988 Disable multihost feature. Too many systems seem have trouble with it. 2011-12-06 19:51:07 +01:00
ShyPike
c0ae406b0a Update French translation. 2011-12-03 11:49:56 +01:00
ShyPike
afdeaacbea Update text files for 0.6.12 2011-12-03 10:45:03 +01:00
ShyPike
f5124c9e79 Don't ask for gzip compression when getting a ZIP file from a web site.
(Improved version of "Handle weird sites that use an extra GZ compression layer on top of ZIPs.")
2011-12-02 21:28:41 +01:00
ShyPike
5fe0d40023 Handle OS-es that returns multiple identical IPs for localhost (like Ubuntu-s). 2011-12-01 22:12:19 +01:00
ShyPike
3da2a8c091 Handle weird sites that use an extra GZ compression layer on top of ZIPs. 2011-12-01 22:10:37 +01:00
ShyPike
cc3f4e6125 Movie sort failed to created specified job folder (regression error). 2011-12-01 20:09:24 +01:00
ShyPike
5643b5682f Show "Enable Growl" option only when on OSX. 2011-11-29 21:23:43 +01:00
ShyPike
92a49d1736 Update text files for 0.6.11 Final. 2011-11-29 20:44:44 +01:00
ShyPike
ce9350cd8e Modify analysis of RSS feeds so that links in a Yahoo pipe are handled
conform the rules for the original index site.
2011-11-26 12:16:05 +01:00
ShyPike
04d67887d1 Prevent rare crash in TestServer function. 2011-11-24 19:46:04 +01:00
ShyPike
afd3df869b Fix two potential crashes. 2011-11-23 19:33:11 +01:00
ShyPike
f6804fe009 Handle incorrect date fields in NZB files and accept the NZB anyway. 2011-11-23 19:26:24 +01:00
ShyPike
eda7642af1 Further improvement of detection of encrypted RAR files. 2011-11-16 20:24:44 +01:00
ShyPike
cab42a44f3 Update text files for 0.6.11RC1 2011-11-15 22:35:48 +01:00
ShyPike
89b3c18e9f Make sure SFV check isn't done when more par2 files can still be downloaded. 2011-11-15 19:23:08 +01:00
ShyPike
08560ae9ea api call "get_bookmarks" should ignore "auto-fetch bookmark" setting too. 2011-11-14 20:53:32 +01:00
ShyPike
1bcc993a99 Check writing of NZF files to disk.
Abort job that fails to read one of its NZF files.
2011-11-14 19:49:48 +01:00
ShyPike
2054c31575 Handle unknown Growl errors too. 2011-11-13 22:59:16 +01:00
ShyPike
a2278ea1b3 Update main POT file. 2011-11-11 21:56:43 +01:00
ShyPike
8feaae8061 After failed par2 verification do an SFV check (if enabled and SFV files available).
Previously an SFV check was only done when no par2 files were available.
2011-11-11 21:56:08 +01:00
shypike
a65a5d4b41 Make "Get Bookmarks Now" (newzbin) button work when auto-fetch for bookmarks is off. 2011-11-11 00:30:13 +01:00
shypike
693b59cc0c Fix logging of Pre-Q script result. 2011-11-08 22:13:21 +01:00
ShyPike
b85e093d38 Log invocation of par2 command (debug level). 2011-11-02 20:18:25 +01:00
ShyPike
180cd6f3da Only run extension-based cleanup when verification was OK.
Otherwise the user may lose par2 files if .par2 was in the cleanup list.
2011-11-01 23:15:52 +01:00
ShyPike
1de601c505 Update text files for 0.6.11 2011-10-29 10:58:48 +02:00
ShyPike
97a481c73d Make SABnzbd listen on all available localhost equivalents (usually 127.0.0.1 and [::1]).
Add command line option --stack with values '4', '6', 'b' meaning IPv4-only, IPv6-only and both, respectively.
This will fix connection problems on systems with an ambiguous localhost.
2011-10-28 20:45:31 +02:00
ShyPike
4fdb715b54 Fix Dutch typo. 2011-10-28 20:44:06 +02:00
ShyPike
8fbe463adf Improve detection of encrypted rar files. 2011-10-28 20:40:20 +02:00
shypike
70ee174a47 OSX menu should show 10 queued items (like the text claims) instead of 9. 2011-10-28 20:39:11 +02:00
ShyPike
7532f6b569 Eliminate extra (temporary) folder level when using GenericSort. 2011-10-28 20:38:04 +02:00
ShyPike
4013e616af Update GNTP module to prevent crash on French OSX. 2011-10-28 20:30:10 +02:00
ShyPike
19daeab0f3 Update text files for 0.6.10 2011-10-17 12:01:23 +02:00
ShyPike
4387234e71 Prevent reading newzbin bookmarks when no newzbin credentials are known. 2011-10-17 11:58:05 +02:00
ShyPike
ad92ec55f8 Add sabnzbd.ico to OSX dmg so that Growl can use it. 2011-10-16 22:01:27 +02:00
ShyPike
cba62676d0 Remove some errors from the text files for 0.6.10 2011-10-16 20:56:19 +02:00
ShyPike
05f50fc546 Fix incorrect ref to pynotify. 2011-10-16 17:30:11 +02:00
ShyPike
1ee25ac279 Update text files for 0.6.10 2011-10-16 17:21:39 +02:00
ShyPike
5ee0ad4a20 When reading file names from an SFV file, convert to encoding suitable for the platform. 2011-10-16 11:32:53 +02:00
ShyPike
e52dd8d3f3 Render ambiguous Windows paths like "D:" and "D:folder" as "D:\" and "D:\folder". 2011-10-12 20:14:48 +02:00
ShyPike
755afced61 Add gntp module to source distribution file. 2011-10-12 19:54:01 +02:00
ShyPike
0cdba27504 Only allow Growl support for OSX. 2011-10-11 21:57:13 +02:00
ShyPike
3636e3ce4b Update text files for 0.6.10RC1 2011-10-11 20:30:44 +02:00
shypike
f98d55a14e OSX: Generate a SnowLeopard/Lion DMG and a Leopard DMG. 2011-10-11 20:26:05 +02:00
ShyPike
b645314e50 Create backup of the INI file before changing it.
Add some more steps in an order that avoids damaging it at all times.
2011-10-10 23:18:29 +02:00
ShyPike
95cae0e6c4 Fix failure to recognize "encrypted file" message from unrar 4.01. 2011-10-10 19:34:26 +02:00
shypike
1fdf04e9c0 OSX: Add support for classic Growl and Growl-1.3 (Lion+ only).
Also add enable/disable option for Growl to prevent timeout issues.
2011-10-09 14:03:14 +02:00
62 changed files with 1954 additions and 886 deletions

View File

@@ -1,5 +1,5 @@
*******************************************
*** This is SABnzbd 0.6.9 ***
*** This is SABnzbd 0.6.15 ***
*******************************************
SABnzbd is an open-source cross-platform binary newsreader.
It simplifies the process of downloading from Usenet dramatically,

View File

@@ -1,3 +1,79 @@
-------------------------------------------------------------------------------
0.6.15Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Flag post-processing as failed when files cannot be moved/copied to destination
- Fixed another newzbin link
-------------------------------------------------------------------------------
0.6.15RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Change newzbin URL
- Prevent setting watched-folder speed to 0 (while having no watched-folder)
from triggering an inifinite loop.
- Move "locale" construction from Plush skin to Python code.
Some embedded Linux platforms show unstable behavior with the original construction.
- Extend OSX menu with troubleshooting options
- Add trailing slashes to internal Plush paths to support reverse proxies better.
- Ignore whitespace around regular expressions in RSS filters.
- Prevent crash on restoring URL-fetches when using --repair-all option
- Fix "Repair" button on smpl Connection page. Current path fails when using a reverse proxy
- Suppress "incompatible feed" error when doing a scheduled/automatic RSS read-out.
- Add special setting to use "pickle" library instead of cPickle.
-------------------------------------------------------------------------------
0.6.14Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Prevent potential crash in RSS feed analysis
- Add --console to force console logging for OSX app (diagnostic tool)
- Don't reset watched folder path to default when it doesn't exist at startup
-------------------------------------------------------------------------------
0.6.13Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Disable "SABnzbd will now listen on all "localhost" addresses" feature
- When retrying an URL fetch from History, remove the History entry
- Make sure that paths coming from Sorting are normalized
-------------------------------------------------------------------------------
0.6.12Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix issue with new localhost handling on some IPv4-only Unixes
- Fix job folder creation by Movie Sort when the Sort expression specifies one
- Fix problem with retrieving ZIP files from some web sites
-------------------------------------------------------------------------------
0.6.11Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Better support for Yahoo pipes
- Accept NZB files containing incorrect dates
-------------------------------------------------------------------------------
0.6.11RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix some Growl issues (OSX)
- Improve detection of encrypted RAR files during download
- SABnzbd will now listen on all "localhost" addresses
- Remove unneeded extra temporary folder level in Generic Sort
- Show the promised 10 queue entries in the OSX menu instead of 9
- Fix logging of pre-queue script result
- "Get bookmarks now" for newzbin only worked when automatic readout was also enabled.
- When par2 fails do an SFV-based check when SFV files present and feature enabled.
(previously SFV was only used when no par2 files were available at all)
- Do extra checks on job administration on disk
(an attempt to diagnose jobs with missing admin files)
- Make newzbin "Get bookmarks now" button independent of automatic readout
-------------------------------------------------------------------------------
0.6.10Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Convert ambiguous Windows paths like D: and D:folder to D:\ and D:\folder
- Fix file name encoding problems when verifying using SFV files
- Add GNTP module to source distribution
- Prevent reading newzbin bookmarks when newzbin credentials are not set
-------------------------------------------------------------------------------
0.6.10RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Allow saving of category paths ending in a *
This is will prevent the creation of job folders in the final folder
- Fix incompatibility with unrar 4.01 regarding detection of encrypted files
- Create .bak (backup) file for sabnzbd.ini before modifying it
- OSX: Compatible with Growl 1.2.2 and 1.3
- OSX: Prevent changes to SABnzbd.app folder which confused the OSX Firewall
- OSX: Fix access rights of SABnzbs.app so that restricted users can run SABnzbd
- OSX: Combined SnowLeopard/Lion DMG and separate Leopard DMG
-------------------------------------------------------------------------------
0.6.9Final by The SABnzbd-Team
-------------------------------------------------------------------------------

View File

@@ -1,16 +1,16 @@
(c) Copyright 2007-2011 by "The SABnzbd-team" <team@sabnzbd.org>
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>
The SABnzbd-team is:
Current team:
ShyPike <shypike@sabnzbd.org>
sw1tch <switch@sabnzbd.org>
pairofdimes <pairofdimes@sabnzbd.org>
inpheaux <inpheaux@sabnzbd.org>
rAf <rAf@sabnzbd.org>
Honorary member (and original author)
Previous members
Gregor Kaufmann <tdian@users.sourceforge.net>
sw1tch <switch@sabnzbd.org>
This program is free software; you can redistribute it and/or

View File

@@ -1,10 +1,10 @@
SABnzbd 0.6.9
SABnzbd 0.6.15
-------------------------------------------------------------------------------
0) LICENSE
-------------------------------------------------------------------------------
(c) Copyright 2007-2011 by "The SABnzbd-team" <team@sabnzbd.org>
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@@ -73,3 +73,14 @@
make sure that the drives are mounted.
The operating system wil simply redirect your files to alternative locations.
You may have trouble finding the files when mounting the drive later.
- On some operating systems it looks like there is a problem with one of the standard Python libraries.
It is possible that you get errors about saving admin files and even unexplained crashes.
If so, you can enable the option for the alternative library.
It has the same functionality, but is slower.
We've had reports about this issue on non-mainstream Linux platforms.
- OpenElec
- Squeeze Linux
There is an INI-only option that will allow you to select an alternative library.
use_pickle = 1
See: http://wiki.sabnzbd.org/configure-special

View File

@@ -1,4 +1,4 @@
(c) Copyright 2007-2011 by "The SABnzbd-team" <team@sabnzbd.org>
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@@ -1,7 +1,7 @@
Metadata-Version: 1.0
Name: SABnzbd
Version: 0.6.9
Summary: SABnzbd-0.6.9
Version: 0.6.15
Summary: SABnzbd-0.6.15
Home-page: http://sourceforge.net/projects/sabnzbdplus
Author: The SABnzbd Team
Author-email: team@sabnzbd.org

View File

@@ -4,26 +4,23 @@
\paperw11900\paperh16840\vieww16360\viewh15680\viewkind0
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
\f0\b\fs48 \cf0 SABnzbd 0.6.9\
\f0\b\fs48 \cf0 SABnzbd 0.6.15\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
\b0\fs26 \cf0 \
\b What's new
\b What's new:
\b0 \
- Update Plush to solve minor browser incompatibilities\
- On Windows the 64bit versions of par2 and unrar were never used\
- Updated unrar to 4.01\
- Using the "Download" button in newzbin.com RSS feeds produced malformed names.\
- When removing job folders in the "temporary download folder", remove everything.\
This is needed because some operating systems add spurious files and folders.\
- Generic Sorter failed to uppercase first letter of title when starting with "the/a/to" etc.\
- Add "hidden" option allow_64bit_tools (lost when going from 0.5.6 to 0.6.0)\
- Extend OSX menu with troubleshooting options\
- Change newzbin URL\
- Flag post-processing as failed when files cannot be moved/copied to destination.\
- Move "locale" construction from Plush skin to Python code.\
Some embedded Linux platforms show unstable behavior with the original construction.\
- Add special setting to use "pickle" library instead of cPickle.\
This is needed for some embedded Linux distros (e.g. OpenElec).\
- Minor fixes: see changelog.txt\
\
- OSX has now a Leopard/SnowLeopard DMG and a Lion-only DMG\
You can see the difference in the DMG's background image\
\
\b About
\b0 \
SABnzbd is an open-source cross-platform binary newsreader.\
@@ -34,6 +31,8 @@ extract and clean up posts downloaded from Usenet.\
SABnzbd also has a fully customizable user interface,\
and offers a complete API for third-party applications to hook into.\
\
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>\
\
There is an extensive Wiki on the use of SABnzbd.\
{\field{\*\fldinst{HYPERLINK "http://wiki.sabnzbd.org/"}}{\fldrslt http://wiki.sabnzbd.org/}}\
\

View File

@@ -1,18 +1,14 @@
************************ SABnzbd 0.6.9 ************************
************************ SABnzbd 0.6.15 ************************
What's new:
- Update Plush to solve minor browser incompatibilities
- On Windows the 64bit versions of par2 and unrar were never used
- Updated unrar to 4.01
- Using the "Download" button in newzbin.com RSS feeds produced malformed names.
- When removing job folders in the "temporary download folder", remove everything.
This is needed because some operating systems add spurious files and folders.
- Generic Sorter failed to uppercase first letter of title when starting with "the/a/to" etc.
- Add "hidden" option allow_64bit_tools (lost when going from 0.5.6 to 0.6.0)
- OSX has now a Leopard/SnowLeopard DMG and a Lion-only DMG
You can see the difference in the DMG's background image
- Extend OSX menu with troubleshooting options
- Change newzbin URL
- Flag post-processing as failed when files cannot be moved/copied to destination
- Move "locale" construction from Plush skin to Python code.
Some embedded Linux platforms show unstable behavior with the original construction.
- Add special setting to use "pickle" library instead of cPickle.
This is needed for some embedded Linux distros (e.g. OpenElec).
- Minor fixes: see changelog.txt
About:
SABnzbd is an open-source cross-platform binary newsreader.
@@ -21,4 +17,4 @@ About:
built-in post-processing options that automatically verify, repair,
extract and clean up posts downloaded from Usenet.
(c) Copyright 2007-2011 by "The SABnzbd-team" <team@sabnzbd.org>
(c) Copyright 2007-2012 by "The SABnzbd-team" <team@sabnzbd.org>

View File

@@ -251,6 +251,7 @@ def print_help():
print " with full data reconstruction"
print " --https <port> Port to use for HTTPS server"
print " --log-all Log all article handling (for developers)"
print " --console Force console logging for OSX app"
print " --new Run a new instance of SABnzbd"
def print_version():
@@ -491,6 +492,18 @@ def print_modules():
logging.info("pyOpenSSL... NOT found - try apt-get install python-pyopenssl (SSL is optional)")
#------------------------------------------------------------------------------
def all_localhosts():
""" Return all unique values of localhost """
return ['127.0.0.1']
ips = []
for item in socket.getaddrinfo('localhost', None):
item = item[4][0]
if item not in ips:
ips.append(item)
return ips
#------------------------------------------------------------------------------
def get_webhost(cherryhost, cherryport, https_port):
""" Determine the webhost address and port,
@@ -613,6 +626,18 @@ def get_webhost(cherryhost, cherryport, https_port):
return cherryhost, cherryport, browserhost, https_port
def attach_server(host, port, cert=None, key=None):
""" Define and attach server, optionally HTTPS
"""
http_server = _cpwsgi_server.CPWSGIServer()
http_server.bind_addr = (host, port)
if cert and key:
http_server.ssl_certificate = cert
http_server.ssl_private_key = key
adapter = _cpserver.ServerAdapter(cherrypy.engine, http_server, http_server.bind_addr)
adapter.subscribe()
def is_sabnzbd_running(url):
""" Return True when there's already a SABnzbd instance running.
"""
@@ -773,7 +798,7 @@ def commandline_handler(frozen=True):
'weblogging=', 'server=', 'templates',
'template2', 'browser=', 'config-file=', 'force',
'version', 'https=', 'autorestarted', 'repair', 'repair-all',
'log-all', 'no-login', 'pid=', 'new', 'sessions',
'log-all', 'no-login', 'pid=', 'new', 'sessions', 'console',
# Below Win32 Service options
'password=', 'username=', 'startup=', 'perfmonini=', 'perfmondll=',
'interactive', 'wait=',
@@ -847,6 +872,7 @@ def main():
pid_path = None
new_instance = False
force_sessions = False
osx_console = False
service, sab_opts, serv_opts, upload_nzbs = commandline_handler()
@@ -928,7 +954,11 @@ def main():
elif opt in ('--new',):
new_instance = True
elif opt in ('--sessions',):
re_argv.append(opt)
force_sessions = True
elif opt in ('--console',):
re_argv.append(opt)
osx_console = True
sabnzbd.MY_FULLNAME = os.path.normpath(os.path.abspath(sabnzbd.MY_FULLNAME))
sabnzbd.MY_NAME = os.path.basename(sabnzbd.MY_FULLNAME)
@@ -946,7 +976,7 @@ def main():
consoleLogging = consoleLogging and not sabnzbd.DAEMON
# No console logging needed for OSX app
noConsoleLoggingOSX = (sabnzbd.DIR_PROG.find('.app/Contents/Resources') > 0)
noConsoleLoggingOSX = (not osx_console) and (sabnzbd.DIR_PROG.find('.app/Contents/Resources') > 0)
if noConsoleLoggingOSX:
consoleLogging = 1
@@ -1273,18 +1303,38 @@ def main():
logging.warning(Ta('Disabled HTTPS because of missing CERT and KEY files'))
enable_https = False
if enable_https:
if https_port:
# Prepare an extra server for the HTTP port
http_server = _cpwsgi_server.CPWSGIServer()
http_server.bind_addr = (cherryhost, cherryport)
#secure_server.ssl_certificate = https_cert
#secure_server.ssl_private_key = https_key
adapter = _cpserver.ServerAdapter(cherrypy.engine, http_server, http_server.bind_addr)
adapter.subscribe()
cherryport = https_port
cherrypy.config.update({'server.ssl_certificate' : https_cert,
'server.ssl_private_key' : https_key })
# Determine if this system has multiple definitions for 'localhost'
hosts = all_localhosts()
multilocal = len(hosts) > 1 and cherryhost in ('localhost', '0.0.0.0')
# For 0.0.0.0 CherryPy will always pick IPv4, so make sure the secondary localhost is IPv6
if multilocal and cherryhost == '0.0.0.0' and hosts[1] == '127.0.0.1':
hosts[1] = '::1'
# The Windows binary requires numeric localhost as primary address
if multilocal and cherryhost == 'localhost' and hosts[1] == '127.0.0.1':
cherryhost = '::1'
if enable_https:
if https_port:
# Extra HTTP port for primary localhost
attach_server(cherryhost, cherryport)
if multilocal:
# Extra HTTP port for secondary localhost
attach_server(hosts[1], cherryport)
# Extra HTTPS port for secondary localhost
attach_server(hosts[1], https_port, https_cert, https_key)
cherryport = https_port
elif multilocal:
# Extra HTTPS port for secondary localhost
attach_server(hosts[1], cherryport, https_cert, https_key)
cherrypy.config.update({'server.ssl_certificate' : https_cert,
'server.ssl_private_key' : https_key })
elif multilocal:
# Extra HTTP port for secondary localhost
attach_server(hosts[1], cherryport)
if no_login:
sabnzbd.cfg.username.set('')

441
gntp/__init__.py Normal file
View File

@@ -0,0 +1,441 @@
import re
import hashlib
import time
import platform
__version__ = '0.4'
class BaseError(Exception):
pass
class ParseError(BaseError):
def gntp_error(self):
error = GNTPError(errorcode=500,errordesc='Error parsing the message')
return error.encode()
class AuthError(BaseError):
def gntp_error(self):
error = GNTPError(errorcode=400,errordesc='Error with authorization')
return error.encode()
class UnsupportedError(BaseError):
def gntp_error(self):
error = GNTPError(errorcode=500,errordesc='Currently unsupported by gntp.py')
return error.encode()
class _GNTPBase(object):
info = {
'version':'1.0',
'messagetype':None,
'encryptionAlgorithmID':None
}
_requiredHeaders = []
headers = {}
resources = {}
def add_origin_info(self):
self.add_header('Origin-Machine-Name',platform.node())
self.add_header('Origin-Software-Name','gntp.py')
self.add_header('Origin-Software-Version',__version__)
self.add_header('Origin-Platform-Name',platform.system())
self.add_header('Origin-Platform-Version',platform.platform())
def __str__(self):
return self.encode()
def _parse_info(self,data):
'''
Parse the first line of a GNTP message to get security and other info values
@param data: GNTP Message
@return: GNTP Message information in a dictionary
'''
#GNTP/<version> <messagetype> <encryptionAlgorithmID>[:<ivValue>][ <keyHashAlgorithmID>:<keyHash>.<salt>]
match = re.match('GNTP/(?P<version>\d+\.\d+) (?P<messagetype>REGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR)'+
' (?P<encryptionAlgorithmID>[A-Z0-9]+(:(?P<ivValue>[A-F0-9]+))?) ?'+
'((?P<keyHashAlgorithmID>[A-Z0-9]+):(?P<keyHash>[A-F0-9]+).(?P<salt>[A-F0-9]+))?\r\n', data,re.IGNORECASE)
if not match:
raise ParseError('ERROR_PARSING_INFO_LINE')
info = match.groupdict()
if info['encryptionAlgorithmID'] == 'NONE':
info['encryptionAlgorithmID'] = None
return info
def set_password(self,password,encryptAlgo='MD5'):
'''
Set a password for a GNTP Message
@param password: Null to clear password
@param encryptAlgo: Supports MD5,SHA1,SHA256,SHA512
@todo: Support other hash functions
'''
hash = {
'MD5': hashlib.md5,
'SHA1': hashlib.sha1,
'SHA256': hashlib.sha256,
'SHA512': hashlib.sha512,
}
self.password = password
self.encryptAlgo = encryptAlgo.upper()
if not password:
self.info['encryptionAlgorithmID'] = None
self.info['keyHashAlgorithm'] = None;
return
if not self.encryptAlgo in hash.keys():
raise UnsupportedError('INVALID HASH "%s"'%self.encryptAlgo)
hashfunction = hash.get(self.encryptAlgo)
password = password.encode('utf8')
seed = time.ctime()
salt = hashfunction(seed).hexdigest()
saltHash = hashfunction(seed).digest()
keyBasis = password+saltHash
key = hashfunction(keyBasis).digest()
keyHash = hashfunction(key).hexdigest()
self.info['keyHashAlgorithmID'] = self.encryptAlgo
self.info['keyHash'] = keyHash.upper()
self.info['salt'] = salt.upper()
def _decode_hex(self,value):
'''
Helper function to decode hex string to `proper` hex string
@param value: Value to decode
@return: Hex string
'''
result = ''
for i in range(0,len(value),2):
tmp = int(value[i:i+2],16)
result += chr(tmp)
return result
def _decode_binary(self,rawIdentifier,identifier):
rawIdentifier += '\r\n\r\n'
dataLength = int(identifier['Length'])
pointerStart = self.raw.find(rawIdentifier)+len(rawIdentifier)
pointerEnd = pointerStart + dataLength
data = self.raw[pointerStart:pointerEnd]
if not len(data) == dataLength:
raise ParseError('INVALID_DATA_LENGTH Expected: %s Recieved %s'%(dataLength,len(data)))
return data
def _validate_password(self,password):
'''
Validate GNTP Message against stored password
'''
self.password = password
if password == None: raise Exception()
keyHash = self.info.get('keyHash',None)
if keyHash is None and self.password is None:
return True
if keyHash is None:
raise AuthError('Invalid keyHash')
if self.password is None:
raise AuthError('Missing password')
password = self.password.encode('utf8')
saltHash = self._decode_hex(self.info['salt'])
keyBasis = password+saltHash
key = hashlib.md5(keyBasis).digest()
keyHash = hashlib.md5(key).hexdigest()
if not keyHash.upper() == self.info['keyHash'].upper():
raise AuthError('Invalid Hash')
return True
def validate(self):
'''
Verify required headers
'''
for header in self._requiredHeaders:
if not self.headers.get(header,False):
raise ParseError('Missing Notification Header: '+header)
def _format_info(self):
'''
Generate info line for GNTP Message
@return: Info line string
'''
info = u'GNTP/%s %s'%(
self.info.get('version'),
self.info.get('messagetype'),
)
if self.info.get('encryptionAlgorithmID',None):
info += ' %s:%s'%(
self.info.get('encryptionAlgorithmID'),
self.info.get('ivValue'),
)
else:
info+=' NONE'
if self.info.get('keyHashAlgorithmID',None):
info += ' %s:%s.%s'%(
self.info.get('keyHashAlgorithmID'),
self.info.get('keyHash'),
self.info.get('salt')
)
return info
def _parse_dict(self,data):
'''
Helper function to parse blocks of GNTP headers into a dictionary
@param data:
@return: Dictionary of headers
'''
dict = {}
for line in data.split('\r\n'):
match = re.match('([\w-]+):(.+)', line)
if not match: continue
key = match.group(1).strip()
val = match.group(2).strip()
dict[key] = val
return dict
def add_header(self,key,value):
if isinstance(value, unicode):
self.headers[key] = value
else:
self.headers[key] = unicode('%s'%value,'utf8','replace')
def decode(self,data,password=None):
'''
Decode GNTP Message
@param data:
'''
self.password = password
self.raw = data
parts = self.raw.split('\r\n\r\n')
self.info = self._parse_info(data)
self.headers = self._parse_dict(parts[0])
def encode(self):
'''
Encode a GNTP Message
@return: GNTP Message ready to be sent
'''
self.validate()
EOL = u'\r\n'
message = self._format_info() + EOL
#Headers
for k,v in self.headers.iteritems():
message += u'%s: %s%s'%(k,v,EOL)
message += EOL
return message
class GNTPRegister(_GNTPBase):
"""Represents a GNTP Registration Command"""
notifications = []
_requiredHeaders = [
'Application-Name',
'Notifications-Count'
]
_requiredNotificationHeaders = ['Notification-Name']
def __init__(self,data=None,password=None):
'''
@param data: (Optional) See decode()
@param password: (Optional) Password to use while encoding/decoding messages
'''
self.info['messagetype'] = 'REGISTER'
if data:
self.decode(data,password)
else:
self.set_password(password)
self.add_header('Application-Name', 'pygntp')
self.add_header('Notifications-Count', 0)
self.add_origin_info()
def validate(self):
'''
Validate required headers and validate notification headers
'''
for header in self._requiredHeaders:
if not self.headers.get(header,False):
raise ParseError('Missing Registration Header: '+header)
for notice in self.notifications:
for header in self._requiredNotificationHeaders:
if not notice.get(header,False):
raise ParseError('Missing Notification Header: '+header)
def decode(self,data,password):
'''
Decode existing GNTP Registration message
@param data: Message to decode.
'''
self.raw = data
parts = self.raw.split('\r\n\r\n')
self.info = self._parse_info(data)
self._validate_password(password)
self.headers = self._parse_dict(parts[0])
for i,part in enumerate(parts):
if i==0: continue #Skip Header
if part.strip()=='': continue
notice = self._parse_dict(part)
if notice.get('Notification-Name',False):
self.notifications.append(notice)
elif notice.get('Identifier',False):
notice['Data'] = self._decode_binary(part,notice)
#open('register.png','wblol').write(notice['Data'])
self.resources[ notice.get('Identifier') ] = notice
def add_notification(self,name,enabled=True):
'''
Add new Notification to Registration message
@param name: Notification Name
@param enabled: Default Notification to Enabled
'''
notice = {}
notice['Notification-Name'] = u'%s'%name
notice['Notification-Enabled'] = u'%s'%enabled
self.notifications.append(notice)
self.add_header('Notifications-Count', len(self.notifications))
def encode(self):
'''
Encode a GNTP Registration Message
@return: GNTP Registration Message ready to be sent
'''
self.validate()
EOL = u'\r\n'
message = self._format_info() + EOL
#Headers
for k,v in self.headers.iteritems():
message += u'%s: %s%s'%(k,v,EOL)
#Notifications
if len(self.notifications)>0:
for notice in self.notifications:
message += EOL
for k,v in notice.iteritems():
message += u'%s: %s%s'%(k,v,EOL)
message += EOL
return message
class GNTPNotice(_GNTPBase):
"""Represents a GNTP Notification Command"""
_requiredHeaders = [
'Application-Name',
'Notification-Name',
'Notification-Title'
]
def __init__(self,data=None,app=None,name=None,title=None,password=None):
'''
@param data: (Optional) See decode()
@param app: (Optional) Set Application-Name
@param name: (Optional) Set Notification-Name
@param title: (Optional) Set Notification Title
@param password: (Optional) Password to use while encoding/decoding messages
'''
self.info['messagetype'] = 'NOTIFY'
if data:
self.decode(data,password)
else:
self.set_password(password)
if app:
self.add_header('Application-Name', app)
if name:
self.add_header('Notification-Name', name)
if title:
self.add_header('Notification-Title', title)
self.add_origin_info()
def decode(self,data,password):
'''
Decode existing GNTP Notification message
@param data: Message to decode.
'''
self.raw = data
parts = self.raw.split('\r\n\r\n')
self.info = self._parse_info(data)
self._validate_password(password)
self.headers = self._parse_dict(parts[0])
for i,part in enumerate(parts):
if i==0: continue #Skip Header
if part.strip()=='': continue
notice = self._parse_dict(part)
if notice.get('Identifier',False):
notice['Data'] = self._decode_binary(part,notice)
#open('notice.png','wblol').write(notice['Data'])
self.resources[ notice.get('Identifier') ] = notice
def encode(self):
'''
Encode a GNTP Notification Message
@return: GNTP Notification Message ready to be sent
'''
self.validate()
EOL = u'\r\n'
message = self._format_info() + EOL
#Headers
for k,v in self.headers.iteritems():
message += u'%s: %s%s'%(k,v,EOL)
message += EOL
return message
class GNTPSubscribe(_GNTPBase):
"""Represents a GNTP Subscribe Command"""
def __init__(self,data=None,password=None):
self.info['messagetype'] = 'SUBSCRIBE'
self._requiredHeaders = [
'Subscriber-ID',
'Subscriber-Name',
]
if data:
self.decode(data,password)
else:
self.set_password(password)
self.add_origin_info()
class GNTPOK(_GNTPBase):
"""Represents a GNTP OK Response"""
_requiredHeaders = ['Response-Action']
def __init__(self,data=None,action=None):
'''
@param data: (Optional) See _GNTPResponse.decode()
@param action: (Optional) Set type of action the OK Response is for
'''
self.info['messagetype'] = '-OK'
if data:
self.decode(data)
if action:
self.add_header('Response-Action', action)
self.add_origin_info()
class GNTPError(_GNTPBase):
_requiredHeaders = ['Error-Code','Error-Description']
def __init__(self,data=None,errorcode=None,errordesc=None):
'''
@param data: (Optional) See _GNTPResponse.decode()
@param errorcode: (Optional) Error code
@param errordesc: (Optional) Error Description
'''
self.info['messagetype'] = '-ERROR'
if data:
self.decode(data)
if errorcode:
self.add_header('Error-Code', errorcode)
self.add_header('Error-Description', errordesc)
self.add_origin_info()
def error(self):
return self.headers['Error-Code'],self.headers['Error-Description']
def parse_gntp(data,password=None):
'''
Attempt to parse a message as a GNTP message
@param data: Message to be parsed
@param password: Optional password to be used to verify the message
'''
match = re.match('GNTP/(?P<version>\d+\.\d+) (?P<messagetype>REGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR)',data,re.IGNORECASE)
if not match:
raise ParseError('INVALID_GNTP_INFO')
info = match.groupdict()
if info['messagetype'] == 'REGISTER':
return GNTPRegister(data,password=password)
elif info['messagetype'] == 'NOTIFY':
return GNTPNotice(data,password=password)
elif info['messagetype'] == 'SUBSCRIBE':
return GNTPSubscribe(data,password=password)
elif info['messagetype'] == '-OK':
return GNTPOK(data)
elif info['messagetype'] == '-ERROR':
return GNTPError(data)
raise ParseError('INVALID_GNTP_MESSAGE')

172
gntp/notifier.py Normal file
View File

@@ -0,0 +1,172 @@
"""
The gntp.notifier module is provided as a simple way to send notifications
using GNTP
.. note::
This class is intended to mostly mirror the older Python bindings such
that you should be able to replace instances of the old bindings with
this class.
`Original Python bindings <http://code.google.com/p/growl/source/browse/Bindings/python/Growl.py>`_
"""
import gntp
import socket
import logging
logger = logging.getLogger(__name__)
class GrowlNotifier(object):
"""Helper class to simplfy sending Growl messages
:param string applicationName: Sending application name
:param list notification: List of valid notifications
:param list defaultNotifications: List of notifications that should be enabled
by default
:param string applicationIcon: Icon URL
:param string hostname: Remote host
:param integer port: Remote port
"""
applicationName = 'Python GNTP'
notifications = []
defaultNotifications = []
applicationIcon = None
passwordHash = 'MD5'
#GNTP Specific
password = None
hostname = 'localhost'
port = 23053
def __init__(self, applicationName=None, notifications=None, defaultNotifications=None, applicationIcon=None, hostname=None, password=None, port=None):
if applicationName:
self.applicationName = applicationName
assert self.applicationName, 'An application name is required.'
if notifications:
self.notifications = list(notifications)
assert self.notifications, 'A sequence of one or more notification names is required.'
if defaultNotifications is not None:
self.defaultNotifications = list(defaultNotifications)
elif not self.defaultNotifications:
self.defaultNotifications = list(self.notifications)
if applicationIcon is not None:
self.applicationIcon = self._checkIcon(applicationIcon)
elif self.applicationIcon is not None:
self.applicationIcon = self._checkIcon(self.applicationIcon)
#GNTP Specific
if password:
self.password = password
if hostname:
self.hostname = hostname
assert self.hostname, 'Requires valid hostname'
if port:
self.port = int(port)
assert isinstance(self.port, int), 'Requires valid port'
def _checkIcon(self, data):
'''
Check the icon to see if it's valid
@param data:
@todo Consider checking for a valid URL
'''
return data
def register(self):
"""Send GNTP Registration
.. warning::
Before sending notifications to Growl, you need to have
sent a registration message at least once
"""
logger.info('Sending registration to %s:%s', self.hostname, self.port)
register = gntp.GNTPRegister()
register.add_header('Application-Name', self.applicationName)
for notification in self.notifications:
enabled = notification in self.defaultNotifications
register.add_notification(notification, enabled)
if self.applicationIcon:
register.add_header('Application-Icon', self.applicationIcon)
if self.password:
register.set_password(self.password, self.passwordHash)
response = self._send('register', register.encode())
if isinstance(response, gntp.GNTPOK):
return True
logger.error('Invalid response %s', response.error())
return response.error()
def notify(self, noteType, title, description, icon=None, sticky=False, priority=None):
"""Send a GNTP notifications
.. warning::
Must have registered with growl beforehand or messages will be ignored
:param string noteType: One of the notification names registered earlier
:param string title: Notification title (usually displayed on the notification)
:param string description: The main content of the notification
:param string icon: Icon URL path
:param boolean sticky: Sticky notification
:param integer priority: Message priority level from -2 to 2
"""
logger.info('Sending notification [%s] to %s:%s', noteType, self.hostname, self.port)
assert noteType in self.notifications
notice = gntp.GNTPNotice()
notice.add_header('Application-Name', self.applicationName)
notice.add_header('Notification-Name', noteType)
notice.add_header('Notification-Title', title)
if self.password:
notice.set_password(self.password, self.passwordHash)
if sticky:
notice.add_header('Notification-Sticky', sticky)
if priority:
notice.add_header('Notification-Priority', priority)
if icon:
notice.add_header('Notification-Icon', self._checkIcon(icon))
if description:
notice.add_header('Notification-Text', description)
response = self._send('notify', notice.encode())
if isinstance(response, gntp.GNTPOK):
return True
logger.error('Invalid response %s', response.error())
return response.error()
def subscribe(self, id, name, port):
"""Send a Subscribe request to a remote machine"""
sub = gntp.GNTPSubscribe()
sub.add_header('Subscriber-ID', id)
sub.add_header('Subscriber-Name', name)
sub.add_header('Subscriber-Port', port)
if self.password:
sub.set_password(self.password, self.passwordHash)
response = self._send('subscribe', sub.encode())
if isinstance(response, gntp.GNTPOK):
return True
logger.error('Invalid response %s', response.error())
return response.error()
def _send(self, type, data):
"""Send the GNTP Packet"""
#logger.debug('To : %s:%s <%s>\n%s', self.hostname, self.port, type, data)
#Less verbose please
logger.debug('To : %s:%s <%s>', self.hostname, self.port, type)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((self.hostname, self.port))
s.send(data.encode('utf8', 'replace'))
try:
s.settimeout(10)
except:
pass
response = gntp.parse_gntp(s.recv(1024))
s.close()
#logger.debug('From : %s:%s <%s>\n%s', self.hostname, self.port, response.__class__, response)
#Less verbose please
logger.debug('From : %s:%s <%s>', self.hostname, self.port, response.__class__)
return response

View File

@@ -49,7 +49,7 @@ $T('explain-bookmark_rate')<br>
<fieldset class="EntryFieldSet">
<legend>$T('processedBM')</legend>
<!--#for $msgid in $bookmarks_list#-->
<a href="https://www.newzbin.com/browse/post/$msgid/" target="_blank">$msgid</a>&nbsp;
<a href="https://$newzbin_url/browse/post/$msgid/" target="_blank">$msgid</a>&nbsp;
<!--#end for#-->
</fieldset>
<!--#end if#-->

View File

@@ -1,6 +1,6 @@
<!--#set global $topmenu="config"#-->
<!--#set global $statpath="../.."#-->
<!--#set global $helpsubject="Configure+Switches+V3"#-->
<!--#set global $helpsubject="Configure+Switches+V2"#-->
<!--#include $webdir + "/inc_top.tmpl"#-->
<!--#set global $submenu="switches"#-->
@@ -129,6 +129,11 @@
$T('explain-ampm')<br>
<br/>
<!--#end if#-->
<!--#if $darwin#-->
<label><input type="checkbox" name="growl_enable" value="1" <!--#if $growl_enable > 0 then "checked=1" else ""#--> /> <strong>$T('opt-growl_enable')</strong></label><br>
$T('explain-growl_enable')<br>
<br/>
<!--#end if#-->
<strong>$T('opt-ignore_samples'):</strong><br>
$T('explain-ignore_samples')<br>
<input class="radio" type="radio" name="ignore_samples" value="0" <!--#if $ignore_samples == 0 then 'checked="1"' else ""#--> /> $T('igsam-off')

View File

@@ -83,9 +83,9 @@
</ul>
<ul class="menu" id="navigation_menu_left">
<li#if $pane=="Main"# class="active first"#else# class="first"#end if#><a href="${path}"><span class="icon_nav_download">$T('Plush-downloads').capitalize()</span></a></li>
<li#if $pane=="Connections"# class="active"#end if#><a href="${path}connections"><span class="icon_nav_connections">$T('menu-cons').capitalize()</span></a></li>
<li#if $pane=="RSS"# class="active"#end if#><a href="${path}config/rss"><span class="icon_nav_rss">$T('rss').upper()</span></a></li>
<li#if $pane!="RSS" and $pane!="Nzo" and ($pane=="Config" or $path=='../../')# class="active last"#else# class="last"#end if#><a href="${path}config"><span class="icon_nav_config">$T('menu-config').capitalize()</span></a></li>
<li#if $pane=="Connections"# class="active"#end if#><a href="${path}connections/"><span class="icon_nav_connections">$T('menu-cons').capitalize()</span></a></li>
<li#if $pane=="RSS"# class="active"#end if#><a href="${path}config/rss/"><span class="icon_nav_rss">$T('rss').upper()</span></a></li>
<li#if $pane!="RSS" and $pane!="Nzo" and ($pane=="Config" or $path=='../../')# class="active last"#else# class="last"#end if#><a href="${path}config/"><span class="icon_nav_config">$T('menu-config').capitalize()</span></a></li>
</ul>
</div>
<div id="nav_text_right">
@@ -114,23 +114,23 @@
#else#
<div class="config_nav">
<ul>
<li><a class="#if $pane=="General"#nav_active#end if#" id="config_nav_general" href="${path}config/general">
<li><a class="#if $pane=="General"#nav_active#end if#" id="config_nav_general" href="${path}config/general/">
<div class="config_sprite_container sprite_config_nav_general">$T('cmenu-general')</div></a></li>
<li><a class="#if $pane=="Folders"#nav_active#end if#" id="config_nav_directories" href="${path}config/directories">
<li><a class="#if $pane=="Folders"#nav_active#end if#" id="config_nav_directories" href="${path}config/directories/">
<div class="config_sprite_container sprite_config_nav_folders">$T('cmenu-folders')</div></a></li>
<li><a class="#if $pane=="Switches"#nav_active#end if#" id="config_nav_switches" href="${path}config/switches">
<li><a class="#if $pane=="Switches"#nav_active#end if#" id="config_nav_switches" href="${path}config/switches/">
<div class="config_sprite_container sprite_config_nav_switches">$T('cmenu-switches')</div></a></li>
<li><a class="#if $pane=="Servers"#nav_active#end if#" id="config_nav_server" href="${path}config/server">
<li><a class="#if $pane=="Servers"#nav_active#end if#" id="config_nav_server" href="${path}config/server/">
<div class="config_sprite_container sprite_config_nav_servers">$T('cmenu-servers')</div></a></li>
<li><a class="#if $pane=="Scheduling"#nav_active#end if#" id="config_nav_scheduling" href="${path}config/scheduling">
<li><a class="#if $pane=="Scheduling"#nav_active#end if#" id="config_nav_scheduling" href="${path}config/scheduling/">
<div class="config_sprite_container sprite_config_nav_scheduling">$T('Plush-cmenu-scheduling')</div></a></li>
<li><a class="#if $pane=="Email"#nav_active#end if#" id="config_nav_email" href="${path}config/email">
<li><a class="#if $pane=="Email"#nav_active#end if#" id="config_nav_email" href="${path}config/email/">
<div class="config_sprite_container sprite_config_nav_email">$T('cmenu-email')</div></a></li>
<li><a class="#if $pane=="Index Sites"#nav_active#end if#" id="config_nav_index_sites" href="${path}config/newzbin">
<li><a class="#if $pane=="Index Sites"#nav_active#end if#" id="config_nav_index_sites" href="${path}config/newzbin/">
<div class="config_sprite_container sprite_config_nav_indexsites">$T('cmenu-newzbin')</div></a></li>
<li><a class="#if $pane=="Categories"#nav_active#end if#" id="config_nav_categories" href="${path}config/categories">
<li><a class="#if $pane=="Categories"#nav_active#end if#" id="config_nav_categories" href="${path}config/categories/">
<div class="config_sprite_container sprite_config_nav_categories">$T('cmenu-cat')</div></a></li>
<li><a class="#if $pane=="Sorting"#nav_active#end if#" id="config_nav_sorting" href="${path}config/sorting">
<li><a class="#if $pane=="Sorting"#nav_active#end if#" id="config_nav_sorting" href="${path}config/sorting/">
<div class="config_sprite_container sprite_config_nav_sorting">$T('cmenu-sorting')</div></a></li>
</ul>
</div>

View File

@@ -121,7 +121,7 @@
</div>
<fieldset class="component-group-list">
<!--#for $msgid in $bookmarks_list#-->
<a href="https://www.newzbin.com/browse/post/$msgid/" target="_blank">$msgid</a><br/>
<a href="https://$newzbin_url/browse/post/$msgid/" target="_blank">$msgid</a><br/>
<!--#end for#-->
</fieldset>
</div><!-- /component-group4 -->

View File

@@ -1,5 +1,5 @@
<!--#set global $pane="Switches"#-->
<!--#set global $help_uri="Configure+Switches+V3"#-->
<!--#set global $help_uri="Configure+Switches+V2"#-->
<!--#include $webdir + "/_inc_header.tmpl"#-->
<form action="saveSwitches" method="post" name="fullform" id="fullform">
@@ -35,6 +35,15 @@
</label>
</div>
<!--#end if#-->
<!--#if $darwin#-->
<div class="field-pair">
<input type="checkbox" name="growl_enable" id="growl_enable" value="1" <!--#if $growl_enable > 0 then "checked=1" else ""#--> />
<label class="clearfix" for="growl_enable">
<span class="component-title">$T('opt-growl_enable')</span>
<span class="component-desc">$T('explain-growl_enable')</span>
</label>
</div>
<!--#end if#-->
</fieldset>
</div><!-- /component-group1 -->

View File

@@ -61,8 +61,8 @@
</td>
<td>
<!--#if $line.report #-->
<a href="https://www.newzbin.com/browse/post/$line.report/" target="_blank">
<div class="icon_history_verbose main_sprite_container sprite_hv_report pointer" title='$T('Plush-openSourceURL')<br><br>https://www.newzbin.com/browse/post/$line.report'>&nbsp;</div>
<a href="https://$newzbin_url/browse/post/$line.report/" target="_blank">
<div class="icon_history_verbose main_sprite_container sprite_hv_report pointer" title='$T('Plush-openSourceURL')<br><br>https://$newzbin_url/browse/post/$line.report'>&nbsp;</div>
</a>
<!--#else if $varExists('newzbinDetails')#-->
<div class="icon_history_verbose main_sprite_container sprite_hv_report hvFaded">&nbsp;</div>

View File

@@ -1,6 +1,3 @@
<% import locale %>
<% locale.setlocale(locale.LC_ALL, "") %>
<script type="text/javascript">
if (typeof( jQuery ) == 'undefined')
window.location = "../"; // redirect to main on direct template hit
@@ -62,8 +59,8 @@
<td>
<div class="main_sprite_container sprite_progressbar_bg">
<div class="main_sprite_container sprite_progress_done" style="background-position: -<!--#if $slot.mb == "0.00" then "120" else int(120 - 120.0 / 100.0 * int(100 - float($slot.mbleft) / float($slot.mb) * 100))#-->px -401px">
<div class="totalDownload"><!--#echo locale.format('%d', int(float($slot.mb)), True)#-->&nbsp;<small>$T('MB')</small></div>
<div class="currentDownload"><!--#if $slot.mb!=$slot.mbleft#--><!--#echo locale.format('%d', int(float($slot.mb)-float($slot.mbleft)), True)#-->&nbsp;<small>$T('MB')&nbsp;$T('AofB')</small><!--#end if#--></div>
<div class="totalDownload">$slot.mb_fmt&nbsp;<small>$T('MB')</small></div>
<div class="currentDownload"><!--#if $slot.mb!=$slot.mbleft#-->$slot.mbdone_fmt&nbsp;<small>$T('MB')&nbsp;$T('AofB')</small><!--#end if#--></div>
</div>
</div>
</td>

View File

@@ -54,7 +54,7 @@ $T('explain-newzbin')<br/>
<legend>$T('processedBM')</legend>
<hr />
<!--#for $msgid in $bookmarks_list#-->
<a href="https://www.newzbin.com/browse/post/$msgid/" target="_blank">$msgid</a>&nbsp;
<a href="https://$newzbin_url/browse/post/$msgid/" target="_blank">$msgid</a>&nbsp;
<!--#end for#-->
<br class="clear" />
</fieldset>

View File

@@ -1,5 +1,5 @@
<a href="${helpuri}Configure+Switches+V3" id="help" target="_blank">$T('menu-help')</a>
<a href="${helpuri}Configure+Switches+V2" id="help" target="_blank">$T('menu-help')</a>
<h3>$T('switchesConfig')</h3>
<div class="EntryBlock">
<form id="configSwitches" class="cmxform">
@@ -175,6 +175,14 @@
<br class="clear" />
<!--#end if#-->
<!--#if $darwin#-->
<label><span class="label">$T('opt-growl_enable'):</span>
<input class="radio" type="checkbox" name="growl_enable" value="1" <!--#if $growl_enable > 0 then 'checked="1"' else ""#--> /></label>
<span class="tips">$T('explain-growl_enable')</span>
<!--#end if#-->
<br class="clear" />
<span class="label">$T('opt-ignore_samples'):</span>
<input class="radio" type="radio" name="ignore_samples" value="0" <!--#if $ignore_samples == 0 then 'checked="1"' else ""#--> /> $T('igsam-off')
<input class="radio" type="radio" name="ignore_samples" value="1" <!--#if $ignore_samples == 1 then 'checked="1"' else ""#--> /> $T('igsam-del')

View File

@@ -86,6 +86,6 @@ $T('explain-orphans')<br/>
<!--#end if#-->
$T('explain-Repair')<br/>
<form action="saveGeneral" method="post">
<input type="submit" onclick="this.form.action='../config/repair?session=$session'; this.form.submit(); return false;" value="$T('button-repair')"/>
<input type="submit" onclick="this.form.action='config/repair?session=$session'; this.form.submit(); return false;" value="$T('button-repair')"/>
</form>

View File

@@ -36,7 +36,7 @@
<td>$line.name<!--#if $line.action_line#--> - <span class="action_message">$line.action_line</span><!--#else if $line.fail_message#--> - <span class="fail_message">$line.fail_message</span><!--#end if#--></td>
<td>
<!--#if $line.report#-->
<a href="https://www.newzbin.com/browse/post/$line.report"><img class="imglink" src="static/images/newzbin.png" /></a>
<a href="https://$newzbin_url/browse/post/$line.report"><img class="imglink" src="static/images/newzbin.png" /></a>
<!--#end if#-->
<!--#if $line.url_info#-->
<a href="$line.url_info"><img class="imglink" src="static/images/browser.png" /></a>

View File

@@ -3,7 +3,7 @@
<form action="./four" method="post" autocomplete="off">
<p>$T('wizard-index-explain')</p>
<div id="serverDetails">
<h3><a href="http://newzbin.com" target="_blank">Newzbin.com</a> ($T('wizard-optional'))</h3>
<h3><a href="http://$newzbin_url" target="_blank">Newzbin2.es</a> ($T('wizard-optional'))</h3>
<label class="label">$T('srv-username'):</label><input type="text" size="20" value="$newzbin_user" name="newzbin_user">
<br class="clear" />
<label class="label">$T('srv-password'):</label><input type="password" size="20" value="$newzbin_pass" name="newzbin_pass">

29
licenses/License-gntp.txt Normal file
View File

@@ -0,0 +1,29 @@
The module gntp is (C) Paul Traylor
Home of the module:
https://github.com/kfdm/gntp/
It is covered by the following license.
-------------------------------------------------------------------------
Copyright (c) 2011 Paul Traylor
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------------

BIN
osx/image/sabnzbd.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -34,6 +34,9 @@ except ImportError:
try:
import py2app
from setuptools import setup
OSX_LION = [int(n) for n in platform.mac_ver()[0].split('.')] >= [10, 7, 0]
OSX_SL = not OSX_LION and [int(n) for n in platform.mac_ver()[0].split('.')] >= [10, 6, 0]
OSX_LEOPARD = not (OSX_LION or OSX_SL)
except ImportError:
py2app = None
@@ -313,6 +316,7 @@ fileIns = prod + '-win32-setup.exe'
fileBin = prod + '-win32-bin.zip'
fileSrc = prod + '-src.tar.gz'
fileDmg = prod + '-osx.dmg'
fileDmgLp = prod + '-osx-leopard.dmg'
fileOSr = prod + '-osx-src.tar.gz'
fileImg = prod + '.sparseimage'
@@ -381,17 +385,20 @@ if target == 'app':
# Select OSX version specific background image
# Take care to preserve the special attributes of the background image file
if [int(n) for n in platform.mac_ver()[0].split('.')] >= [10, 7, 0]:
# Lion and higher
f = open('osx/image/sabnzbd_lion.png', 'rb')
if OSX_LION:
# Lion and higher: generates SnowLeopard/Lion DMG
f = open('osx/image/sabnzbd.png', 'rb')
png = f.read()
f.close()
f = open('/Volumes/SABnzbd/sabnzbd.png', 'wb')
f.write(png)
f.close()
else:
# Snow Leopard and lower
pass
# Snow Leopard and lower: generates Leopard DMG
fileDmg = fileDmgLp
f = open('osx/image/sabnzbd_leopard.png', 'rb')
png = f.read()
f.close()
f = open('/Volumes/SABnzbd/sabnzbd.png', 'wb')
f.write(png)
f.close()
# Rename the volume
fp = open('mount.log', 'r')
@@ -448,6 +455,7 @@ if target == 'app':
os.system("cp -pR osx/par2/ dist/SABnzbd.app/Contents/Resources/osx/par2>/dev/null")
os.system("mkdir dist/SABnzbd.app/Contents/Resources/osx/unrar>/dev/null")
os.system("cp -pR osx/unrar/ dist/SABnzbd.app/Contents/Resources/osx/unrar>/dev/null")
os.system("cp sabnzbd.ico dist/SABnzbd.app/Contents/Resources >/dev/null")
os.system("find dist/SABnzbd.app -name .git | xargs rm -rf")
#copy app to mounted sparseimage
@@ -621,7 +629,7 @@ else:
os.mkdir(root)
# Set data files
data_files.extend(['po/', 'cherrypy/'])
data_files.extend(['po/', 'cherrypy/', 'gntp/'])
options['data_files'] = PairList(data_files)
options['data_files'].append(('tools', ['tools/make_mo.py', 'tools/msgfmt.py']))

View File

@@ -1,22 +1,21 @@
#
# SABnzbd Translation Template file
# Copyright (C) 2010 by the SABnzbd Team
# team@sabnzbd.org
# French translation for sabnzbd
# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
# This file is distributed under the same license as the sabnzbd package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-0.6.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-01-15 19:19+0000\n"
"PO-Revision-Date: 2011-08-01 19:14+0000\n"
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-06-29 19:43+0000\n"
"PO-Revision-Date: 2011-08-01 19:15+0000\n"
"Last-Translator: shypike <Unknown>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language-Team: French <fr@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-08-02 04:50+0000\n"
"X-Launchpad-Export-Date: 2011-08-02 05:48+0000\n"
"X-Generator: Launchpad (build 13552)\n"
"Language: fr\n"
#: email/email.tmpl:1
msgid ""
@@ -164,148 +163,3 @@ msgstr ""
"<!--#end for#-->\n"
"\n"
"Au Revoir\n"
#~ msgid ""
#~ "##\n"
#~ "## Default Email template for SABnzbd\n"
#~ "## This a Cheetah template\n"
#~ "## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
#~ "##\n"
#~ "## Newlines and whitespace are significant!\n"
#~ "##\n"
#~ "## These are the email headers\n"
#~ "to: $to\n"
#~ "from: $from\n"
#~ "date: $date\n"
#~ "subject: SABnzbd has <!--#if $status then \"completed\" else \"failed\" #--> "
#~ "job $name\n"
#~ "X-priority: 5\n"
#~ "X-MS-priority: 5\n"
#~ "## After this comes the body, the empty line is required!\n"
#~ "\n"
#~ "Hi,\n"
#~ "<!--#if $status #-->\n"
#~ "SABnzbd has downloaded \"$name\" <!--#if $msgid==\"\" then \"\" else "
#~ "\"(newzbin #\" + $msgid + \")\"#-->\n"
#~ "<!--#else#-->\n"
#~ "SABnzbd has failed to download \"$name\" <!--#if $msgid==\"\" then \"\" else "
#~ "\"(newzbin #\" + $msgid + \")\"#-->\n"
#~ "<!--#end if#-->\n"
#~ "Finished at $end_time\n"
#~ "Downloaded $size\n"
#~ "\n"
#~ "Results of the job:\n"
#~ "<!--#for $stage in $stages #-->\n"
#~ "Stage $stage <!--#slurp#-->\n"
#~ "<!--#for $result in $stages[$stage]#-->\n"
#~ " $result <!--#slurp#-->\n"
#~ "<!--#end for#-->\n"
#~ "<!--#end for#-->\n"
#~ "<!--#if $script!=\"\" #-->\n"
#~ "Output from user script \"$script\" (Exit code = $script_ret):\n"
#~ "$script_output\n"
#~ "<!--#end if#-->\n"
#~ "<!--#if $status #-->\n"
#~ "Enjoy!\n"
#~ "<!--#else#-->\n"
#~ "Sorry!\n"
#~ "<!--#end if#-->\n"
#~ msgstr ""
#~ "#encoding UTF-8\n"
#~ "##\n"
#~ "## Template Email pour SABnzbd\n"
#~ "## Ceci est un template Cheetah\n"
#~ "## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
#~ "##\n"
#~ "## Les retours à la ligne et les espaces sont importants !\n"
#~ "##\n"
#~ "## Entêtes de l'email\n"
#~ "to: $to\n"
#~ "from: $from\n"
#~ "date: $date\n"
#~ "subject: SABnzbd <!--#if $status#-->Succès<!--#else#-->Echec<!--#end if#--> "
#~ "du téléchargement $name\n"
#~ "X-priority: 5\n"
#~ "X-MS-priority: 5\n"
#~ "## Le contenu du message, la ligne vide est obligatoire !\n"
#~ "\n"
#~ "Bonjour,\n"
#~ "<!--#if $status #-->\n"
#~ "SABnzbd a téléchargé avec succès \"$name\" <!--#if $msgid==\"\" then \"\" "
#~ "else \"(newzbin #\" + $msgid + \")\"#-->\n"
#~ "<!--#else#-->\n"
#~ "SABnzbd a téléchargé sans succès \"$name\" <!--#if $msgid==\"\" then \"\" "
#~ "else \"(newzbin #\" + $msgid + \")\"#-->\n"
#~ "<!--#end if#-->\n"
#~ "Terminé à $end_time\n"
#~ "Téléchargé $size\n"
#~ "\n"
#~ "Résultat du téléchargement :\n"
#~ "<!--#for $stage in $stages #-->\n"
#~ "Etape $stage <!--#slurp#-->\n"
#~ "<!--#for $result in $stages[$stage]#-->\n"
#~ " $result <!--#slurp#-->\n"
#~ "<!--#end for#-->\n"
#~ "<!--#end for#-->\n"
#~ "<!--#if $script!=\"\" #-->\n"
#~ "Sortie du script utilisateur \"$script\" (Code Retour = $script_ret):\n"
#~ "$script_output\n"
#~ "<!--#end if#-->\n"
#~ "<!--#if $status #-->\n"
#~ "A bientôt !\n"
#~ "<!--#else#-->\n"
#~ "Désolé !\n"
#~ "<!--#end if#-->\n"
#~ msgid ""
#~ "##\n"
#~ "## RSS Email template for SABnzbd\n"
#~ "## This a Cheetah template\n"
#~ "## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
#~ "##\n"
#~ "## Newlines and whitespace are significant!\n"
#~ "##\n"
#~ "## These are the email headers\n"
#~ "to: $to\n"
#~ "from: $from\n"
#~ "date: $date\n"
#~ "subject: SABnzbd has added $amount jobs to the queue\n"
#~ "X-priority: 5\n"
#~ "X-MS-priority: 5\n"
#~ "## After this comes the body, the empty line is required!\n"
#~ "\n"
#~ "Hi,\n"
#~ "\n"
#~ "SABnzbd has added $amount job(s) to the queue.\n"
#~ "They are from RSS feed \"$feed\".\n"
#~ "<!--#for $job in $jobs#-->\n"
#~ " $job <!--#slurp#-->\n"
#~ "<!--#end for#-->\n"
#~ "\n"
#~ "Bye\n"
#~ msgstr ""
#~ "##\n"
#~ "## RSS Email template for SABnzbd\n"
#~ "## This a Cheetah template\n"
#~ "## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
#~ "##\n"
#~ "## Newlines and whitespace are significant!\n"
#~ "##\n"
#~ "## These are the email headers\n"
#~ "to: $to\n"
#~ "from: $from\n"
#~ "date: $date\n"
#~ "subject: SABnzbd has added $amount jobs to the queue\n"
#~ "X-priority: 5\n"
#~ "X-MS-priority: 5\n"
#~ "## After this comes the body, the empty line is required!\n"
#~ "\n"
#~ "Hi,\n"
#~ "\n"
#~ "SABnzbd has added $amount job(s) to the queue.\n"
#~ "They are from RSS feed \"$feed\".\n"
#~ "<!--#for $job in $jobs#-->\n"
#~ " $job <!--#slurp#-->\n"
#~ "<!--#end for#-->\n"
#~ "\n"
#~ "Bye\n"

View File

@@ -12,63 +12,111 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 7bit\n"
"POT-Creation-Date: 2011-09-04 12:16+CEST\n"
"POT-Creation-Date: 2011-11-11 21:53+West-Europa (standaardtijd)\n"
"Generated-By: pygettext.py 1.5\n"
#: SABnzbd.py:300 [Error message]
#: SABnzbd.py:301 [Error message]
msgid "Failed to start web-interface"
msgstr ""
#: SABnzbd.py:333 [Warning message]
#: SABnzbd.py:334 [Warning message]
msgid "Cannot find web template: %s, trying standard template"
msgstr ""
#: SABnzbd.py:456 [Error message]
#: SABnzbd.py:457 [Error message]
msgid "_yenc module... NOT found!"
msgstr ""
#: SABnzbd.py:463 [Error message]
#: SABnzbd.py:464 [Error message]
msgid "par2 binary... NOT found!"
msgstr ""
#: SABnzbd.py:471 [Warning message]
#: SABnzbd.py:472 [Warning message]
msgid "unrar binary... NOT found"
msgstr ""
#: SABnzbd.py:476 [Warning message]
#: SABnzbd.py:477 [Warning message]
msgid "unzip binary... NOT found!"
msgstr ""
#: SABnzbd.py:580 [Warning message]
#: SABnzbd.py:588 [Warning message]
msgid "Please be aware the 0.0.0.0 hostname will need an IPv6 address for external access"
msgstr ""
#: SABnzbd.py:1273 [Warning message]
#: SABnzbd.py:1298 [Warning message]
msgid "Disabled HTTPS because of missing CERT and KEY files"
msgstr ""
#: SABnzbd.py:1532 # sabnzbd/osxmenu.py:731
#: SABnzbd.py:1577 # sabnzbd/osxmenu.py:731
msgid "SABnzbd shutdown finished"
msgstr ""
#: sabnzbd/utils/servertests.py:35
msgid "The hostname is not set."
msgstr ""
#: sabnzbd/utils/servertests.py:41
msgid "There are no connections set. Please set at least one connection."
msgstr ""
#: sabnzbd/utils/servertests.py:74
msgid "Password masked in ******, please re-enter"
msgstr ""
#: sabnzbd/utils/servertests.py:78
msgid "Invalid server details"
msgstr ""
#: sabnzbd/utils/servertests.py:90
msgid "Timed out: Try enabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py:92
msgid "Timed out"
msgstr ""
#: sabnzbd/utils/servertests.py:97
msgid "Invalid server address."
msgstr ""
#: sabnzbd/utils/servertests.py:119
msgid "Server requires username and password."
msgstr ""
#: sabnzbd/utils/servertests.py:122
msgid "Connection Successful!"
msgstr ""
#: sabnzbd/utils/servertests.py:125
msgid "Authentication failed, check username/password."
msgstr ""
#: sabnzbd/utils/servertests.py:128
msgid "Too many connections, please pause downloading or try again later"
msgstr ""
#: sabnzbd/utils/servertests.py:131
msgid "Could not determine connection result (%s)"
msgstr ""
#: sabnzbd/__init__.py:159 [Warning message]
msgid "Signal %s caught, saving and exiting..."
msgstr ""
#: sabnzbd/__init__.py:429
msgid "fetching msgid %s from www.newzbin.com"
msgid "fetching msgid %s from www.newzbin2.es"
msgstr ""
#: sabnzbd/__init__.py:435 [Error message]
msgid "Error Fetching msgid %s from www.newzbin.com - Please make sure your Username and Password are set"
msgid "Error Fetching msgid %s from www.newzbin2.es - Please make sure your Username and Password are set"
msgstr ""
#: sabnzbd/__init__.py:447
msgid "Trying to fetch NZB from %s"
msgstr ""
#: sabnzbd/__init__.py:570 [Error message] # sabnzbd/config.py:749 [Error message]
#: sabnzbd/__init__.py:570 [Error message]
msgid "Cannot create temp file for %s"
msgstr ""
@@ -101,11 +149,11 @@ msgstr ""
msgid "Default"
msgstr ""
#: sabnzbd/api.py:1468 # sabnzbd/interface.py:2183
#: sabnzbd/api.py:1468 # sabnzbd/interface.py:2186
msgid "WARNING:"
msgstr ""
#: sabnzbd/api.py:1468 # sabnzbd/interface.py:2183 # sabnzbd/interface.py:2276
#: sabnzbd/api.py:1468 # sabnzbd/interface.py:2186 # sabnzbd/interface.py:2279
msgid "ERROR:"
msgstr ""
@@ -149,7 +197,7 @@ msgstr ""
msgid "%s is not a valid email address"
msgstr ""
#: sabnzbd/cfg.py:54 # sabnzbd/interface.py:1464
#: sabnzbd/cfg.py:54 # sabnzbd/interface.py:1470
msgid "Server address required"
msgstr ""
@@ -157,23 +205,31 @@ msgstr ""
msgid "Cannot create %s folder %s"
msgstr ""
#: sabnzbd/config.py:872 [Error message]
#: sabnzbd/config.py:730 [Error message]
msgid "Cannot write to INI file %s"
msgstr ""
#: sabnzbd/config.py:762 [Error message]
msgid "Cannot create backup file for %s"
msgstr ""
#: sabnzbd/config.py:886 [Error message]
msgid "Incorrectly encoded password %s"
msgstr ""
#: sabnzbd/config.py:896
#: sabnzbd/config.py:910
msgid "%s is not a correct octal value"
msgstr ""
#: sabnzbd/config.py:905
#: sabnzbd/config.py:919
msgid "UNC path \"%s\" not allowed here"
msgstr ""
#: sabnzbd/config.py:913
#: sabnzbd/config.py:927
msgid "Error: Queue not empty, cannot change folder."
msgstr ""
#: sabnzbd/config.py:922
#: sabnzbd/config.py:936
msgid "Folder \"%s\" does not exist"
msgstr ""
@@ -377,315 +433,315 @@ msgstr ""
msgid "&nbsp<br />SABnzbd shutdown finished.<br />Wait for about 5 second and then click the button below.<br /><br /><strong><a href=\"..\">Refresh</a></strong><br />"
msgstr ""
#: sabnzbd/interface.py:1578 [Used as default Feed name in Config->RSS] # sabnzbd/skintext.py:479 [Config->RSS, tab header]
#: sabnzbd/interface.py:1584 [Used as default Feed name in Config->RSS] # sabnzbd/skintext.py:479 [Config->RSS, tab header]
msgid "Feed"
msgstr ""
#: sabnzbd/interface.py:1791 # sabnzbd/skintext.py:80
#: sabnzbd/interface.py:1797 # sabnzbd/skintext.py:80
msgid "Daily"
msgstr ""
#: sabnzbd/interface.py:1792 # sabnzbd/skintext.py:81
#: sabnzbd/interface.py:1798 # sabnzbd/skintext.py:81
msgid "Monday"
msgstr ""
#: sabnzbd/interface.py:1793 # sabnzbd/skintext.py:82
#: sabnzbd/interface.py:1799 # sabnzbd/skintext.py:82
msgid "Tuesday"
msgstr ""
#: sabnzbd/interface.py:1794 # sabnzbd/skintext.py:83
#: sabnzbd/interface.py:1800 # sabnzbd/skintext.py:83
msgid "Wednesday"
msgstr ""
#: sabnzbd/interface.py:1795 # sabnzbd/skintext.py:84
#: sabnzbd/interface.py:1801 # sabnzbd/skintext.py:84
msgid "Thursday"
msgstr ""
#: sabnzbd/interface.py:1796 # sabnzbd/skintext.py:85
#: sabnzbd/interface.py:1802 # sabnzbd/skintext.py:85
msgid "Friday"
msgstr ""
#: sabnzbd/interface.py:1797 # sabnzbd/skintext.py:86
#: sabnzbd/interface.py:1803 # sabnzbd/skintext.py:86
msgid "Saturday"
msgstr ""
#: sabnzbd/interface.py:1798 # sabnzbd/skintext.py:87
#: sabnzbd/interface.py:1804 # sabnzbd/skintext.py:87
msgid "Sunday"
msgstr ""
#: sabnzbd/interface.py:2175
#: sabnzbd/interface.py:2178
msgid "&nbsp;Resolving address"
msgstr ""
#: sabnzbd/interface.py:2276
#: sabnzbd/interface.py:2279
msgid "Incorrect parameter"
msgstr ""
#: sabnzbd/interface.py:2276 # sabnzbd/interface.py:2302
#: sabnzbd/interface.py:2326 # sabnzbd/interface.py:2343
#: sabnzbd/interface.py:2428 # sabnzbd/interface.py:2447 # sabnzbd/skintext.py:98 [Generic "Back" button]
#: sabnzbd/interface.py:2279 # sabnzbd/interface.py:2305
#: sabnzbd/interface.py:2329 # sabnzbd/interface.py:2346
#: sabnzbd/interface.py:2431 # sabnzbd/interface.py:2450 # sabnzbd/skintext.py:98 [Generic "Back" button]
msgid "Back"
msgstr ""
#: sabnzbd/interface.py:2343
#: sabnzbd/interface.py:2346
msgid "Job \"%s\" was re-added to the queue"
msgstr ""
#: sabnzbd/interface.py:2428
#: sabnzbd/interface.py:2431
msgid "Jobs marked with a '*' will not be automatically downloaded."
msgstr ""
#: sabnzbd/interface.py:2428 # sabnzbd/skintext.py:493 [Config->RSS section header]
#: sabnzbd/interface.py:2431 # sabnzbd/skintext.py:493 [Config->RSS section header]
msgid "Matched"
msgstr ""
#: sabnzbd/interface.py:2429
#: sabnzbd/interface.py:2432
msgid "Not matched"
msgstr ""
#: sabnzbd/interface.py:2429 # sabnzbd/skintext.py:495 [Config->RSS section header]
#: sabnzbd/interface.py:2432 # sabnzbd/skintext.py:495 [Config->RSS section header]
msgid "Downloaded"
msgstr ""
#: sabnzbd/interface.py:2447
#: sabnzbd/interface.py:2450
msgid "Downloaded so far"
msgstr ""
#: sabnzbd/interface.py:2492
#: sabnzbd/interface.py:2495
msgid "Incorrect value for %s: %s"
msgstr ""
#: sabnzbd/misc.py:329 [Error message] # sabnzbd/tvsort.py:148 [Error message]
#: sabnzbd/misc.py:333 [Error message] # sabnzbd/tvsort.py:151 [Error message]
msgid "Cannot create directory %s"
msgstr ""
#: sabnzbd/misc.py:335 [Error message]
#: sabnzbd/misc.py:339 [Error message]
msgid "%s directory: %s error accessing"
msgstr ""
#: sabnzbd/misc.py:357 [Error message]
#: sabnzbd/misc.py:361 [Error message]
msgid "Cannot connect to registry hive HKEY_CURRENT_USER."
msgstr ""
#: sabnzbd/misc.py:364 [Error message]
#: sabnzbd/misc.py:368 [Error message]
msgid "Cannot open registry key \"%s\"."
msgstr ""
#: sabnzbd/misc.py:391 [Error message]
#: sabnzbd/misc.py:395 [Error message]
msgid "Failed to read registry keys for special folders"
msgstr ""
#: sabnzbd/misc.py:720 [Error message]
#: sabnzbd/misc.py:724 [Error message]
msgid "Failed making (%s)"
msgstr ""
#: sabnzbd/misc.py:744 [Error message]
#: sabnzbd/misc.py:748 [Error message]
msgid "Failed moving %s to %s"
msgstr ""
#: sabnzbd/misc.py:860
#: sabnzbd/misc.py:864
msgid "Unusable NZB file"
msgstr ""
#: sabnzbd/misc.py:871
#: sabnzbd/misc.py:875
msgid "Try again"
msgstr ""
#: sabnzbd/misc.py:871
#: sabnzbd/misc.py:875
msgid "URL Fetching failed; %s"
msgstr ""
#: sabnzbd/misc.py:1025 [Warning message]
#: sabnzbd/misc.py:1029 [Warning message]
msgid "pyopenssl module missing, please install for https access"
msgstr ""
#: sabnzbd/misc.py:1043 [Error message]
#: sabnzbd/misc.py:1047 [Error message]
msgid "Error creating SSL key and certificate"
msgstr ""
#: sabnzbd/newsunpack.py:297
#: sabnzbd/newsunpack.py:298
msgid "Expected size did not equal actual size"
msgstr ""
#: sabnzbd/newsunpack.py:298 # sabnzbd/newsunpack.py:355
#: sabnzbd/newsunpack.py:363
msgid "File join of %s failed"
msgstr ""
#: sabnzbd/newsunpack.py:299 # sabnzbd/newsunpack.py:356
#: sabnzbd/newsunpack.py:364
msgid "File join of %s failed"
msgstr ""
#: sabnzbd/newsunpack.py:300 # sabnzbd/newsunpack.py:357
#: sabnzbd/newsunpack.py:365
msgid "[%s] Error \"%s\" while joining files"
msgstr ""
#: sabnzbd/newsunpack.py:300 [Error message] # sabnzbd/newsunpack.py:357 [Error message]
#: sabnzbd/newsunpack.py:365 [Error message]
#: sabnzbd/newsunpack.py:301 [Error message] # sabnzbd/newsunpack.py:358 [Error message]
#: sabnzbd/newsunpack.py:366 [Error message]
msgid "Error \"%s\" while running file_join on %s"
msgstr ""
#: sabnzbd/newsunpack.py:339
#: sabnzbd/newsunpack.py:340
msgid "Joining"
msgstr ""
#: sabnzbd/newsunpack.py:350
#: sabnzbd/newsunpack.py:351
msgid "[%s] Joined %s files"
msgstr ""
#: sabnzbd/newsunpack.py:412 # sabnzbd/newsunpack.py:709
#: sabnzbd/newsunpack.py:413 # sabnzbd/newsunpack.py:718
msgid "Unpacking failed, %s"
msgstr ""
#: sabnzbd/newsunpack.py:414
#: sabnzbd/newsunpack.py:415
msgid "[%s] Error \"%s\" while unpacking RAR files"
msgstr ""
#: sabnzbd/newsunpack.py:416 [Error message]
#: sabnzbd/newsunpack.py:417 [Error message]
msgid "Error \"%s\" while running rar_unpack on %s"
msgstr ""
#: sabnzbd/newsunpack.py:431 [Warning message] # sabnzbd/newsunpack.py:440 [Warning message]
#: sabnzbd/newsunpack.py:694 [Warning message] # sabnzbd/newsunpack.py:704 [Warning message]
#: sabnzbd/newsunpack.py:806 [Warning message] # sabnzbd/newsunpack.py:816 [Warning message]
#: sabnzbd/newsunpack.py:823 [Warning message] # sabnzbd/newsunpack.py:830 [Warning message]
#: sabnzbd/newsunpack.py:845 [Warning message]
#: sabnzbd/newsunpack.py:432 [Warning message] # sabnzbd/newsunpack.py:441 [Warning message]
#: sabnzbd/newsunpack.py:703 [Warning message] # sabnzbd/newsunpack.py:713 [Warning message]
#: sabnzbd/newsunpack.py:815 [Warning message] # sabnzbd/newsunpack.py:825 [Warning message]
#: sabnzbd/newsunpack.py:832 [Warning message] # sabnzbd/newsunpack.py:839 [Warning message]
#: sabnzbd/newsunpack.py:854 [Warning message]
msgid "Deleting %s failed!"
msgstr ""
#: sabnzbd/newsunpack.py:539 # sabnzbd/newsunpack.py:559
#: sabnzbd/newsunpack.py:669
#: sabnzbd/newsunpack.py:540 # sabnzbd/newsunpack.py:560
#: sabnzbd/newsunpack.py:678
msgid "Unpacking"
msgstr ""
#: sabnzbd/newsunpack.py:563 # sabnzbd/newsunpack.py:564
#: sabnzbd/newsunpack.py:564 # sabnzbd/newsunpack.py:565
msgid "Unpacking failed, unable to find %s"
msgstr ""
#: sabnzbd/newsunpack.py:566 [Warning message]
#: sabnzbd/newsunpack.py:567 [Warning message]
msgid "ERROR: unable to find \"%s\""
msgstr ""
#: sabnzbd/newsunpack.py:571
#: sabnzbd/newsunpack.py:572
msgid "Unpacking failed, CRC error"
msgstr ""
#: sabnzbd/newsunpack.py:572 # sabnzbd/newsunpack.py:574 [Warning message]
#: sabnzbd/newsunpack.py:573 # sabnzbd/newsunpack.py:575 [Warning message]
msgid "ERROR: CRC failed in \"%s\""
msgstr ""
#: sabnzbd/newsunpack.py:578 # sabnzbd/newsunpack.py:579
#: sabnzbd/newsunpack.py:579 # sabnzbd/newsunpack.py:580
msgid "Unpacking failed, write error or disk is full?"
msgstr ""
#: sabnzbd/newsunpack.py:581 [Warning message]
#: sabnzbd/newsunpack.py:582 [Warning message]
msgid "ERROR: write error (%s)"
msgstr ""
#: sabnzbd/newsunpack.py:585
#: sabnzbd/newsunpack.py:586
msgid "Unpacking failed, see log"
msgstr ""
#: sabnzbd/newsunpack.py:586 [Warning message] # sabnzbd/newsunpack.py:587
#: sabnzbd/newsunpack.py:587 [Warning message] # sabnzbd/newsunpack.py:588
msgid "ERROR: %s"
msgstr ""
#: sabnzbd/newsunpack.py:593 # sabnzbd/newsunpack.py:594
#: sabnzbd/newsunpack.py:596 [Error message]
#: sabnzbd/newsunpack.py:602 # sabnzbd/newsunpack.py:603
#: sabnzbd/newsunpack.py:605 [Error message]
msgid "Unpacking failed, archive requires a password"
msgstr ""
#: sabnzbd/newsunpack.py:635
#: sabnzbd/newsunpack.py:644
msgid "Missing expected file: %s => unrar error?"
msgstr ""
#: sabnzbd/newsunpack.py:638
#: sabnzbd/newsunpack.py:647
msgid "Unpacking failed, an expected file was not unpacked"
msgstr ""
#: sabnzbd/newsunpack.py:640
#: sabnzbd/newsunpack.py:649
msgid "Unpacking failed, these file(s) are missing:"
msgstr ""
#: sabnzbd/newsunpack.py:647
#: sabnzbd/newsunpack.py:656
msgid "Unpacked %s files/folders in %s"
msgstr ""
#: sabnzbd/newsunpack.py:681
#: sabnzbd/newsunpack.py:690
msgid "%s files in %s"
msgstr ""
#: sabnzbd/newsunpack.py:710 [Error message]
#: sabnzbd/newsunpack.py:719 [Error message]
msgid "Error \"%s\" while running unzip() on %s"
msgstr ""
#: sabnzbd/newsunpack.py:753
#: sabnzbd/newsunpack.py:762
msgid "Quick Checking"
msgstr ""
#: sabnzbd/newsunpack.py:753 # sabnzbd/newsunpack.py:765 # sabnzbd/skintext.py:27 [PP phase "repair"]
#: sabnzbd/newsunpack.py:762 # sabnzbd/newsunpack.py:774 # sabnzbd/skintext.py:27 [PP phase "repair"]
#: sabnzbd/skintext.py:159 # sabnzbd/skintext.py:253
msgid "Repair"
msgstr ""
#: sabnzbd/newsunpack.py:757
#: sabnzbd/newsunpack.py:766
msgid "[%s] Quick Check OK"
msgstr ""
#: sabnzbd/newsunpack.py:765
#: sabnzbd/newsunpack.py:774
msgid "Starting Repair"
msgstr ""
#: sabnzbd/newsunpack.py:789 # sabnzbd/newsunpack.py:848
#: sabnzbd/newsunpack.py:798 # sabnzbd/newsunpack.py:857
msgid "Repairing failed, %s"
msgstr ""
#: sabnzbd/newsunpack.py:790 [Error message]
#: sabnzbd/newsunpack.py:799 [Error message]
msgid "Error %s while running par2_repair on set %s"
msgstr ""
#: sabnzbd/newsunpack.py:849 [Error message]
#: sabnzbd/newsunpack.py:858 [Error message]
msgid "Error \"%s\" while running par2_repair on set %s"
msgstr ""
#: sabnzbd/newsunpack.py:927
#: sabnzbd/newsunpack.py:937
msgid "[%s] PAR2 received incorrect options, check your Config->Switches settings"
msgstr ""
#: sabnzbd/newsunpack.py:932
#: sabnzbd/newsunpack.py:942
msgid "[%s] Verified in %s, all files correct"
msgstr ""
#: sabnzbd/newsunpack.py:939
#: sabnzbd/newsunpack.py:949
msgid "[%s] Verified in %s, repair is required"
msgstr ""
#: sabnzbd/newsunpack.py:948
#: sabnzbd/newsunpack.py:958
msgid "Main packet not found..."
msgstr ""
#: sabnzbd/newsunpack.py:968
#: sabnzbd/newsunpack.py:978
msgid "Invalid par2 files, cannot verify or repair"
msgstr ""
#: sabnzbd/newsunpack.py:1009 # sabnzbd/newsunpack.py:1041
#: sabnzbd/newsunpack.py:1019 # sabnzbd/newsunpack.py:1051
msgid "Repair failed, not enough repair blocks (%s short)"
msgstr ""
#: sabnzbd/newsunpack.py:1036
#: sabnzbd/newsunpack.py:1046
msgid "Fetching %s blocks..."
msgstr ""
#: sabnzbd/newsunpack.py:1038
#: sabnzbd/newsunpack.py:1048
msgid "Fetching"
msgstr ""
#: sabnzbd/newsunpack.py:1050 # sabnzbd/newsunpack.py:1055
#: sabnzbd/newsunpack.py:1060 # sabnzbd/newsunpack.py:1065
msgid "Repairing"
msgstr ""
#: sabnzbd/newsunpack.py:1059
#: sabnzbd/newsunpack.py:1069
msgid "[%s] Repaired in %s"
msgstr ""
#: sabnzbd/newsunpack.py:1077 # sabnzbd/newsunpack.py:1095
#: sabnzbd/newsunpack.py:1087 # sabnzbd/newsunpack.py:1105
msgid "Verifying"
msgstr ""
@@ -705,11 +761,11 @@ msgstr ""
msgid "Newzbin server changed its protocol"
msgstr ""
#: sabnzbd/newzbin.py:224 # sabnzbd/newzbin.py:329 [Warning message]
#: sabnzbd/newzbin.py:224 # sabnzbd/newzbin.py:334 [Warning message]
msgid "You have no credit on your Newzbin account"
msgstr ""
#: sabnzbd/newzbin.py:228 # sabnzbd/newzbin.py:327 [Warning message]
#: sabnzbd/newzbin.py:228 # sabnzbd/newzbin.py:332 [Warning message]
msgid "Unauthorised, check your newzbin username/password"
msgstr ""
@@ -725,11 +781,11 @@ msgstr ""
msgid "Newzbin server fails to give info for %s"
msgstr ""
#: sabnzbd/newzbin.py:340 [Warning message]
#: sabnzbd/newzbin.py:345 [Warning message]
msgid "Could not delete newzbin bookmark %s"
msgstr ""
#: sabnzbd/newzbin.py:352 [Error message]
#: sabnzbd/newzbin.py:357 [Error message]
msgid "Newzbin gives undocumented error code (%s)"
msgstr ""
@@ -1038,91 +1094,99 @@ msgstr ""
msgid "Download failed - Out of your server's retention?"
msgstr ""
#: sabnzbd/postproc.py:296
#: sabnzbd/postproc.py:298
msgid "Cannot create final folder %s"
msgstr ""
#: sabnzbd/postproc.py:318
#: sabnzbd/postproc.py:320
msgid "No post-processing because of failed verification"
msgstr ""
#: sabnzbd/postproc.py:326
#: sabnzbd/postproc.py:328
msgid "Moving"
msgstr ""
#: sabnzbd/postproc.py:350
#: sabnzbd/postproc.py:352
msgid "Sent %s to queue"
msgstr ""
#: sabnzbd/postproc.py:369 [Error message]
#: sabnzbd/postproc.py:371 [Error message]
msgid "Error renaming \"%s\" to \"%s\""
msgstr ""
#: sabnzbd/postproc.py:388
#: sabnzbd/postproc.py:390
msgid "Running script"
msgstr ""
#: sabnzbd/postproc.py:389
#: sabnzbd/postproc.py:391
msgid "Running user script %s"
msgstr ""
#: sabnzbd/postproc.py:398
#: sabnzbd/postproc.py:400
msgid "Ran %s"
msgstr ""
#: sabnzbd/postproc.py:419
#: sabnzbd/postproc.py:421
msgid "More"
msgstr ""
#: sabnzbd/postproc.py:423
#: sabnzbd/postproc.py:425
msgid "View script output"
msgstr ""
#: sabnzbd/postproc.py:436
#: sabnzbd/postproc.py:439
msgid "Download Completed"
msgstr ""
#: sabnzbd/postproc.py:439 # sabnzbd/postproc.py:448
#: sabnzbd/postproc.py:442 # sabnzbd/postproc.py:451
msgid "Download Failed"
msgstr ""
#: sabnzbd/postproc.py:443 [Error message]
#: sabnzbd/postproc.py:446 [Error message]
msgid "Post Processing Failed for %s (%s)"
msgstr ""
#: sabnzbd/postproc.py:446
#: sabnzbd/postproc.py:449
msgid "see logfile"
msgstr ""
#: sabnzbd/postproc.py:447
#: sabnzbd/postproc.py:450
msgid "PostProcessing was aborted (%s)"
msgstr ""
#: sabnzbd/postproc.py:475 [Error message]
#: sabnzbd/postproc.py:478 [Error message]
msgid "Cleanup of %s failed."
msgstr ""
#: sabnzbd/postproc.py:485 [Error message]
#: sabnzbd/postproc.py:488 [Error message]
msgid "Error removing workdir (%s)"
msgstr ""
#: sabnzbd/postproc.py:497
#: sabnzbd/postproc.py:500
msgid "Post-processing"
msgstr ""
#: sabnzbd/postproc.py:536
#: sabnzbd/postproc.py:540
msgid "Trying SFV verification"
msgstr ""
#: sabnzbd/postproc.py:543
msgid "Some files failed to verify against \"%s\""
msgstr ""
#: sabnzbd/postproc.py:540
#: sabnzbd/postproc.py:546
msgid "Verified successfully using SFV files"
msgstr ""
#: sabnzbd/postproc.py:549
msgid "[%s] No par2 sets"
msgstr ""
#: sabnzbd/postproc.py:572 [Error message] # sabnzbd/postproc.py:579 [Error message]
#: sabnzbd/postproc.py:581 [Error message] # sabnzbd/postproc.py:588 [Error message]
msgid "Cannot change permissions of %s"
msgstr ""
#: sabnzbd/postproc.py:630 [Error message] # sabnzbd/postproc.py:705 [Error message]
#: sabnzbd/postproc.py:639 [Error message] # sabnzbd/postproc.py:714 [Error message]
msgid "Removing %s failed"
msgstr ""
@@ -2804,7 +2868,7 @@ msgid "Test Notification"
msgstr ""
#: sabnzbd/skintext.py:536
msgid "If you have an account at <strong>www.newzbin.com</strong>, you can enter your account info here.<br />This will unlock extra functionality."
msgid "If you have an account at <strong>www.newzbin2.es</strong>, you can enter your account info here.<br />This will unlock extra functionality."
msgstr ""
#: sabnzbd/skintext.py:537
@@ -3748,15 +3812,15 @@ msgid ""
"It is licensed under the GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version.\n"
msgstr ""
#: sabnzbd/tvsort.py:288 [Error message]
#: sabnzbd/tvsort.py:291 [Error message]
msgid "Error getting TV info (%s)"
msgstr ""
#: sabnzbd/tvsort.py:636 [Error message] # sabnzbd/tvsort.py:659 [Error message] # sabnzbd/tvsort.py:840 [Error message]
#: sabnzbd/tvsort.py:639 [Error message] # sabnzbd/tvsort.py:662 [Error message] # sabnzbd/tvsort.py:843 [Error message]
msgid "Failed to rename: %s to %s"
msgstr ""
#: sabnzbd/tvsort.py:1035 [Error message]
#: sabnzbd/tvsort.py:1038 [Error message]
msgid "Failed to rename similar file: %s to %s"
msgstr ""
@@ -3768,71 +3832,3 @@ msgstr ""
msgid "Invalid nzbmatrix report number %s"
msgstr ""
#: sabnzbd/utils/osx.py:31 [Message class for Growl server]
msgid "Startup/Shutdown"
msgstr ""
#: sabnzbd/utils/osx.py:32 [Message class for Growl server]
msgid "Added NZB"
msgstr ""
#: sabnzbd/utils/osx.py:33 [Message class for Growl server]
msgid "Post-processing started"
msgstr ""
#: sabnzbd/utils/osx.py:34 [Message class for Growl server]
msgid "Job finished"
msgstr ""
#: sabnzbd/utils/osx.py:35 [Message class for Growl server]
msgid "Other Messages"
msgstr ""
#: sabnzbd/utils/servertests.py:35
msgid "The hostname is not set."
msgstr ""
#: sabnzbd/utils/servertests.py:41
msgid "There are no connections set. Please set at least one connection."
msgstr ""
#: sabnzbd/utils/servertests.py:74
msgid "Password masked in ******, please re-enter"
msgstr ""
#: sabnzbd/utils/servertests.py:78
msgid "Invalid server details"
msgstr ""
#: sabnzbd/utils/servertests.py:90
msgid "Timed out: Try enabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py:92
msgid "Timed out"
msgstr ""
#: sabnzbd/utils/servertests.py:97
msgid "Invalid server address."
msgstr ""
#: sabnzbd/utils/servertests.py:119
msgid "Server requires username and password."
msgstr ""
#: sabnzbd/utils/servertests.py:122
msgid "Connection Successful!"
msgstr ""
#: sabnzbd/utils/servertests.py:125
msgid "Authentication failed, check username/password."
msgstr ""
#: sabnzbd/utils/servertests.py:128
msgid "Too many connections, please pause downloading or try again later"
msgstr ""
#: sabnzbd/utils/servertests.py:131
msgid "Could not determine connection result (%s)"
msgstr ""

View File

@@ -64,15 +64,15 @@ msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s modtaget, gemmer og lukker..."
#: sabnzbd/__init__.py:442
msgid "fetching msgid %s from www.newzbin.com"
msgstr "henter msgid %s fra www.newzbin.com"
msgid "fetching msgid %s from www.newzbin2.es"
msgstr "henter msgid %s fra www.newzbin2.es"
#: sabnzbd/__init__.py:448 [Error message]
msgid ""
"Error Fetching msgid %s from www.newzbin.com - Please make sure your "
"Error Fetching msgid %s from www.newzbin2.es - Please make sure your "
"Username and Password are set"
msgstr ""
"Fejl ved hentning af msgid %s fra www.newzbin.com - Sørg for at dit "
"Fejl ved hentning af msgid %s fra www.newzbin2.es - Sørg for at dit "
"brugernavn og kodeord er fastsat"
#: sabnzbd/__init__.py:460
@@ -3002,10 +3002,10 @@ msgstr "Afprøv notifikation"
#: sabnzbd/skintext.py:543
msgid ""
"If you have an account at <strong>www.newzbin.com</strong>, you can enter "
"If you have an account at <strong>www.newzbin2.es</strong>, you can enter "
"your account info here.<br />This will unlock extra functionality."
msgstr ""
"Hvis du har en konto til <strong>www.newzbin.com</strong>, kan du skrive "
"Hvis du har en konto til <strong>www.newzbin2.es</strong>, kan du skrive "
"dine bruger informationer her.<br />Dette vil frigøre ekstra funktionalitet."
#: sabnzbd/skintext.py:544

View File

@@ -66,15 +66,15 @@ msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s erkannt. Speichern und beenden..."
#: sabnzbd/__init__.py:442
msgid "fetching msgid %s from www.newzbin.com"
msgstr "Abrufen der Download-ID %s von newzbin.com"
msgid "fetching msgid %s from www.newzbin2.es"
msgstr "Abrufen der Download-ID %s von newzbin2.es"
#: sabnzbd/__init__.py:448 [Error message]
msgid ""
"Error Fetching msgid %s from www.newzbin.com - Please make sure your "
"Error Fetching msgid %s from www.newzbin2.es - Please make sure your "
"Username and Password are set"
msgstr ""
"Fehler beim Abrufen der Download-ID %s von newzbin.com - Überprüfen Sie, ob "
"Fehler beim Abrufen der Download-ID %s von newzbin2.es - Überprüfen Sie, ob "
"der Benutzername und das Passwort korrekt eingegeben wurden."
#: sabnzbd/__init__.py:460
@@ -3064,10 +3064,10 @@ msgstr "Benachrichtigungen testen"
#: sabnzbd/skintext.py:543
msgid ""
"If you have an account at <strong>www.newzbin.com</strong>, you can enter "
"If you have an account at <strong>www.newzbin2.es</strong>, you can enter "
"your account info here.<br />This will unlock extra functionality."
msgstr ""
"Wenn Sie ein Konto bei <strong>www.newzbin.com</strong> haben, können Sie "
"Wenn Sie ein Konto bei <strong>www.newzbin2.es</strong> haben, können Sie "
"die entsprechenden Informationen hier eintragen.<br />Dies gibt weitere "
"Funktionen frei."

View File

File diff suppressed because it is too large Load Diff

View File

@@ -63,15 +63,15 @@ msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s mottatt, lagrer og avslutter..."
#: sabnzbd/__init__.py:442
msgid "fetching msgid %s from www.newzbin.com"
msgstr "henter msgid %s fra www.newzbin.com"
msgid "fetching msgid %s from www.newzbin2.es"
msgstr "henter msgid %s fra www.newzbin2.es"
#: sabnzbd/__init__.py:448 [Error message]
msgid ""
"Error Fetching msgid %s from www.newzbin.com - Please make sure your "
"Error Fetching msgid %s from www.newzbin2.es - Please make sure your "
"Username and Password are set"
msgstr ""
"Feil ved henting av msgid %s fra www.newzbin.com - Sjekk at brukernavn og "
"Feil ved henting av msgid %s fra www.newzbin2.es - Sjekk at brukernavn og "
"passord er satt korrekt"
#: sabnzbd/__init__.py:460
@@ -2921,10 +2921,10 @@ msgstr ""
#: sabnzbd/skintext.py:543
msgid ""
"If you have an account at <strong>www.newzbin.com</strong>, you can enter "
"If you have an account at <strong>www.newzbin2.es</strong>, you can enter "
"your account info here.<br />This will unlock extra functionality."
msgstr ""
"Om du har konto på <strong>www.newzbin.com</strong>, så kan du skrive inn "
"Om du har konto på <strong>www.newzbin2.es</strong>, så kan du skrive inn "
"bruker informasjon her.<br />Dette åpner for ekstra funksjoner."
#: sabnzbd/skintext.py:544

View File

@@ -66,15 +66,15 @@ msgid "Signal %s caught, saving and exiting..."
msgstr "Signaal %s ontvangen, opslaan en afluiten..."
#: sabnzbd/__init__.py:442
msgid "fetching msgid %s from www.newzbin.com"
msgstr "Ophalen rapport %s van www.newzbin.com"
msgid "fetching msgid %s from www.newzbin2.es"
msgstr "Ophalen rapport %s van www.newzbin2.es"
#: sabnzbd/__init__.py:448 [Error message]
msgid ""
"Error Fetching msgid %s from www.newzbin.com - Please make sure your "
"Error Fetching msgid %s from www.newzbin2.es - Please make sure your "
"Username and Password are set"
msgstr ""
"Fout bij ophalen van rapport %s van www.newzbin.com - Zorg dat je "
"Fout bij ophalen van rapport %s van www.newzbin2.es - Zorg dat je "
"gebruikersnaam en wachtwoord goed ingevuld zijn"
#: sabnzbd/__init__.py:460
@@ -923,7 +923,7 @@ msgstr "Herstarten"
#: sabnzbd/osxmenu.py:325
msgid "Queue First 10 Items"
msgstr "Wachtrij Eersto 10 Items"
msgstr "Wachtrij Eerste 10 Items"
#: sabnzbd/osxmenu.py:349 # sabnzbd/osxmenu.py:390
msgid "Empty"
@@ -3013,10 +3013,10 @@ msgstr "Test Melding"
#: sabnzbd/skintext.py:543
msgid ""
"If you have an account at <strong>www.newzbin.com</strong>, you can enter "
"If you have an account at <strong>www.newzbin2.es</strong>, you can enter "
"your account info here.<br />This will unlock extra functionality."
msgstr ""
"Wanneer je een account bij <strong>www.newzbin.com</strong> hebt, kun je "
"Wanneer je een account bij <strong>www.newzbin2.es</strong> hebt, kun je "
"hier je gegevens invullen.<br />Dit maakt extra mogelijkheden beschikbaar."
#: sabnzbd/skintext.py:544

View File

@@ -62,15 +62,15 @@ msgid "Signal %s caught, saving and exiting..."
msgstr "Semnal %s prins, salvez şi ies..."
#: sabnzbd/__init__.py:442
msgid "fetching msgid %s from www.newzbin.com"
msgstr "descarc msgid %s de la www.newzbin.com"
msgid "fetching msgid %s from www.newzbin2.es"
msgstr "descarc msgid %s de la www.newzbin2.es"
#: sabnzbd/__init__.py:448 [Error message]
msgid ""
"Error Fetching msgid %s from www.newzbin.com - Please make sure your "
"Error Fetching msgid %s from www.newzbin2.es - Please make sure your "
"Username and Password are set"
msgstr ""
"Eroare Descărcare msgid %s de la www.newzbin.com - Vă rugăm asiguraţi-vă că "
"Eroare Descărcare msgid %s de la www.newzbin2.es - Vă rugăm asiguraţi-vă că "
"Numele de Utilizator şi Parola sunt stabilite"
#: sabnzbd/__init__.py:460
@@ -3020,10 +3020,10 @@ msgstr "Notificări Test"
#: sabnzbd/skintext.py:543
msgid ""
"If you have an account at <strong>www.newzbin.com</strong>, you can enter "
"If you have an account at <strong>www.newzbin2.es</strong>, you can enter "
"your account info here.<br />This will unlock extra functionality."
msgstr ""
"Dacă aveţi un cont la <strong>www.newzbin.com</strong>, puteţi introduce "
"Dacă aveţi un cont la <strong>www.newzbin2.es</strong>, puteţi introduce "
"informatiile contului dvs. aici.<br />Aceasta va debloca funcţionalitate "
"extra."

View File

@@ -63,15 +63,15 @@ msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s mottagen, sparar och stänger..."
#: sabnzbd/__init__.py:442
msgid "fetching msgid %s from www.newzbin.com"
msgstr "hämtar msgid %s från www.newzbin.com"
msgid "fetching msgid %s from www.newzbin2.es"
msgstr "hämtar msgid %s från www.newzbin2.es"
#: sabnzbd/__init__.py:448 [Error message]
msgid ""
"Error Fetching msgid %s from www.newzbin.com - Please make sure your "
"Error Fetching msgid %s from www.newzbin2.es - Please make sure your "
"Username and Password are set"
msgstr ""
"Fel vid hämtning av msgid %s från www.newzbin.com - Kolla så att "
"Fel vid hämtning av msgid %s från www.newzbin2.es - Kolla så att "
"användarnamn och lösenord är inställt"
#: sabnzbd/__init__.py:460
@@ -2921,10 +2921,10 @@ msgstr ""
#: sabnzbd/skintext.py:543
msgid ""
"If you have an account at <strong>www.newzbin.com</strong>, you can enter "
"If you have an account at <strong>www.newzbin2.es</strong>, you can enter "
"your account info here.<br />This will unlock extra functionality."
msgstr ""
"Om du har ett konto på <strong>www.newzbin.com</strong>, så kan du skriva in "
"Om du har ett konto på <strong>www.newzbin2.es</strong>, så kan du skriva in "
"din användarinformation här.<br />Detta kommer att tillgängliggöra extra "
"funktioner."

View File

@@ -1,22 +1,21 @@
#
# SABnzbd Translation Template file NSIS
# Copyright (C) 2010 by the SABnzbd Team
# team@sabnzbd.org
# French translation for sabnzbd
# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
# This file is distributed under the same license as the sabnzbd package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-0.6.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-08-20 14:21+0000\n"
"PO-Revision-Date: 2011-03-10 21:33+0000\n"
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-08-20 14:31+0000\n"
"PO-Revision-Date: 2011-07-27 21:16+0000\n"
"Last-Translator: Fox Ace <Unknown>\n"
"Language-Team: FRANCAIS <LL@li.org>\n"
"Language-Team: French <fr@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-08-21 04:51+0000\n"
"X-Launchpad-Export-Date: 2011-08-21 05:10+0000\n"
"X-Generator: Launchpad (build 13697)\n"
"Language: fr\n"
#: NSIS_Installer.nsi:408
msgid "Start SABnzbd (hidden)"
@@ -74,3 +73,32 @@ msgstr "Supprimer les logs"
#: NSIS_Installer.nsi:516
msgid "Delete Cache"
msgstr "Supprimer le Cache"
#: NSIS_Installer.nsi:525
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
msgstr ""
"Ce système nécessite que la bibliothèque d'exécution Microsoft vc90 soit "
"installée en premier. Voulez-vous le faire maintenant?"
#: NSIS_Installer.nsi:534
msgid "Downloading Microsoft runtime installer..."
msgstr "Téléchargement de Microsoft runtime installateur ..."
#: NSIS_Installer.nsi:543
msgid "Download error, retry?"
msgstr "Erreur téléchargement, réessayer?"
#: NSIS_Installer.nsi:552
msgid "Cannot install without runtime library, retry?"
msgstr "Impossible d'installer sans bibliothèque d'exécution, réessayer?"
#: NSIS_Installer.nsi:561
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
msgstr ""
"Vous ne pouvez pas remplacer une installation existante. \\n\\nCliquez `OK` "
"pour supprimer la version précédente ou `Annuler` pour annuler cette mise à "
"niveau."

View File

@@ -23,7 +23,7 @@ import os
import logging
import datetime
import tempfile
import cPickle
import cPickle, pickle
import zipfile
import glob
import gzip
@@ -425,14 +425,14 @@ def add_msgid(msgid, pp=None, script=None, cat=None, priority=None, nzbname=None
if cat and cat.lower()=='default': cat = None
if cfg.newzbin_username() and cfg.newzbin_password():
logging.info('Fetching msgid %s from www.newzbin.com', msgid)
msg = T('fetching msgid %s from www.newzbin.com') % msgid
logging.info('Fetching msgid %s from www.newzbin2.es', msgid)
msg = T('fetching msgid %s from www.newzbin2.es') % msgid
future_nzo = NzbQueue.do.generate_future(msg, pp, script, cat=cat, url=msgid, priority=priority, nzbname=nzbname)
MSGIDGrabber.do.grab(msgid, future_nzo)
else:
logging.error(Ta('Error Fetching msgid %s from www.newzbin.com - Please make sure your Username and Password are set'), msgid)
logging.error(Ta('Error Fetching msgid %s from www.newzbin2.es - Please make sure your Username and Password are set'), msgid)
def add_url(url, pp=None, script=None, cat=None, priority=None, nzbname=None):
@@ -772,7 +772,10 @@ def save_data(data, _id, path, do_pickle = True, silent=False):
try:
_f = open(path, 'wb')
if do_pickle:
pickler = cPickle.Pickler(_f, 2)
if cfg.use_pickle():
pickler = pickle.Pickler(_f, 2)
else:
pickler = cPickle.Pickler(_f, 2)
pickler.dump(data)
_f.flush()
_f.close()
@@ -785,6 +788,8 @@ def save_data(data, _id, path, do_pickle = True, silent=False):
except:
logging.error(Ta('Saving %s failed'), path)
logging.info("Traceback: ", exc_info = True)
return False
return misc.has_substance(path)
@synchronized(IO_LOCK)
@@ -802,7 +807,10 @@ def load_data(_id, path, remove=True, do_pickle=True, silent=False):
try:
_f = open(path, 'rb')
if do_pickle:
data = cPickle.load(_f)
if cfg.use_pickle():
data = pickle.load(_f)
else:
data = cPickle.load(_f)
else:
data = _f.read()
_f.close()

View File

@@ -25,6 +25,8 @@ import re
import datetime
import time
import cherrypy
import locale
locale.setlocale(locale.LC_ALL, "")
try:
import win32api, win32file
except ImportError:
@@ -280,8 +282,13 @@ def _api_addfile(name, output, kwargs):
# Normal upload will send the nzb in a kw arg called nzbfile
if name is None or isinstance(name, str) or isinstance(name, unicode):
name = kwargs.get('nzbfile')
if name is not None and name.filename and name.value:
if hasattr(name, 'getvalue'):
#Side effect of next line is that attribute .value is created
#which is needed to make add_nzbfile() work
size = name.length
else:
size = len(name.value)
if name is not None and name.filename and size:
sabnzbd.add_nzbfile(name, kwargs.get('pp'), kwargs.get('script'), kwargs.get('cat'),
kwargs.get('priority'), kwargs.get('nzbname'))
return report(output)
@@ -537,7 +544,7 @@ def _api_auth(name, output, kwargs):
def _api_newzbin(name, output, kwargs):
""" API: accepts output """
if name == 'get_bookmarks':
Bookmarks.do.run()
Bookmarks.do.run(force=True)
return report(output)
return report(output, _MSG_NOT_IMPLEMENTED)
@@ -1031,6 +1038,9 @@ def build_queue(web_dir=None, root=None, verbose=False, prim=True, verbose_list=
slot['cat'] = cat
slot['mbleft'] = "%.2f" % mbleft
slot['mb'] = "%.2f" % mb
if not output:
slot['mb_fmt'] = locale.format('%d', int(mb), True)
slot['mbdone_fmt'] = locale.format('%d', int(mb-mbleft), True)
slot['size'] = format_bytes(bytes)
slot['sizeleft'] = format_bytes(bytesleft)
if not Downloader.do.paused and status != 'Paused' and status != 'Fetching' and not found_active:
@@ -1327,7 +1337,7 @@ def rss_qstatus():
item = Item()
item.title = name
if msgid:
item.link = "https://newzbin.com/browse/post/%s/" % msgid
item.link = "https://%s/browse/post/%s/" % (cfg.newzbin_url(), msgid)
else:
item.link = "http://%s:%s/sabnzbd/history" % ( \
cfg.cherryhost(), cfg.cherryport() )
@@ -1467,6 +1477,7 @@ def build_header(prim):
header['have_warnings'] = str(sabnzbd.GUIHANDLER.count())
header['last_warning'] = sabnzbd.GUIHANDLER.last().replace('WARNING', Ta('WARNING:')).replace('ERROR', Ta('ERROR:'))
header['active_lang'] = cfg.language()
header['newzbin_url'] = cfg.newzbin_url()
if prim:
header['webdir'] = sabnzbd.WEB_DIR
else:

View File

@@ -40,7 +40,7 @@ from sabnzbd.articlecache import ArticleCache
from sabnzbd.postproc import PostProcessor
import sabnzbd.downloader
from sabnzbd.utils.rarfile import RarFile, is_rarfile
from sabnzbd.encoding import latin1
from sabnzbd.encoding import latin1, unicoder
#------------------------------------------------------------------------------
@@ -269,13 +269,23 @@ def ParseFilePacket(f, header):
return nothing
def is_cloaked(path, names):
""" Return True if this is likely to be a cloaked encrypted post """
fname = unicoder(os.path.split(path)[1]).lower()
for name in names:
name = unicoder(name.lower())
if fname == name or 'password' in name:
return True
return False
def check_encrypted_rar(nzo, filepath):
""" Check if file is rar and is encrypted """
encrypted = False
if not nzo.password and cfg.pause_on_pwrar() and is_rarfile(filepath):
try:
zf = RarFile(filepath)
encrypted = zf.encrypted
zf = RarFile(filepath, all_names=True)
encrypted = zf.encrypted or is_cloaked(filepath, zf.namelist())
if encrypted and int(nzo.encrypted) < 2:
nzo.encrypted = 1
else:

View File

@@ -105,6 +105,7 @@ newzbin_password = OptionPassword('newzbin', 'password')
newzbin_bookmarks = OptionBool('newzbin', 'bookmarks', False)
newzbin_unbookmark = OptionBool('newzbin', 'unbookmark', True)
bookmark_rate = OptionNumber('newzbin', 'bookmark_rate', 60, minval=15, maxval=24*60)
newzbin_url = OptionStr('newzbin', 'url', 'www.newzbin2.es')
top_only = OptionBool('misc', 'top_only', False)
autodisconnect = OptionBool('misc', 'auto_disconnect', True)
@@ -159,7 +160,7 @@ nzb_backup_dir = OptionDir('misc', 'nzb_backup_dir', DEF_NZBBACK_DIR)
cache_dir = OptionDir('misc', 'cache_dir', 'cache', create=False, validation=validate_safedir)
admin_dir = OptionDir('misc', 'admin_dir', DEF_ADMIN_DIR, validation=validate_safedir)
#log_dir = OptionDir('misc', 'log_dir', 'logs')
dirscan_dir = OptionDir('misc', 'dirscan_dir', create=True)
dirscan_dir = OptionDir('misc', 'dirscan_dir', create=False)
dirscan_speed = OptionNumber('misc', 'dirscan_speed', DEF_SCANRATE, 0, 3600)
SIZE_LIMIT = OptionStr('misc', 'size_limit')
password_file = OptionDir('misc', 'password_file', '', create=False)
@@ -204,6 +205,8 @@ ssl_type = OptionStr('misc', 'ssl_type', 'v23')
unpack_check = OptionBool('misc', 'unpack_check', True)
no_penalties = OptionBool('misc', 'no_penalties', False)
growl_enable = OptionBool('growl', 'growl_enable', True)
# Internal options, not saved in INI file
debug_delay = OptionNumber('misc', 'debug_delay', 0, add=False)
@@ -211,6 +214,7 @@ api_key = OptionStr('misc', 'api_key', create_api_key())
nzb_key = OptionStr('misc', 'nzb_key', create_api_key())
disable_key = OptionBool('misc', 'disable_api_key', False)
api_warnings = OptionBool('misc', 'api_warnings', True)
use_pickle = OptionBool('misc', 'use_pickle', False)
#------------------------------------------------------------------------------
# Set root folders for Folder config-items

View File

@@ -661,6 +661,9 @@ def read_config(path):
if 'misc' in CFG:
compatibility_fix(CFG['misc'])
if 'rss' in CFG:
newzbin_fix(CFG['rss'])
# Use CFG data to set values for all static options
for section in database:
if section not in ('servers', 'categories', 'rss'):
@@ -725,28 +728,42 @@ def save_config(force=False):
filename = CFG.filename
try:
# Check if file is writable
if not sabnzbd.misc.is_writable(filename):
logging.error(Ta('Cannot write to INI file %s'), filename)
modified = False
return False
# Read current content
f = open(CFG.filename)
f = open(filename)
data = f.read()
f.close()
# Write to temp file
CFG.filename = filename + '.tmp'
f = open(CFG.filename, 'w')
tmpname = filename + '.tmp'
bakname = filename + '.bak'
# Write new file
f = open(tmpname, 'w')
f.write(data)
f.close()
# Update temp file content
CFG.filename = tmpname
CFG.write()
# Rename to backup
if os.path.isfile(bakname):
os.remove(bakname)
os.rename(filename, bakname)
# Rename temp file, overwriting old one
os.remove(filename)
os.rename(CFG.filename, filename)
os.rename(tmpname, filename)
modified = False
res = True
except:
logging.error(Ta('Cannot create temp file for %s'), CFG.filename)
logging.error(Ta('Cannot create backup file for %s'), filename)
logging.info("Traceback: ", exc_info = True)
res = False
CFG.filename = filename
return res
@@ -970,3 +987,10 @@ def compatibility_fix(cf):
del cf[old]
except KeyError:
pass
def newzbin_fix(cf):
""" Replace old newzbin links """
for feed in cf:
item = cf[feed].get('uri')
if item and 'newzbin.com' in item:
cf[feed]['uri'] = item.replace('newzbin.com', 'newzbin2.es')

View File

@@ -312,7 +312,7 @@ def build_history_info(nzo, storage='', downpath='', postproc_time=0, script_out
# Get the url and newzbin msgid
report = decode_factory(nzo_info.get('msgid', ''))
if report:
url = 'https://newzbin.com/browse/post/%s/' % (report)
url = 'https://%s/browse/post/%s/' % (sabnzbd.cfg.newzbin_url(), report)
else:
url = decode_factory(nzo_info.get('url', ''))

View File

@@ -270,8 +270,8 @@ class DirScanner(threading.Thread):
time.sleep(1.0)
x = x - 1
self.trigger = False
if self.dirscan_speed and not self.shutdown:
self.trigger = False
self.scan()
def scan(self):

View File

@@ -414,21 +414,17 @@ class MainPage(object):
""" Duplicate of retry of History, needed for some skins """
msg = check_session(kwargs)
if msg: return msg
url = kwargs.get('url', '')
job = kwargs.get('job', '')
url = kwargs.get('url', '').strip()
pp = kwargs.get('pp')
cat = kwargs.get('cat')
script = kwargs.get('script')
url = url.strip()
if url and (url.isdigit() or len(url)==5):
sabnzbd.add_msgid(url, pp, script, cat)
elif url:
sabnzbd.add_url(url, pp, script, cat)
if url:
return ShowOK(url)
else:
raise dcRaiser(self.__root, kwargs)
sabnzbd.add_url(url, pp, script, cat, nzbname=kwargs.get('nzbname'))
del_hist_job(job, del_files=True)
raise dcRaiser(self.__root, kwargs)
@cherrypy.expose
def retry_pp(self, **kwargs):
@@ -971,6 +967,7 @@ class HistoryPage(object):
def retry(self, **kwargs):
msg = check_session(kwargs)
if msg: return msg
job = kwargs.get('job', '')
url = kwargs.get('url', '').strip()
pp = kwargs.get('pp')
cat = kwargs.get('cat')
@@ -979,10 +976,9 @@ class HistoryPage(object):
sabnzbd.add_msgid(url, pp, script, cat)
elif url:
sabnzbd.add_url(url, pp, script, cat, nzbname=kwargs.get('nzbname'))
if url:
return ShowOK(url)
else:
raise dcRaiser(self.__root, kwargs)
del_hist_job(job, del_files=True)
raise dcRaiser(self.__root, kwargs)
#------------------------------------------------------------------------------
class ConfigPage(object):
@@ -1111,7 +1107,7 @@ class ConfigDirectories(object):
value = kwargs.get(kw)
if value != None:
value = platform_encode(value)
if kw == 'complete_dir':
if kw in ('complete_dir', 'dirscan_dir'):
msg = config.get_config('misc', kw).set(value, create=True)
else:
msg = config.get_config('misc', kw).set(value)
@@ -1129,7 +1125,7 @@ SWITCH_LIST = \
'safe_postproc', 'no_dupes', 'replace_spaces', 'replace_dots', 'replace_illegal', 'auto_browser',
'ignore_samples', 'pause_on_post_processing', 'quick_check', 'nice', 'ionice',
'ssl_type', 'pre_script', 'pause_on_pwrar', 'ampm', 'sfv_check', 'folder_rename',
'unpack_check'
'unpack_check', 'growl_enable'
)
#------------------------------------------------------------------------------
@@ -1151,7 +1147,10 @@ class ConfigSwitches(object):
conf['have_ionice'] = bool(sabnzbd.newsunpack.IONICE_COMMAND)
for kw in SWITCH_LIST:
conf[kw] = config.get_config('misc', kw)()
if kw == 'growl_enable':
conf[kw] = config.get_config('growl', kw)()
else:
conf[kw] = config.get_config('misc', kw)()
conf['script_list'] = list_scripts() or ['None']
conf['have_ampm'] = HAVE_AMPM
@@ -1166,7 +1165,10 @@ class ConfigSwitches(object):
if msg: return msg
for kw in SWITCH_LIST:
item = config.get_config('misc', kw)
if kw == 'growl_enable':
item = config.get_config('growl', kw)
else:
item = config.get_config('misc', kw)
value = platform_encode(kwargs.get(kw))
msg = item.set(value)
if msg:
@@ -1966,7 +1968,7 @@ class ConfigNewzbin(object):
def getBookmarks(self, **kwargs):
msg = check_session(kwargs)
if msg: return msg
Bookmarks.do.run()
Bookmarks.do.run(force=True)
raise dcRaiser(self.__root, kwargs)
@cherrypy.expose
@@ -2346,7 +2348,7 @@ def GetRssLog(feed):
url = job.get('url', '')
title = xml_name(job.get('title', ''))
if url.isdigit():
title = '<a href="https://www.newzbin.com/browse/post/%s/" target="_blank">%s</a>' % (url, title)
title = '<a href="https://%s/browse/post/%s/" target="_blank">%s</a>' % (cfg.newzbin_url(), url, title)
else:
title = title
if sabnzbd.rss.special_rss_site(url):
@@ -2533,7 +2535,7 @@ def rss_history(url, limit=50, search=None):
youngest = history['completed']
if history['report']:
item.link = "https://www.newzbin.com/browse/post/%s/" % history['report']
item.link = "https://%s/browse/post/%s/" % (cfg.newzbin_url(), history['report'])
elif history['url_info']:
item.link = history['url_info']
else:

View File

@@ -30,6 +30,7 @@ import subprocess
import socket
import time
import glob
import stat
import sabnzbd
from sabnzbd.decorators import synchronized
@@ -301,7 +302,10 @@ def real_path(loc, path):
if not sabnzbd.WIN32 and path.startswith('~/'):
path = path.replace('~', sabnzbd.DIR_HOME, 1)
if sabnzbd.WIN32:
if path[0] not in '/\\' and not (len(path) > 1 and path[0].isalpha() and path[1] == ':'):
if path[0].isalpha() and len(path) > 1 and path[1] == ':':
if len(path) == 2 or path[2] not in '\\/':
path = path.replace(':', ':\\', 1)
else:
path = os.path.join(loc, path)
elif path[0] != '/':
path = os.path.join(loc, path)
@@ -743,6 +747,7 @@ def move_to_path(path, new_path, unique=True):
except:
logging.error(Ta('Failed moving %s to %s'), path, new_path)
logging.info("Traceback: ", exc_info = True)
new_path = None
return new_path
@@ -868,8 +873,8 @@ def bad_fetch(nzo, url, msg='', retry=False, content=False):
nzbname = '&nzbname=%s' % urllib.quote(nzbname)
else:
nzbname = ''
text = T('URL Fetching failed; %s') + ', <a href="./retry?session=%s&url=%s%s%s%s%s">' + T('Try again') + '</a>'
parms = (msg, cfg.api_key(), urllib.quote(url), pp, cat, script, nzbname)
text = T('URL Fetching failed; %s') + ', <a href="./retry?session=%s&url=%s&job=%s%s%s%s%s">' + T('Try again') + '</a>'
parms = (msg, cfg.api_key(), urllib.quote(url), nzo.nzo_id, pp, cat, script, nzbname)
nzo.fail_msg = text % parms
else:
nzo.fail_msg = msg
@@ -1166,3 +1171,14 @@ def remove_all(path, pattern='*', keep_folder=False, recursive=False):
except:
logging.info('Cannot remove folder %s', path)
def is_writable(path):
""" Return True is file is writable (also when non-existent) """
if os.path.isfile(path):
return bool(os.stat(path).st_mode & stat.S_IWUSR)
else:
return True
def has_substance(path):
""" Return True when file exists and has some content """
return os.path.exists(path) and os.stat(path).st_size > 0

View File

@@ -28,9 +28,10 @@ from time import time
import binascii
import sabnzbd
from sabnzbd.encoding import TRANS, UNTRANS, unicode2local, name_fixer, reliable_unpack_names, unicoder, latin1
from sabnzbd.encoding import TRANS, UNTRANS, unicode2local, name_fixer, \
reliable_unpack_names, unicoder, latin1, platform_encode
from sabnzbd.utils.rarfile import RarFile, is_rarfile
from sabnzbd.misc import format_time_string, find_on_path, make_script_path
from sabnzbd.misc import format_time_string, find_on_path, make_script_path, int_conv
from sabnzbd.tvsort import SeriesSorter
import sabnzbd.cfg as cfg
@@ -588,8 +589,16 @@ def rar_extract_core(rarfile, numrars, one_folder, nzo, setname, extraction_path
nzo.set_unpack_info('Unpack', unicoder(msg), set=setname)
fail = 1
elif line.startswith('Encrypted file: CRC failed'):
filename = TRANS(line[31:-23].strip())
elif 'ncrypted file' in line and 'CRC failed' in line:
# unrar 4.x syntax
m = re.search('encrypted file (.+)\. Corrupt file', line)
if not m:
# unrar 3.x syntax
m = re.search('Encrypted file: CRC failed in (.+) \(password', line)
if m:
filename = TRANS(m.group(1)).strip()
else:
filename = '???'
nzo.fail_msg = T('Unpacking failed, archive requires a password')
msg = ('[%s][%s] '+Ta('Unpacking failed, archive requires a password')) % (setname, latin1(filename))
nzo.set_unpack_info('Unpack', unicoder(msg), set=setname)
@@ -881,6 +890,7 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False):
command.append(joinable)
stup, need_shell, command, creationflags = build_command(command)
logging.debug('Starting par2: %s', command)
try:
p = subprocess.Popen(command, shell=need_shell, stdin=subprocess.PIPE,
@@ -1330,7 +1340,7 @@ def sfv_check(sfv_path):
x = line.rfind(' ')
filename = line[:x].strip()
checksum = line[x:].strip()
path = os.path.join(root, filename)
path = os.path.join(root, platform_encode(filename))
if os.path.exists(path):
if crc_check(path, checksum):
logging.debug('File %s passed SFV check', path)
@@ -1338,7 +1348,8 @@ def sfv_check(sfv_path):
logging.warning('File %s did not pass SFV check', latin1(path))
status = False
else:
logging.warning('File %s mssing in SFV check', latin1(path))
logging.warning('File %s missing in SFV check', latin1(path))
status = False
fp.close()
return status
@@ -1411,10 +1422,10 @@ def pre_queue(name, pp, cat, script, priority, size, groups):
if n < len(values) and line:
values[n] = TRANS(line)
n += 1
if values[0]:
logging.info('Pre-Q accepts %s', name)
else:
if int_conv(values[0]) < 1:
logging.info('Pre-Q refuses %s', name)
else:
logging.info('Pre-Q accepts %s', name)
return values

View File

@@ -16,7 +16,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
sabnzbd.newzbin - newzbin.com support functions
sabnzbd.newzbin - newzbin2.es support functions
"""
import httplib
@@ -157,9 +157,9 @@ def _grabnzb(msgid):
# Connect to Newzbin
try:
if _HAVE_SSL:
conn = httplib.HTTPSConnection('www.newzbin.com')
conn = httplib.HTTPSConnection(cfg.newzbin_url())
else:
conn = httplib.HTTPConnection('www.newzbin.com')
conn = httplib.HTTPConnection(cfg.newzbin_url())
postdata = { 'username': cfg.newzbin_username(), 'password': cfg.newzbin_password(), 'reportid': msgid }
postdata = urllib.urlencode(postdata)
@@ -260,7 +260,7 @@ def _grabnzb(msgid):
BOOK_LOCK = Lock()
class Bookmarks(object):
""" Get list of bookmarks from www.newzbin.com
""" Get list of bookmarks from www.newzbin2.es
"""
do = None # Link to instance
@@ -272,16 +272,21 @@ class Bookmarks(object):
Bookmarks.do = self
@synchronized(BOOK_LOCK)
def run(self, delete=None):
def run(self, delete=None, force=False):
if not (cfg.newzbin_bookmarks() or force):
return
if not (cfg.newzbin_username() and cfg.newzbin_password()):
return
headers = { 'User-Agent': 'SABnzbd+/%s' % sabnzbd.__version__, }
# Connect to Newzbin
try:
if _HAVE_SSL:
conn = httplib.HTTPSConnection('www.newzbin.com')
conn = httplib.HTTPSConnection(cfg.newzbin_url())
else:
conn = httplib.HTTPConnection('www.newzbin.com')
conn = httplib.HTTPConnection(cfg.newzbin_url())
if delete:
logging.debug('Trying to delete Newzbin bookmark %s', delete)

View File

@@ -105,9 +105,12 @@ class NzbQueue(TryList):
if repair:
self.scan_jobs(not folders)
# Handle any lost future jobs
for nzo_id in globber(os.path.join(cfg.admin_dir.get_path(), FUTURE_Q_FOLDER)):
for path in globber(os.path.join(cfg.admin_dir.get_path(), FUTURE_Q_FOLDER)):
path, nzo_id = os.path.split(path)
if nzo_id not in self.__nzo_table:
self.add(nzo, save=False)
nzo = sabnzbd.load_data(nzo_id, path, remove=True)
if nzo:
self.add(nzo, save=True)
def scan_jobs(self, all=False, action=True):
@@ -685,13 +688,15 @@ class NzbQueue(TryList):
logging.warning(Ta('%s -> Unknown encoding'), filename)
if post_done:
if self.actives(grabs=False) < 2 and cfg.autodisconnect():
# This was the last job, close server connections
sabnzbd.downloader.Downloader.do.disconnect()
self.finish_nzo(nzo)
# Notify assembler to call postprocessor
Assembler.do.process((nzo, None))
def finish_nzo(self, nzo):
if self.actives(grabs=False) < 2 and cfg.autodisconnect():
# This was the last job, close server connections
sabnzbd.downloader.Downloader.do.disconnect()
# Notify assembler to call postprocessor
Assembler.do.process((nzo, None))
@synchronized(NZBQUEUE_LOCK)
def actives(self, grabs=True):
@@ -725,7 +730,7 @@ class NzbQueue(TryList):
def is_empty(self):
empty = True
for nzo in self.__nzo_list:
if not nzo.futuretype:
if not nzo.futuretype and nzo.status != 'Paused':
empty = False
break
return empty

View File

@@ -194,7 +194,9 @@ class NzbFile(TryList):
self.valid = bool(article_db)
if self.valid and self.nzf_id:
sabnzbd.save_data(article_db, self.nzf_id, nzo.workpath)
if not sabnzbd.save_data(article_db, self.nzf_id, nzo.workpath):
logging.info('Saving %s failed', latin1(os.path.join(nzo.workpath, self.nzf_id)))
raise IOError
def finish_import(self):
""" Load the article objects from disk """
@@ -320,6 +322,7 @@ class NzbParser(xml.sax.handler.ContentHandler):
self.nzf_list = []
self.groups = []
self.filter = remove_samples
self.now = time.time()
def startDocument(self):
pass
@@ -356,8 +359,8 @@ class NzbParser(xml.sax.handler.ContentHandler):
try:
self.file_date = int(attrs.get('date'))
except:
# NZB has non-standard timestamp, assume 1
self.file_date = 1
# NZB has non-standard timestamp, assume now
self.file_date = self.now
self.article_db = {}
self.file_bytes = 0
@@ -410,7 +413,11 @@ class NzbParser(xml.sax.handler.ContentHandler):
if not self.article_db:
logging.warning(Ta('File %s is empty, skipping'), self.filename)
return
tm = datetime.datetime.fromtimestamp(self.file_date)
try:
tm = datetime.datetime.fromtimestamp(self.file_date)
except:
tm = datetime.datetime.fromtimestamp(self.now)
self.file_date = self.now
nzf = NzbFile(tm, self.filename, self.article_db, self.file_bytes, self.nzo)
if nzf.valid and nzf.nzf_id:
logging.info('File %s added to queue', self.filename)
@@ -489,7 +496,8 @@ NzbObjectMapper = (
('extra6', 'encrypted'), # Encrypted RAR file encountered
('duplicate', 'duplicate'), # Was detected as a duplicate
('oversized', 'oversized'), # Was detected as oversized
('create_group_folder', 'create_group_folder')
('create_group_folder', 'create_group_folder'),
('aborted', 'aborted') # Download aborted due to admin errors
)
class NzbObject(TryList):
@@ -574,6 +582,7 @@ class NzbObject(TryList):
self.parsed = False
self.duplicate = False
self.oversized = False
self.aborted = False
# Store one line responses for filejoin/par2/unrar/unzip here for history display
self.action_line = ''
@@ -657,6 +666,10 @@ class NzbObject(TryList):
logging.warning(Ta('Invalid NZB file %s, skipping (reason=%s, line=%s)'),
filename, err.getMessage(), err.getLineNumber())
raise ValueError
except IOError:
self.purge_data(keep_basic=reuse)
logging.warning(Ta('Cannot save NZB admin files for "%s"'), latin1(self.work_name))
raise ValueError
except Exception, err:
self.purge_data(keep_basic=reuse)
logging.warning(Ta('Invalid NZB file %s, skipping (reason=%s, line=%s)'), filename, err, 0)
@@ -815,7 +828,7 @@ class NzbObject(TryList):
else:
if not file_done:
nzf.reset_try_list()
self.files.remove(nzf)
if nzf in self.files: self.files.remove(nzf)
self.extrapars[head].append(nzf)
## No par2file in this set yet, set this as
## initialparfile
@@ -1010,7 +1023,9 @@ class NzbObject(TryList):
if not nzf.import_finished:
logging.error(Ta('Error importing %s'), nzf)
nzf_remove_list.append(nzf)
continue
nzf.nzo.aborted = True
sabnzbd.nzbqueue.NzbQueue.do.finish_nzo(nzf.nzo)
return None
else:
continue

View File

@@ -235,10 +235,20 @@ class SABnzbdDelegate(NSObject):
self.newzbin_menu_item.setEnabled_(NO)
self.menu.addItem_(self.newzbin_menu_item)
if (debug == 1) : NSLog("[osx] menu 14 newzbin added")
#Watched folder Item
self.watched_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Scan watched folder'), 'watchedFolderAction:', '')
if self.isLeopard:
self.watched_menu_item.setHidden_(YES)
else:
self.watched_menu_item.setEnabled_(NO)
self.menu.addItem_(self.watched_menu_item)
self.separator2_menu_item = NSMenuItem.separatorItem()
self.menu.addItem_(self.separator2_menu_item)
if (debug == 1) : NSLog("[osx] menu 14 newzbin added")
if (debug == 1) : NSLog("[osx] menu 14 watched folder added")
#Complete Folder Item
self.completefolder_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Complete Folder') + '\t\t\t', 'openFolderAction:', '')
@@ -258,20 +268,29 @@ class SABnzbdDelegate(NSObject):
#menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('About SABnzbd', 'aboutAction:', '')
#self.menu.addItem_(menu_item)
# Set diagnostic menu
self.diagnostic_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Troubleshoot'), '', '')
self.menu_diagnostic = NSMenu.alloc().init()
diag_items = ((T('Restart'), 'restartAction:'),
(T('Restart') + ' - 127.0.0.1:8080', 'restartSafeHost:'),
(T('Restart without login'), 'restartNoLogin:')
)
for item in diag_items:
menu_diag_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(item[0], item[1], '')
menu_diag_item.setRepresentedObject_(item[0])
self.menu_diagnostic.addItem_(menu_diag_item)
self.diagnostic_menu_item.setSubmenu_(self.menu_diagnostic)
self.menu.addItem_(self.diagnostic_menu_item)
if (debug == 1) : NSLog("[osx] menu 16 Diagnostic added")
#Quit Item
menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Quit'), 'terminate:', '')
self.menu.addItem_(menu_item)
if (debug == 1) : NSLog("[osx] menu 16 quit added")
#Restart Item
menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(T('Restart'), 'restartAction:', '')
menu_item.setAlternate_(YES)
menu_item.setKeyEquivalentModifierMask_(NSAlternateKeyMask)
self.menu.addItem_(menu_item)
if (debug == 1) : NSLog("[osx] menu 17 restart added")
#Add menu to Status Item
self.status_item.setMenu_(self.menu)
@@ -299,6 +318,7 @@ class SABnzbdDelegate(NSObject):
self.versionUpdate()
self.newzbinUpdate()
self.diskspaceUpdate()
self.watchedUpdate()
else:
if self.status_removed == 0:
status_bar = NSStatusBar.systemStatusBar()
@@ -328,7 +348,7 @@ class SABnzbdDelegate(NSObject):
job_nb = 1
for pnfo in pnfo_list:
if job_nb >= 10:
if job_nb > 10:
break
filename = pnfo[PNFO_FILENAME_FIELD]
msgid = pnfo[PNFO_MSGID_FIELD]
@@ -512,9 +532,24 @@ class SABnzbdDelegate(NSObject):
logging.info("[osx] versionUpdate Exception %s" % (sys.exc_info()[0]))
def watchedUpdate(self):
try:
if sabnzbd.cfg.dirscan_dir():
if self.isLeopard:
self.watched_menu_item.setHidden_(NO)
else:
self.watched_menu_item.setEnabled_(YES)
else:
if self.isLeopard:
self.watched_menu_item.setHidden_(YES)
else:
self.watched_menu_item.setEnabled_(NO)
except :
logging.info("[osx] watchedUpdate Exception %s" % (sys.exc_info()[0]))
def newzbinUpdate(self):
try:
if sabnzbd.cfg.newzbin_username() and sabnzbd.cfg.newzbin_password() and sabnzbd.cfg.newzbin_bookmarks():
if sabnzbd.cfg.newzbin_username() and sabnzbd.cfg.newzbin_password():
if self.isLeopard:
self.newzbin_menu_item.setHidden_(NO)
else:
@@ -543,6 +578,7 @@ class SABnzbdDelegate(NSObject):
self.resume_menu_item.setHidden_(hide)
self.pause_menu_item.setHidden_(hide)
self.newzbin_menu_item.setHidden_(hide)
self.watched_menu_item.setHidden_(hide)
self.purgequeue_menu_item.setAlternate_(alternate)
self.purgequeue_menu_item.setHidden_(hide)
self.queue_menu_item.setHidden_(hide)
@@ -558,6 +594,7 @@ class SABnzbdDelegate(NSObject):
self.resume_menu_item.setEnabled_(alternate)
self.pause_menu_item.setEnabled_(alternate)
self.newzbin_menu_item.setEnabled_(alternate)
self.watched_menu_item.setEnabled_(alternate)
self.purgequeue_menu_item.setAlternate_(alternate)
self.purgequeue_menu_item.setEnabled_(alternate)
self.queue_menu_item.setEnabled_(alternate)
@@ -683,7 +720,10 @@ class SABnzbdDelegate(NSObject):
scheduler.plan_resume(0)
def getNewzbinBookmarksAction_(self, sender):
Bookmarks.do.run()
Bookmarks.do.run(force=True)
def watchedFolderAction_(self, sender):
sabnzbd.dirscanner.dirscan()
def openFolderAction_(self, sender):
folder2open = sender.representedObject()
@@ -702,6 +742,26 @@ class SABnzbdDelegate(NSObject):
cherrypy.engine.restart()
self.setMenuTitle("\n\n%s\n"% (T('Stopping...')))
def restartSafeHost_(self, sender):
sabnzbd.cfg.cherryhost.set('127.0.0.1')
sabnzbd.cfg.cherryport.set('8080')
sabnzbd.cfg.https_port.set('8090')
sabnzbd.cfg.enable_https.set(False)
sabnzbd.config.save_config()
self.setMenuTitle("\n\n%s\n"% (T('Stopping...')))
sabnzbd.halt()
cherrypy.engine.restart()
self.setMenuTitle("\n\n%s\n"% (T('Stopping...')))
def restartNoLogin_(self, sender):
sabnzbd.cfg.username.set('')
sabnzbd.cfg.password.set('')
sabnzbd.config.save_config()
self.setMenuTitle("\n\n%s\n"% (T('Stopping...')))
sabnzbd.halt()
cherrypy.engine.restart()
self.setMenuTitle("\n\n%s\n"% (T('Stopping...')))
def application_openFiles_(self, nsapp, filenames):
#logging.info('[osx] file open')
#logging.info('[osx] file : %s' % (filenames))

View File

@@ -123,7 +123,7 @@ class PostProcessor(Thread):
self.history_queue.remove(nzo)
except:
nzo_id = getattr(nzo, 'nzo_id', 'unknown id')
logging.error(Ta('Failed to remove nzo from postproc queue (id)'), nzo_id)
logging.error(Ta('Failed to remove nzo from postproc queue (id)') + ' ' + nzo_id)
self.save()
def stop(self):
@@ -232,6 +232,9 @@ def process_job(nzo):
all_ok = False
try:
if nzo.aborted:
crash_msg = T('Download aborted due to admin errros')
raise IOError
# Get the folder containing the download result
workdir = nzo.downpath
@@ -330,7 +333,10 @@ def process_job(nzo):
path = os.path.join(root, file_)
new_path = path.replace(workdir, tmp_workdir_complete)
new_path = get_unique_filename(new_path)
move_to_path(path, new_path, unique=False)
if not move_to_path(path, new_path, unique=False):
nzo.set_unpack_info('Unpack', T('Failed moving %s to %s') % (unicoder(path), unicoder(new_path)))
all_ok = False
break
## Set permissions right
if not sabnzbd.WIN32:
@@ -378,7 +384,10 @@ def process_job(nzo):
if all_ok:
if newfiles and file_sorter.is_sortfile():
file_sorter.rename(newfiles, workdir_complete)
workdir_complete = file_sorter.move(workdir_complete)
workdir_complete, ok = file_sorter.move(workdir_complete)
if not ok:
nzo.set_unpack_info('Unpack', T('Failed to move files'))
all_ok = False
## Run the user script
script_path = make_script_path(script)
@@ -423,7 +432,8 @@ def process_job(nzo):
T('View script output')), unique=True)
## Cleanup again, including NZB files
cleanup_list(workdir_complete, False)
if all_ok:
cleanup_list(workdir_complete, False)
## Remove newzbin bookmark, if any
if msgid and all_ok:
@@ -526,16 +536,22 @@ def parring(nzo, workdir):
logging.info('Par2 check finished on %s', filename)
else:
if (par_error and not re_add) or not repair_sets:
# See if alternative SFV check is possible
sfv = None
if cfg.sfv_check():
for sfv in globber(workdir, '*.sfv'):
par_error = par_error or not sfv_check(sfv)
if par_error:
nzo.set_unpack_info('Repair', T('Some files failed to verify against "%s"') % unicoder(os.path.basename(sfv)))
if not sfv:
sfvs = globber(workdir, '*.sfv')
else:
sfvs = None
if sfvs:
par_error = False
nzo.set_unpack_info('Repair', T('Trying SFV verification'))
for sfv in sfvs:
if not sfv_check(sfv):
nzo.set_unpack_info('Repair', T('Some files failed to verify against "%s"') % unicoder(os.path.basename(sfv)))
par_error = True
if not par_error:
nzo.set_unpack_info('Repair', T('Verified successfully using SFV files'))
elif not repair_sets:
logging.info("No par2 sets for %s", filename)
nzo.set_unpack_info('Repair', T('[%s] No par2 sets') % unicoder(filename))

View File

@@ -117,8 +117,9 @@ def convert_filter(text):
If string starts with re: it's a real regex
else quote all regex specials, replace '*' by '.*'
"""
if text[:3].lower() == 're:':
txt = text[3:]
text = text.strip().lower()
if text.startswith('re:'):
txt = text[3:].strip()
else:
txt = wildcard_to_re(text)
try:
@@ -194,6 +195,7 @@ class RSSQueue(object):
if item.get('status', ' ')[0] not in ('D', 'G', 'B', 'X'):
item['status'] = 'X'
if not isinstance(item.get('url'), unicode): item['url'] = ''
item['url'] = item['url'].replace('www.newzbin.com', cfg.newzbin_url())
if not check_str(item.get('cat')): item['cat'] = ''
if not check_str(item.get('orgcat')): item['orgcat'] = ''
if not check_str(item.get('pp')): item['pp'] = '3'
@@ -353,9 +355,9 @@ class RSSQueue(object):
except (AttributeError, IndexError):
link = None
category = ''
logging.error('Incompatible feed %s', uri)
logging.info(Ta('Incompatible feed') + ' ' + uri)
logging.info("Traceback: ", exc_info = True)
return 'Incompatible feed'
return T('Incompatible feed')
category = latin1(category)
# Make sure only latin-1 encodable characters occur
atitle = latin1(entry.title)
@@ -547,7 +549,7 @@ class RSSQueue(object):
self.jobs[feed][item]['status'] = 'D-'
RE_NEWZBIN = re.compile(r'(newz)(bin|xxx).com/browse/post/(\d+)', re.I)
RE_NEWZBIN = re.compile(r'(newz)(bin|xxx|bin2)\.[\w]+/browse/post/(\d+)', re.I)
def _HandleLink(jobs, link, title, flag, orgcat, cat, pp, script, download, star, order,
priority=NORMAL_PRIORITY, rule=0):
@@ -608,18 +610,21 @@ def _get_link(uri, entry):
link = None
category = ''
uri = uri.lower()
if 'newzbin.com' in uri or 'newzxxx.com'in uri:
if 'newzbin.' in uri or 'newzxxx.'in uri or 'newzbin2.' in uri:
link = entry.link
if not (link and '/post/' in link.lower()):
# Use alternative link
link = entry.links[0].href
elif 'nzbindex.nl' in uri or 'nzbindex.com' in uri or 'animeusenet.org' in uri or 'nzbclub.com' in uri:
link = entry.enclosures[0]['href']
elif not link:
else:
# Try standard link first
link = entry.link
if not link:
link = entry.links[0].href
if encl_sites(uri, link):
try:
link = entry.enclosures[0]['href']
except:
pass
if link and 'http' in link.lower():
try:
@@ -645,3 +650,13 @@ def special_rss_site(url):
""" Return True if url describes an RSS site with odd titles
"""
return cfg.rss_filenames() or 'nzbindex.nl/' in url or 'nzbindex.com/' in url or 'nzbclub.com/' in url
_ENCL_SITES = ('nzbindex.nl', 'nzbindex.com', 'animeusenet.org', 'nzbclub.com')
def encl_sites(url, link):
""" Return True if url or link match sites that use enclosures
"""
for site in _ENCL_SITES:
if site in url or (link and site in link):
return True
return False

View File

@@ -533,7 +533,7 @@ SKIN_TEXT = {
'testNotify' : TT('Test Notification'),
# Config->Newzbin
'explain-newzbin' : TT('If you have an account at <strong>www.newzbin.com</strong>, you can enter your account info here.<br />This will unlock extra functionality.'),
'explain-newzbin' : TT('If you have an account at <strong>www.newzbin2.es</strong>, you can enter your account info here.<br />This will unlock extra functionality.'),
'accountInfo' : TT('Account info'),
'opt-username_newzbin' : TT('Newzbin Username'),
'explain-username_newzbin' : TT('Set your account username here.'),

View File

@@ -72,14 +72,15 @@ def move_to_parent_folder(workdir):
If afterwards the directory is not empty, rename it to _JUNK_folder, else remove it.
"""
skipped = False # Keep track of any skipped files
path1 = os.path.abspath(os.path.join(workdir, '..')) #move things to the folder below
path1 = os.path.abspath(os.path.normpath(os.path.join(workdir, '..'))) #move things to the folder below
for root, dirs, files in os.walk(workdir):
for _file in files:
path = os.path.join(root, _file)
new_path = path.replace(workdir, path1)
new_path = get_unique_filename(new_path)
move_to_path(path, new_path, False)
if not move_to_path(path, new_path, False):
return path1, False
cleanup_empty_directories(workdir)
try:
@@ -87,7 +88,7 @@ def move_to_parent_folder(workdir):
except:
pass
return path1
return path1, True
class Sorter(object):
@@ -96,6 +97,7 @@ class Sorter(object):
self.type = None
self.sort_file = False
self.cat = cat
self.ext = ''
def detect(self, dirname, complete_dir):
self.sorter = SeriesSorter(dirname, complete_dir, self.cat)
@@ -127,6 +129,7 @@ class Sorter(object):
self.sorter.rename(newfiles, workdir_complete)
def move(self, workdir_complete):
ok = True
if self.type == 'movie':
move_to_parent = True
# check if we should leave the files inside an extra folder
@@ -134,9 +137,12 @@ class Sorter(object):
#if there is a folder in the download, leave it in an extra folder
move_to_parent = not check_for_folder(workdir_complete)
if move_to_parent:
workdir_complete = move_to_parent_folder(workdir_complete)
workdir_complete, ok = move_to_parent_folder(workdir_complete)
else:
workdir_complete = move_to_parent_folder(workdir_complete)
workdir_complete, ok = move_to_parent_folder(workdir_complete)
if not ok:
return workdir_complete, False
path, part = os.path.split(workdir_complete)
if '%fn' in part and self.sorter.fname:
old = workdir_complete
@@ -147,7 +153,8 @@ class Sorter(object):
except:
logging.error(Ta('Cannot create directory %s'), workdir_complete)
workdir_complete = old
return workdir_complete
ok = False
return workdir_complete, ok
def is_sortfile(self):
return self.sort_file
@@ -352,7 +359,7 @@ class SeriesSorter(object):
else:
head = path
return head
return os.path.normpath(head)
def should_rename(self):
return self.rename_or_not
@@ -592,7 +599,7 @@ class GenericSorter(object):
else:
head = path
return head
return os.path.normpath(head)
def should_rename(self):
return self.rename_or_not
@@ -808,7 +815,7 @@ class DateSorter(object):
else:
head = path
return head
return os.path.normpath(head)
def should_rename(self):
return self.rename_or_not
@@ -1013,7 +1020,7 @@ def stripFolders(folders):
x = x.strip()
return x
return '/'.join([strip_all(x) for x in f])
return os.path.normpath('/'.join([strip_all(x) for x in f]))
def rename_similar(path, file, name):

View File

@@ -114,7 +114,8 @@ class URLGrabber(Thread):
opener.prompt_user_passwd = None
opener.addheaders = []
opener.addheader('User-Agent', 'SABnzbd+/%s' % sabnzbd.version.__version__)
opener.addheader('Accept-encoding','gzip')
if '.zip' not in url:
opener.addheader('Accept-encoding','gzip')
filename = None
category = None
length = 0

View File

@@ -15,51 +15,165 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#"""
#TO FIX : Translations are not working with this implementation
# Growl Registration may only be done once per run ?
# Registration is made too early, the language module has not read the text file yet
#NOTIFICATION = {'startup':'grwl-notif-startup','download':'grwl-notif-dl','pp':'grwl-notif-pp','other':'grwl-notif-other'}
NOTIFICATION = {'startup':'1. On Startup/Shutdown','download':'2. On adding NZB','pp':'3. On post-processing','complete':'4. On download terminated','other':'5. Other Messages'}
"""
sabnzbd.growler - Send notifications to Growl
"""
#------------------------------------------------------------------------------
# For a future release, make texts translatable.
if 0:
#------------------------------------------------------------------------------
# Define translatable message table
TT = lambda x:x
_NOTIFICATION = {
'startup' : TT('Startup/Shutdown'), #: Message class for Growl server
'download' : TT('Added NZB'), #: Message class for Growl server
'pp' : TT('Post-processing started'), #: Message class for Growl server
'complete' : TT('Job finished'), #: Message class for Growl server
'other' : TT('Other Messages') #: Message class for Growl server
}
import os.path
import logging
import socket
import sabnzbd
from sabnzbd.encoding import unicoder, latin1
import gntp
import gntp.notifier
try:
import Growl
import os.path
import logging
if os.path.isfile('sabnzbdplus.icns'):
nIcon = Growl.Image.imageFromPath('sabnzbdplus.icns')
elif os.path.isfile('osx/resources/sabnzbdplus.icns'):
nIcon = Growl.Image.imageFromPath('osx/resources/sabnzbdplus.icns')
import platform
# If running on OSX-Lion and classic Growl (older than 1.3) is absent, assume GNTP-only
if [int(n) for n in platform.mac_ver()[0].split('.')] >= [10, 7, 0]:
_HAVE_OSX_GROWL = os.path.isfile('/Library/PreferencePanes/Growl.prefPane/Contents/MacOS/Growl')
else:
nIcon = Growl.Image.imageWithIconForApplication('Terminal')
def sendGrowlMsg(nTitle , nMsg, nType=NOTIFICATION['other']):
gnotifier = SABGrowlNotifier(applicationIcon=nIcon)
gnotifier.register()
#TO FIX
#gnotifier.notify(T(nType), nTitle, nMsg)
gnotifier.notify(nType, nTitle, nMsg)
class SABGrowlNotifier(Growl.GrowlNotifier):
applicationName = "SABnzbd"
#TO FIX
#notifications = [T(notification) for notification in NOTIFICATION.values()]
notifications = NOTIFICATION.values()
_HAVE_OSX_GROWL = True
except ImportError:
def sendGrowlMsg(nTitle , nMsg, nType):
pass
_HAVE_OSX_GROWL = False
#------------------------------------------------------------------------------
# Define translatable message table
NOTIFICATION = {'startup':'1. On Startup/Shutdown','download':'2. On adding NZB','pp':'3. On post-processing','complete':'4. On download terminated','other':'5. Other Messages'}
#------------------------------------------------------------------------------
# Setup platform dependent Growl support
#
_GROWL_ICON = None # Platform-dependant icon path
_GROWL = None # Instance of the Notifier after registration
_GROWL_REG = False # Succesful registration
#------------------------------------------------------------------------------
def get_icon():
icon = os.path.join(sabnzbd.DIR_PROG, 'sabnzbd.ico')
if not os.path.isfile(icon):
icon = None
return icon
#------------------------------------------------------------------------------
def register_growl():
""" Register this app with Growl
"""
error = None
# Clean up persistent data in GNTP to make re-registration work
gntp.GNTPRegister.notifications = []
gntp.GNTPRegister.headers = {}
growler = gntp.notifier.GrowlNotifier(
applicationName = 'SABnzbd',
applicationIcon = get_icon(),
notifications = sorted(NOTIFICATION.values()),
hostname = None,
port = 23053,
password = None
)
try:
ret = growler.register()
if ret is None or isinstance(ret, bool):
logging.info('Registered with Growl')
ret = growler
else:
error = 'Cannot register with Growl %s' % ret
logging.debug(error)
del growler
ret = None
except socket.error, err:
error = 'Cannot register with Growl %s' % err
logging.debug(error)
del growler
ret = None
except:
error = 'Unknown Growl registration error'
logging.debug(error)
del growler
ret = None
return ret, error
#------------------------------------------------------------------------------
def sendGrowlMsg(title , msg, gtype):
""" Send Growl message
"""
global _GROWL, _GROWL_REG
if not sabnzbd.cfg.growl_enable() or not sabnzbd.DARWIN:
return
if _HAVE_OSX_GROWL:
res = send_local_growl(title, msg, gtype)
return res
for n in (0, 1):
if not _GROWL_REG: _GROWL = None
if not _GROWL:
_GROWL, error = register_growl()
if _GROWL:
assert isinstance(_GROWL, gntp.notifier.GrowlNotifier)
_GROWL_REG = True
#logging.debug('Send to Growl: %s %s %s', gtype, latin1(title), latin1(msg))
try:
ret = _GROWL.notify(
noteType = gtype,
title = title,
description = unicoder(msg),
#icon = options.icon,
#sticky = options.sticky,
#priority = options.priority
)
if ret is None or isinstance(ret, bool):
return None
elif ret[0] == '401':
_GROWL = False
else:
logging.debug('Growl error %s', ret)
return 'Growl error %s', ret
except socket.error, err:
error = 'Growl error %s' % err
logging.debug(error)
return error
except:
error = 'Growl error (unknown)'
logging.debug(error)
return error
else:
return error
return None
#------------------------------------------------------------------------------
# Local OSX Growl support
#
if _HAVE_OSX_GROWL:
_local_growl = None
if os.path.isfile('sabnzbdplus.icns'):
_OSX_ICON = Growl.Image.imageFromPath('sabnzbdplus.icns')
elif os.path.isfile('osx/resources/sabnzbdplus.icns'):
_OSX_ICON = Growl.Image.imageFromPath('osx/resources/sabnzbdplus.icns')
else:
_OSX_ICON = Growl.Image.imageWithIconForApplication('Terminal')
def send_local_growl(title , msg, gtype):
""" Send to local Growl server, OSX-only """
global _local_growl
if not _local_growl:
notes = sorted(NOTIFICATION.values())
_local_growl = Growl.GrowlNotifier(
applicationName = 'SABnzbd',
applicationIcon = _OSX_ICON,
notifications = notes,
defaultNotifications = notes
)
_local_growl.register()
_local_growl.notify(gtype, title, msg)
return None

View File

@@ -124,9 +124,11 @@ class RarInfo:
class RarFile:
'''Rar archive handling.'''
def __init__(self, rarfile, mode="r", charset='cp850', info_callback=None):
def __init__(self, rarfile, mode="r", charset='cp850', info_callback=None, all_names=False):
# 'all_names' = show names of 'split' files too
self.rarfile = rarfile
self.charset = charset
self.all_names = all_names
self.info_list = []
self.is_solid = 0
@@ -215,7 +217,7 @@ class RarFile:
# RAR_BLOCK_NEWSUB has files too: CMT, RR
if item.type == RAR_BLOCK_FILE:
# use only first part
if (item.flags & RAR_FILE_SPLIT_BEFORE) == 0:
if self.all_names or (item.flags & RAR_FILE_SPLIT_BEFORE) == 0:
# Always use Unix separators
item.filename = item.filename.replace('\\', '/')
item.unicode_filename = item.unicode_filename.replace(u'\\', u'/')

View File

@@ -96,6 +96,10 @@ def test_nntp_server(host, port, server=None, username=None, password=None, ssl=
except TypeError, e:
return False, xml_name(T('Invalid server address.'))
except IndexError:
# No data was received in recv_chunk() call
return False, xml_name(T('Server quit during login sequence.'))
except:
return False, xml_name(str(sys.exc_info()[1]))

View File

@@ -169,6 +169,7 @@ class Wizard(object):
info['newzbin_user'] = cfg.newzbin_username()
info['newzbin_pass'] = cfg.newzbin_password.get_stars()
info['newzbin_bookmarks'] = cfg.newzbin_bookmarks()
info['newzbin_url'] = cfg.newzbin_url()
info['matrix_user'] = cfg.matrix_username()
info['matrix_apikey'] = cfg.matrix_apikey()
info['T'] = Ttemplate