Compare commits

...

108 Commits

Author SHA1 Message Date
shypike
37acad6ec7 Update text files for 0.6.9 RC2 2011-09-06 20:18:49 +02:00
shypike
74d90b8361 Correct formatting errors in translations. 2011-09-06 19:12:59 +02:00
shypike
952682d557 Update translations 2011-09-06 19:02:37 +02:00
shypike
c1f3e44fb8 Add hidden option "allow_64bit_tools" to allow or prevent use of 64bit par2 and unrar. 2011-09-04 16:37:38 +02:00
shypike
fa2a6c673c Improve handling of non-creatable "complete" and category folders.
Remove the tendency of the status-api to create final folders prematurely.
Make error message about folder creation translatable.
2011-09-04 13:00:32 +02:00
shypike
b46ae4782d GenericSorter should always uppercase the initial letter of "the", "a", "of" etc. at the start of a title.
"the way of the few" => "The Way of the Few".
2011-09-03 13:43:24 +02:00
shypike
6ebbc81792 Change the OSX DMG window size so that the optional "path bar" doesn't obsure part of the background image. 2011-09-03 13:12:35 +02:00
shypike
1d7170f193 Fix and I18N the "Downloaded in X days Y hours Z seconds" text in the history report. 2011-09-01 21:42:46 +02:00
shypike
3dea948ecc Update text files for 0.6.9 RC1. 2011-09-01 18:58:25 +02:00
shypike
1e960ae2e9 Check email parameters also when only email_rss option is enabled. 2011-09-01 18:55:44 +02:00
shypike
e6b21f1ca5 Attempt to remove memory leak due to pickling the admin files. Use Pickler object (and clear_memo) instead of pickle function. 2011-08-30 23:32:17 +02:00
shypike
ebd3cbd932 When removing a job folder in the "incomplete" folder, also remove files in subfolders and the subfolders. This is necessary because some operating systems produce stray files/folders. 2011-08-30 22:28:17 +02:00
shypike
b8fb5cbfbf Setting of WIN64 flag was done only after selecting unrar/par2 variants.
The result was that the x64 variants were never used.
Closes #3
2011-08-29 21:54:49 +02:00
shypike
01494bd010 When using the Download button in RSS feeds for newzbin, the nzb name was incorrect. Closes #2 2011-08-29 20:04:21 +02:00
Jon Saine
6dd4c0551e Reverted hoverIntent version back to r5. It was breaking the menu.
Forgot to upgrade plush.js for jquery 1.6.x compatibility.
2011-08-22 09:09:04 -05:00
Jon Saine
8225dae182 Converted some jquery code for 1.6.x compliance.
With jquery 1.6.x the attributes module was modified slightly to eliminate ambiguity between attributes and properties.
Long story short, $('blah').attr('checked', true) is now $('blah').prop('checked', true).
2011-08-22 09:09:03 -05:00
Jon Saine
9999065f0a jQuery 1.5.1 -> 1.6.2
-- http://blog.jquery.com/2011/06/30/jquery-162-released/
 -- 1.5 to 1.6 notes: http://blog.jquery.com/2011/05/12/jquery-1-6-1-released/
jQuery UI 1.8.10 -> 1.8.15
 -- http://jqueryui.com/docs/Changelog/1.8.15
 -- Several additional modules was included due to dependency for the upcoming folder browser code.
ColorBox 1.3.15 -> 1.3.17
 -- http://colorpowered.com/colorbox/core/README
jQuery.hoverIntent r5 -> r6
 -- http://cherne.net/brian/resources/jquery.hoverIntent.html#defects
2011-08-22 09:09:03 -05:00
Jeff George
90d11ada6b Kill .bzr stuff, add .gitignore & a pretty README.md for GitHub. 2011-08-22 09:09:03 -05:00
shypike
67a1ee3cde Update translations. 2011-08-20 17:00:40 +02:00
shypike
0f8df0f072 Update POT files. 2011-08-20 16:11:13 +02:00
shypike
9c9936e7ae Update UnRAR to release 4.01 2011-08-20 15:26:34 +02:00
shypike
92926a4825 Use different background images for Lion and (Snow)Leopard DMG files. 2011-08-20 12:10:13 +02:00
shypike
2cc53e8dc3 Make package.py work in a git environment.
Remove bazaar specials and add .gitignore
2011-08-16 10:43:55 +02:00
ShyPike
18cb5710f9 Servers with square brackets in the name were not removed from the INI file.
The reason was that the required substitution of "[]" with "{}" wasn't done in all situations.
2011-08-16 10:32:33 +02:00
ShyPike
11b8f23528 Fix crash of emailer.py when email notification is on, without having proper email settings. 2011-08-16 10:30:22 +02:00
ShyPike
cf72abedfd Update text files or 0.6.8 Final. 2011-08-11 20:42:14 +02:00
ShyPike
31f92ebdd5 Update text files for 0.6.8 RC1 2011-08-08 16:22:41 +02:00
ShyPike
39a6635229 Prevent occasional exit crashes of the Kronos module. 2011-08-08 14:11:00 +02:00
ShyPike
a87a70d9c6 Solve several RSS issues:
- Remove links from feeds that have been deleted from rss_data.sab
- Expired links should be re-examined when they re-appear in the feed
- Sanity check of rss_data.sab at startup could expire links without reason
- Reduce storage of expired links from 7 days to 3 days.
- Duplicates detected were not given the pseudo-priority "Duplicate" (if that option was set by the user)
2011-08-07 16:11:05 +02:00
ShyPike
2d79e2ac92 Update to 0.6.7 2011-08-04 19:30:26 +02:00
ShyPike
7982ef2f11 Update text files for 0.6.7 RC2. 2011-08-03 20:55:33 +02:00
ShyPike
9280daad41 - Classic/smpl: add link "Purge failed NZBs & delete files" 2011-08-03 20:54:59 +02:00
ShyPike
e22709b5ff Actually delete files when user selects "Purge History" and picks "Purge Failed NZBs & Delete files".
Add "Purge failed & delete files" to the Classic and smpl skins.
2011-08-03 20:21:39 +02:00
ShyPike
ed37330fee Work-around for the Plush top menu issue in Safari 5.1. 2011-08-01 23:10:12 +02:00
ShyPike
f1fb3f904b Update French. 2011-08-01 21:18:59 +02:00
ShyPike
a3b6bb9ad9 Update text files for 0.6.7 2011-08-01 19:56:29 +02:00
ShyPike
54e6431d11 Update translations. 2011-08-01 19:55:54 +02:00
ShyPike
3e6f46483c Launch browser for a second instance when no -b parameter is given.
This means that browser launch is always active when using the standard shortcut.
Only an explicit -b0 will suppress the launch.
2011-07-31 10:53:41 +02:00
ShyPike
f7aadb1b61 Allow jobs still waiting for post-processing to be deleted too. 2011-07-30 15:52:48 +02:00
ShyPike
c7d5ea6ecd Delay starting most tasks until the webserver is ready.
This prevents slow starting of the web server due to heavy downloading.
2011-07-30 13:45:31 +02:00
ShyPike
1060f15463 Prevent persistent end-of-queue action to be triggered at program startup. 2011-07-30 13:44:23 +02:00
ShyPike
559d3064a9 Support both ActiveState (for OSX older than 10.5 and 10.6) and Apple Python (for 10.6 and 10.7). 2011-07-29 00:00:16 +02:00
ShyPike
084e638d30 Update text files for 0.6.6 Final. 2011-07-26 20:55:11 +02:00
ShyPike
428ab1ad96 Prevent UI of running SABnzbd instance coming up when second instance is started with "--browser 0". 2011-07-26 20:53:48 +02:00
ShyPike
b15673d0cd Prevent crash on exit when there are disk problems. 2011-07-26 19:59:49 +02:00
ShyPike
abf15149e9 Fix crash in assembler when fatal disk error (like "full") occurs. 2011-07-26 18:48:01 +02:00
ShyPike
1f9e328c2d Fix bad formatting in README.rtf 2011-07-24 13:37:13 +02:00
ShyPike
2c2c1c93a1 Update text files for 0.6.6 RC1 2011-07-24 12:43:19 +02:00
ShyPike
196c06a17e Don't re-queue NZB-only downloads when the PP is set to "Download only". 2011-07-24 11:38:26 +02:00
ShyPike
be78580ece When retrying a download, ignore the "do not download samples" setting.
That setting can misfire without much clues for the user and this will silently correct it.
2011-07-24 11:17:49 +02:00
ShyPike
748d525ccc File an error message if RSS email template not found. 2011-07-24 00:41:28 +02:00
ShyPike
2269407b1c Improved fix for nzbclub RSS link issues. 2011-07-23 10:36:09 +02:00
ShyPike
af7beab5e9 In RSS: don't remove spaces from NZB URLs, but replace with '%20'.
Needed for proper nzbclub.com support.
2011-07-22 21:51:36 +02:00
ShyPike
fb9abcc583 Start generating the OSX tar.gz distro file again. 2011-07-18 22:52:22 +02:00
ShyPike
29e829de73 Update text files for 0.6.6 Beta 2. 2011-07-18 22:17:40 +02:00
ShyPike
5225925a78 Limit the amount of URL fetch attempts when the NZB is incomplete. 2011-07-18 22:15:37 +02:00
ShyPike
15bd0f8a78 For RSS feeds, show 401/402/403 authentication errors clearly. 2011-07-18 21:39:24 +02:00
ShyPike
1557f3f8e8 OSX did not handle nzb.gz files properly when using "Open With". 2011-07-18 20:36:13 +02:00
ShyPike
b0a833f3a9 Log original command line before any tampering. 2011-07-18 19:56:27 +02:00
ShyPike
8b66deef0e Log command line parameters. 2011-07-18 19:25:32 +02:00
ShyPike
61608545c5 Improve diskfree/disktotal for Posix.
Some systems have such large disks that they return a negative number for free/total blocks.
Detect this and trim to the highest possible size that could be represented (usually 8T).
2011-07-17 22:46:13 +02:00
ShyPike
4f163ad979 Delay removing an NZF file until it's payload file is complete and written to disk.
This will make recovery from crashes more likely.
2011-07-17 21:38:16 +02:00
ShyPike
a01cd34b58 Fix handle leak.
Caused by bug in CherryPy's memory-based session support.
Replace by file-based.
As we don't really need session support, disable it and make it available through the --sessions option.
2011-07-16 00:03:14 +02:00
ShyPike
e6a5b0de57 Remove obsolete function from api.py 2011-07-15 20:34:16 +02:00
ShyPike
b3b1209293 Fix duplicate email problem.
For each recipient a seperate email was sent, but the "to" was always the full list instead of just the current recipient.
2011-07-11 20:01:12 +02:00
ShyPike
4cc21efe90 OSX binary: stop needless console logging. 2011-07-10 13:05:12 +02:00
ShyPike
6acd599d53 Fix package.py. 2011-07-10 12:23:36 +02:00
ShyPike
b73f74470b Fix error message about missing Cheetah. 2011-07-10 12:16:35 +02:00
ShyPike
6b3efe9398 OSX binary: remove odd -psn_0_12345 parameter that would be mistaken for "-p -s -n". 2011-07-09 09:55:39 +02:00
ShyPike
e5c9058201 Update text files for 0.6.6 Beta 1. 2011-07-08 22:04:41 +02:00
ShyPike
897d982e2f Handle special login failure situation (we sent empty username, server doesn't accept). 2011-07-07 22:34:24 +02:00
ShyPike
333b83f3c5 Fix error in German translation. 2011-07-06 19:52:45 +02:00
ShyPike
94938847fb Due to 64bit ApplePython, disable argv-emulation feature in py2app. 2011-07-06 19:35:47 +02:00
ShyPike
64f17675e2 Compensate for some Apple-Python bugs. 2011-07-06 19:23:15 +02:00
ShyPike
a97974d66c Replace colon in folder names by a dash. 2011-07-04 21:13:35 +02:00
ShyPike
349395f67a For Windows only show script files with executable extensions. 2011-07-03 12:41:05 +02:00
ShyPike
344c1ff42d Update POT file. 2011-06-30 19:55:16 +02:00
ShyPike
08435bc138 Show proper error message when only invalid par2 files are found for a set. 2011-06-30 19:54:38 +02:00
ShyPike
ce00490b40 Handle error 502 during nntp login properly. 2011-06-29 20:44:29 +02:00
ShyPike
cc702dde6d Improve handling when user has set username/password for a server, while the server doesn't need authentication.
For incorrect authentication, some servers return code '502 ... Access denied...' instead of the official '481' code.
Handle that as a bad login too.
2011-06-26 15:56:08 +02:00
ShyPike
913121bcc4 Update translations. 2011-06-26 12:43:33 +02:00
ShyPike
6448f4ff5e Add texts for pre-check. 2011-06-25 21:55:21 +02:00
ShyPike
1fbb56fc6f Update quotum texts. 2011-06-25 09:49:36 +02:00
ShyPike
6442391589 Output po/nsis/SABnsis.pot in Unix format too. 2011-06-25 09:49:06 +02:00
ShyPike
80ca43fe7d Extension-based cleanup_list should delete files in all sub-folders too. 2011-06-24 20:52:55 +02:00
ShyPike
3514973f2a Avoid logging an exception when postproc1.sab is missing. 2011-06-24 00:34:41 +02:00
ShyPike
def241c5c4 Early addition of quotum management texts to enable translation. 2011-06-23 19:49:50 +02:00
ShyPike
04e1605b27 Smpl: remove "active" job name below the speed graph. It's inaccurate and misleading. 2011-06-22 21:26:29 +02:00
ShyPike
a931e80f2e Fix error in German output of Launchpad. 2011-06-21 21:40:30 +02:00
ShyPike
f891a0ceac Update translations. 2011-06-21 21:39:02 +02:00
ShyPike
41697d022f Set top_only off by default. 2011-06-21 21:21:00 +02:00
ShyPike
f0b1b9d284 Update POT files. 2011-06-21 21:15:43 +02:00
ShyPike
b1455398c8 Use "repair priority" in the sorting functions too. Make the auto_sort option effective immediately instead of only at a (re-)start. 2011-06-21 21:09:30 +02:00
ShyPike
396e779517 Fetching extra par2 files no longer ignores paused state (it will use priority value 3).
Top-priority will still ignore paused state.
2011-06-21 20:27:29 +02:00
ShyPike
e9bc192bc7 Do end-of-queue action also when only paused download queue items remain after the post-processing queue becomes empty. 2011-06-20 21:23:50 +02:00
ShyPike
287490d549 Split misc.py into misc.py, panic.py and powersup.py. 2011-06-20 20:45:13 +02:00
ShyPike
dcd55b552a Add some more translatable texts in anticipation of Growl support. 2011-06-19 20:24:48 +02:00
ShyPike
4ac2b0d27c Update Growl texts again. 2011-06-15 20:07:21 +02:00
ShyPike
ea4d1e9474 Update Growl texts. 2011-06-15 19:37:07 +02:00
ShyPike
61c29e232d Add translation hints to Growl texts. 2011-06-14 23:47:12 +02:00
ShyPike
7b6ef157e9 Add translation hints to Growl texts. 2011-06-14 23:43:52 +02:00
ShyPike
14d6a033ae Add translatable texts for future merge of extended Growl support. 2011-06-14 23:20:42 +02:00
ShyPike
1db567b5ae Update text files for 0.6.5 2011-06-13 12:05:07 +02:00
ShyPike
ad6c9a56d8 Update translations. 2011-06-13 11:58:26 +02:00
ShyPike
15f6732a5b Generic sort: failed to recognize year surounded with underscores. 2011-06-11 14:13:26 +02:00
ShyPike
e517218240 Quick fix for failing end-of-queue script (side-effect of removing Q-> delay). 2011-06-11 13:21:20 +02:00
ShyPike
89fc5fc124 Update translations. 2011-06-09 21:45:15 +02:00
ShyPike
4025087f89 msgfmt.py : add detection of %s mismatches between original and translated texts.
Print warning and skip text.
2011-06-08 19:55:29 +02:00
79 changed files with 11466 additions and 10659 deletions

15
.bzreol
View File

@@ -1,15 +0,0 @@
[LF]
.bzreol
.bzrignore
*.py
*.tmpl
*.js
*.css
*.txt
*.po
*.pot
*.sh
[CRLF]
*.bat
*.cmd
*.nsi

View File

@@ -1,10 +0,0 @@
*.pyc
*.pyo
build
dist
locale
srcdist
cherrypy
*.wpr
*.keep
*.bak

13
.bzrtab
View File

@@ -1,13 +0,0 @@
[NOTAB]
*.py
*.txt
*.po
*.pot
*.sh
*.bat
*.cmd
*.nsi
*.tmpl
*.js
*.css
[TAB]

28
.gitignore vendored Normal file
View File

@@ -0,0 +1,28 @@
#Compiled python
*.py[co]
# Working folders for Win build
build/
dist/
locale/
srcdist/
# Generated email templates
email/
# Romanian ro.po is generated from ro.px, due to mapping to latin-1
po/*/ro.po
# Build results
SABnzbd*.zip
SABnzbd*.exe
SABnzbd*.gz
SABnzbd*.dmg
# WingIDE project file
*.wpr
# General junk
*.keep
*.bak
*.log

63
ABOUT.txt Normal file
View File

@@ -0,0 +1,63 @@
*******************************************
*** This is SABnzbd 0.6.9 ***
*******************************************
SABnzbd is an open-source cross-platform binary newsreader.
It simplifies the process of downloading from Usenet dramatically,
thanks to its friendly web-based user interface and advanced
built-in post-processing options that automatically verify, repair,
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.
There is an extensive Wiki on the use of SABnzbd.
http://wiki.sabnzbd.org/
IMPORTANT INFORMATION about release 0.6.0:
http://wiki.sabnzbd.org/introducing-0-6-0
Please also read the file "ISSUES.txt"
*******************************************
*** Upgrading from 0.6.x ***
*******************************************
Stop SABnzbd.
Install new version
Start SABnzbd.
*******************************************
*** Upgrading from 0.5.x ***
*******************************************
Stop SABnzbd.
Uninstall current version, keeping the data.
Install new version
Start SABnzbd.
The organization of the download queue is different from 0.5.x.
0.6.x will finish downloading an existing queue, but you
cannot go back to an older version without losing your queue.
Also, your sabnzbd.ini file will be upgraded, making it
incompatible with release 0.5.x
*******************************************
*** Upgrading from 0.4.x ***
*******************************************
>>>>> PLEASE DOWNLOAD YOUR CURRENT QUEUE BEFORE UPGRADING <<<<<<
When upgrading from a 0.4.x release such as 0.4.12 your old settings will be kept.
You will however be given a fresh queue and history. If you have items in your queue
from the older version of SABnzbd, you can either re-import the nzb files if you kept
an nzb backup folder, or temporarily go back to 0.4.x until your queue is complete.
The history is now stored in a better format meaning future upgrades should be backwards
compatible.
*******************************************
*** Changes since 0.5.6 ***
*******************************************
See: http://wiki.sabnzbd.org/introducing-0-6-0

View File

@@ -1,3 +1,71 @@
-------------------------------------------------------------------------------
0.6.9RC2 by The SABnzbd-Team
-------------------------------------------------------------------------------
- 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)
- Improve handling of non-creatable final and category folders
- Fix and I18N the "Downloaded in X days Y hours Z seconds" text in the history report.
- Change the OSX DMG window size so that the optional "path bar" doesn't obsure part of the background image.
-------------------------------------------------------------------------------
0.6.9RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- 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.
- For OSX make a Lion and a Leopard/SnowLeopard version and show this in DMG background image
- When removing job folders in the "temporary download folder", remove everything.
This is needed because some operating systems add spurious files and folders.
- Servers with square brackets in the name could not be removed.
- Check email parameters also when only email_rss is set.
- Try out work-around for potential memory leak in pickle.
-------------------------------------------------------------------------------
0.6.8Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix several RSS issues, due to corruption of stored RSS data
-------------------------------------------------------------------------------
0.6.7Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Prevent immediate exit after startup when queue is empty and
an end-of-queue action like "shutdown" was set
- Fix failure to launch browser when clicking shortcut the second time
- Allow jobs still waiting for post-processing to be deleted
- Delay starting of dowload task until after webserver is started.
- Plush: button "Purge failed NZBs & delete files" will now actually delete files
- Classic/smpl: add link "Purge failed NZBs & delete files"
- Plush: fix flashing top menu in Safari 5.1
-------------------------------------------------------------------------------
0.6.6Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Prevent crashes when running into disk-full situations.
-------------------------------------------------------------------------------
0.6.6RC1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- When "Download only" is used, do not send downloaded NZB files to the queue
- Fix bad links coming from nzbclub.com
- A job sometimes fails verification when the option "don't download samples" is used.
Now this option will be ignored when you click "Retry" in the history.
- File an error message when the RSS-email template is missing.
-------------------------------------------------------------------------------
0.6.6Beta2 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Fix sending of duplicate emails when using a list of recipients
- Fix handle leakage on Windows
- On OSX, SABnzbd didn't handle "Open With" of nzb.gz files properly
- Limit the amount of retries when getting a partial NZB from an index site
-------------------------------------------------------------------------------
0.6.6Beta1 by The SABnzbd-Team
-------------------------------------------------------------------------------
- Compatible with OSX Lion
- End-of-queue action now ignores paused items in the queue
- Fetching extra par2 files now obeys pause too
- Extension-based cleanup now also cleans sub-folders
-------------------------------------------------------------------------------
0.6.5Final by The SABnzbd-Team
-------------------------------------------------------------------------------
- Since 0.6.3, all end-of-queue actions failed.
- Generic sort: failed to recognize years surounded by underscores.
- When running the Wizard in German, the last page crashed.
-------------------------------------------------------------------------------
0.6.4Final by The SABnzbd-Team
-------------------------------------------------------------------------------

View File

@@ -1,4 +1,4 @@
SABnzbd 0.6.3
SABnzbd 0.6.9
-------------------------------------------------------------------------------
0) LICENSE
@@ -49,6 +49,11 @@ You need to have Python installed and some modules.
Unix/Linux/OSX
Python-2.5, 2.6 or 2.7 http://www.python.org
OSX Leopard/SnowLeopard
Python 2.6 http://www.activestate.com
OSX Lion Apple Python 2.7 (included in OSX)
Windows
Python-2.5.latest http://www.activestate.com
Python-2.6.latest

View File

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

54
README.md Normal file
View File

@@ -0,0 +1,54 @@
SABnzbd - The automated Usenet download tool
============================================
SABnzbd is an Open Source Binary Newsreader written in Python.
It's totally free, incredibly easy to use, and works practically everywhere.
SABnzbd makes Usenet as simple and streamlined as possible by automating everything we can. All you have to do is add an .nzb. SABnzbd takes over from there, where it will be automatically downloaded, verified, repaired, extracted and filed away with zero human interaction.
If you want to know more you can head over to our website: http://sabnzbd.org.
## Resolving Dependencies
SABnzbd has a good deal of dependencies you'll need before you can get running. If you've previously run SABnzbd from one of the various Linux packages floating around (Ubuntu, Debian, Fedora, etc), then you likely already have all the needed dependencies. If not, here's what you're looking for:
- `python` (We support Python 2.5-2.7, preferably 2.6 or 2.7.)
- `python-cheetah`
- `python-configobj`
- `python-feedparser`
- `python-dbus`
- `python-openssl`
- `python-support`
- `python-yenc`
- `par2` (Multi-threaded par2 can be downloaded from [ChuChuSoft](http://chuchusoft.com/par2_tbb/download.html) )
- `unrar` (Make sure you get the "official" non-free version of unrar)
- `unzip`
Your package manager should supply these. If not, we've got links in our more in-depth [installation guide](https://github.com/sabnzbd/sabnzbd/blob/master/INSTALL.txt).
## Running SABnzbd from source
Once you've sorted out all the dependencies, simply run:
```
python SABnzbd.py
```
Or, if you want to run in the background:
```
python -d -f /path/to/sabnzbd.ini
```
If you want multi-language support, run:
```
python tools/make_mo.py
```
Our many other commandline options are explained in depth [here](http://wiki.sabnzbd.org/command-line-parameters).
## About Our Repo
We're going to be attempting to follow the [gitflow model](http://nvie.com/posts/a-successful-git-branching-model/), so you can consider "master" to be whatever our present stable release build is (presently 0.6.x) and "develop" to be whatever our next build will be (presently 0.7.x). Once we transition from unstable to stable dev builds we'll create release branches, and encourage you to follow along and help us test.

View File

@@ -1,13 +1,36 @@
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\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.3\
\f0\b\fs48 \cf0 SABnzbd 0.6.9RC2\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
\b0\fs26 \cf0 \
\b What's new
\b0 \
RC2\
- 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)\
- Improve handling of non-creatable final and category folders\
- Fix and I18N the "Downloaded in X days Y hours Z seconds" text in the history report.\
- Change the OSX DMG window size so that the optional "path bar" doesn't obsure part of the background image.\
RC1\
- 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.\
\
- 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.\
It simplifies the process of downloading from Usenet dramatically,\
thanks to its friendly web-based user interface and advanced\
@@ -27,9 +50,7 @@ There is an extensive Wiki on the use of SABnzbd.\
\b Known problems and solutions\
\b0 Read the file
\b
\b0 "ISSUES.txt"
\b0 Read the file"ISSUES.txt"
\b \
\b0 \

View File

@@ -1,63 +1,29 @@
*******************************************
*** This is SABnzbd 0.6.3 ***
*******************************************
SABnzbd is an open-source cross-platform binary newsreader.
It simplifies the process of downloading from Usenet dramatically,
thanks to its friendly web-based user interface and advanced
built-in post-processing options that automatically verify, repair,
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.
************************ SABnzbd 0.6.9RC2 ************************
There is an extensive Wiki on the use of SABnzbd.
http://wiki.sabnzbd.org/
What's new:
RC2
- 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)
- Improve handling of non-creatable final and category folders
- Fix and I18N the "Downloaded in X days Y hours Z seconds" text in the history report.
- Change the OSX DMG window size so that the optional "path bar" doesn't obsure part of the background image.
RC1
- 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.
IMPORTANT INFORMATION about release 0.6.0:
http://wiki.sabnzbd.org/introducing-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
Please also read the file "ISSUES.txt"
About:
SABnzbd is an open-source cross-platform binary newsreader.
It simplifies the process of downloading from Usenet dramatically,
thanks to its friendly web-based user interface and advanced
built-in post-processing options that automatically verify, repair,
extract and clean up posts downloaded from Usenet.
*******************************************
*** Upgrading from 0.6.x ***
*******************************************
Stop SABnzbd.
Install new version
Start SABnzbd.
*******************************************
*** Upgrading from 0.5.x ***
*******************************************
Stop SABnzbd.
Uninstall current version, keeping the data.
Install new version
Start SABnzbd.
The organization of the download queue is different from 0.5.x.
0.6.x will finish downloading an existing queue, but you
cannot go back to an older version without losing your queue.
Also, your sabnzbd.ini file will be upgraded, making it
incompatible with release 0.5.x
*******************************************
*** Upgrading from 0.4.x ***
*******************************************
>>>>> PLEASE DOWNLOAD YOUR CURRENT QUEUE BEFORE UPGRADING <<<<<<
When upgrading from a 0.4.x release such as 0.4.12 your old settings will be kept.
You will however be given a fresh queue and history. If you have items in your queue
from the older version of SABnzbd, you can either re-import the nzb files if you kept
an nzb backup folder, or temporarily go back to 0.4.x until your queue is complete.
The history is now stored in a better format meaning future upgrades should be backwards
compatible.
*******************************************
*** Changes since 0.5.6 ***
*******************************************
See: http://wiki.sabnzbd.org/introducing-0-6-0
(c) Copyright 2007-2011 by "The SABnzbd-team" <team@sabnzbd.org>

View File

@@ -37,7 +37,7 @@ except ValueError:
print "Sorry, requires Python module Cheetah 2.0rc7 or higher."
sys.exit(1)
except:
print "The following modules need to be installed: Cheetah, cherrypy(included, unpack the zip)"
print "The Python module Cheetah is required"
sys.exit(1)
import cherrypy
@@ -62,20 +62,22 @@ except:
else:
SQLITE_DLL = False
import sabnzbd.lang
import sabnzbd
import sabnzbd.lang
import sabnzbd.interface
from sabnzbd.constants import *
import sabnzbd.newsunpack
from sabnzbd.misc import get_user_shellfolders, launch_a_browser, real_path, \
check_latest_version, panic_tmpl, panic_port, panic_host, panic_fwall, panic_sqlite, panic, exit_sab, \
panic_xport, notify, split_host, get_ext, create_https_certificates, \
from sabnzbd.misc import get_user_shellfolders, real_path, \
check_latest_version, exit_sab, \
split_host, get_ext, create_https_certificates, \
windows_variant, ip_extract, set_serv_parms, get_serv_parms, globber
from sabnzbd.panic import panic_tmpl, panic_port, panic_host, panic_fwall, \
panic_sqlite, panic, launch_a_browser, panic_xport
import sabnzbd.scheduler as scheduler
import sabnzbd.config as config
import sabnzbd.cfg
import sabnzbd.downloader
from sabnzbd.encoding import unicoder
from sabnzbd.encoding import unicoder, latin1
from sabnzbd.utils import osx
from threading import Thread
@@ -639,9 +641,12 @@ def find_free_port(host, currentport):
return 0
def check_for_sabnzbd(url, upload_nzbs):
def check_for_sabnzbd(url, upload_nzbs, allow_browser=True):
""" Check for a running instance of sabnzbd(same version) on this port
allow_browser==True|None will launch the browser, False will not.
"""
if allow_browser is None:
allow_browser = True
if is_sabnzbd_running(url):
# Upload any specified nzb files to the running instance
if upload_nzbs:
@@ -650,8 +655,9 @@ def check_for_sabnzbd(url, upload_nzbs):
upload_file(url, f)
else:
# Launch the web browser and quit since sabnzbd is already running
# Trim away everything after the final slash in the URL
url = url[:url.rfind('/')+1]
launch_a_browser(url, force=True)
launch_a_browser(url, force=allow_browser)
exit_sab(0)
return True
return False
@@ -742,6 +748,12 @@ def commandline_handler(frozen=True):
serv_opts = [os.path.normpath(os.path.abspath(sys.argv[0]))]
upload_nzbs = []
# OSX binary: get rid of the weird -psn_0_123456 parameter
for arg in sys.argv:
if arg.startswith('-psn_'):
sys.argv.remove(arg)
break
# Ugly hack to remove the extra "SABnzbd*" parameter the Windows binary
# gets when it's restarted
if len(sys.argv) > 1 and \
@@ -761,7 +773,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',
'log-all', 'no-login', 'pid=', 'new', 'sessions',
# Below Win32 Service options
'password=', 'username=', 'startup=', 'perfmonini=', 'perfmondll=',
'interactive', 'wait=',
@@ -808,6 +820,7 @@ def get_f_option(opts):
#------------------------------------------------------------------------------
def main():
global LOG_FLAG
import sabnzbd # Due to ApplePython bug
autobrowser = None
autorestarted = False
@@ -833,6 +846,7 @@ def main():
re_argv = [sys.argv[0]]
pid_path = None
new_instance = False
force_sessions = False
service, sab_opts, serv_opts, upload_nzbs = commandline_handler()
@@ -913,6 +927,8 @@ def main():
re_argv.append(arg)
elif opt in ('--new',):
new_instance = True
elif opt in ('--sessions',):
force_sessions = True
sabnzbd.MY_FULLNAME = os.path.normpath(os.path.abspath(sabnzbd.MY_FULLNAME))
sabnzbd.MY_NAME = os.path.basename(sabnzbd.MY_FULLNAME)
@@ -951,6 +967,8 @@ def main():
# Detect Windows variant
if sabnzbd.WIN32:
vista_plus, vista64 = windows_variant()
sabnzbd.WIN64 = vista64
if not SQLITE_DLL:
panic_sqlite(sabnzbd.MY_FULLNAME)
@@ -1020,7 +1038,7 @@ def main():
url = None
if sabnzbd.WIN32 and not new_instance:
url = get_connection_info()
if url and check_for_sabnzbd(url, upload_nzbs):
if url and check_for_sabnzbd(url, upload_nzbs, autobrowser):
exit_sab(0)
# If an instance of sabnzbd(same version) is already running on this port, launch the browser
@@ -1038,7 +1056,7 @@ def main():
else:
if not url:
url = 'https://%s:%s/sabnzbd/api?' % (browserhost, port)
if new_instance or not check_for_sabnzbd(url, upload_nzbs):
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
newport = find_free_port(browserhost, port)
if newport > 0:
sabnzbd.cfg.https_port.set(newport)
@@ -1058,7 +1076,7 @@ def main():
else:
if not url:
url = 'http://%s:%s/sabnzbd/api?' % (browserhost, cherryport)
if new_instance or not check_for_sabnzbd(url, upload_nzbs):
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
port = find_free_port(browserhost, cherryport)
if port > 0:
sabnzbd.cfg.cherryport.set(port)
@@ -1164,7 +1182,6 @@ def main():
suffix = ' (=Vista+)'
if vista64:
suffix = ' (=Vista+ x64)'
sabnzbd.WIN64 = True
try:
logging.info('Platform=%s%s Class=%s', platform.platform(), suffix, os.name)
except:
@@ -1172,6 +1189,7 @@ def main():
else:
logging.info('Platform = %s', os.name)
logging.info('Python-version = %s', sys.version)
logging.info('Arguments = %s', sabnzbd.CMDLINE)
# OSX 10.5 I/O priority setting
if sabnzbd.DARWIN:
@@ -1225,21 +1243,8 @@ def main():
# Save the INI file
config.save_config(force=True)
logging.info('Starting %s-%s', sabnzbd.MY_NAME, sabnzbd.__version__)
try:
sabnzbd.start()
except:
logging.exception("Failed to start %s-%s", sabnzbd.MY_NAME, sabnzbd.__version__)
sabnzbd.halt()
print_modules()
# Upload any nzb/zip/rar/nzb.gz files from file association
if upload_nzbs:
from sabnzbd.utils.upload import add_local
for f in upload_nzbs:
add_local(f)
cherrylogtoscreen = False
sabnzbd.WEBLOGFILE = None
@@ -1285,6 +1290,14 @@ def main():
sabnzbd.cfg.username.set('')
sabnzbd.cfg.password.set('')
# Fix leakage in memory-based CherryPy session support by using file-based.
# However, we don't really need session support.
if force_sessions:
sessions = sabnzbd.misc.create_real_path('sessions', sabnzbd.cfg.admin_dir.get_path(), 'sessions')[1]
sabnzbd.misc.remove_all(sessions, 'session-*.lock', keep_folder=True)
else:
sessions = None
cherrypy.config.update({'server.environment': 'production',
'server.socket_host': cherryhost,
'server.socket_port': cherryport,
@@ -1294,10 +1307,13 @@ def main():
'engine.reexec_retry' : 100,
'tools.encode.on' : True,
'tools.gzip.on' : True,
'tools.sessions.on' : True,
'tools.sessions.on' : bool(sessions),
'tools.sessions.storage_type' : 'file',
'tools.sessions.storage_path' : sessions,
'tools.sessions.timeout' : 60,
'request.show_tracebacks': True,
'checker.check_localhost' : bool(consoleLogging),
'error_page.401': sabnzbd.misc.error_page_401
'error_page.401': sabnzbd.panic.error_page_401
})
@@ -1369,7 +1385,9 @@ def main():
sabnzbd.BROWSER_URL = browser_url
if not autorestarted:
launch_a_browser(browser_url)
notify("SAB_Launched", None)
if sabnzbd.FOUNDATION:
import sabnzbd.osxmenu
sabnzbd.osxmenu.notify("SAB_Launched", None)
osx.sendGrowlMsg('SABnzbd %s' % (sabnzbd.__version__),"http://%s:%s/sabnzbd" % (browserhost, cherryport),osx.NOTIFICATION['startup'])
# Now's the time to check for a new version
check_latest_version()
@@ -1399,6 +1417,20 @@ def main():
if pid_path:
sabnzbd.pid_file(pid_path, cherryport)
# Start all SABnzbd tasks
logging.info('Starting %s-%s', sabnzbd.MY_NAME, sabnzbd.__version__)
try:
sabnzbd.start()
except:
logging.exception("Failed to start %s-%s", sabnzbd.MY_NAME, sabnzbd.__version__)
sabnzbd.halt()
# Upload any nzb/zip/rar/nzb.gz files from file association
if upload_nzbs:
from sabnzbd.utils.upload import add_local
for f in upload_nzbs:
add_local(f)
# Have to keep this running, otherwise logging will terminate
timer = 0
while not sabnzbd.SABSTOP:
@@ -1488,7 +1520,7 @@ def main():
mail.send('stop')
if sabnzbd.WIN32:
del_connection_info()
notify("SAB_Shutdown", None)
if sabnzbd.FOUNDATION: sabnzbd.osxmenu.notify("SAB_Shutdown", None)
logging.info('Leaving SABnzbd')
sys.stderr.flush()
sys.stdout.flush()
@@ -1620,6 +1652,8 @@ def HandleCommandLine(allow_service=True):
#
if __name__ == '__main__':
sabnzbd.CMDLINE = ', '.join(['"%s"' % latin1(p) for p in sys.argv])
if sabnzbd.WIN32:
if not HandleCommandLine(allow_service=not hasattr(sys, "frozen")):
main()

View File

@@ -6,6 +6,7 @@
<span class="SubMenu">
<a href="./purge?session=$session" onclick="return confirm('$T('purgeHistConf').replace("'","`") ');">$T('purgeHist')</a> |
<a href="./purge_failed?session=$session" onclick="return confirm('$T('purgeHistFailedConf').replace("'","`") ');">$T('purgeHistFailed')</a> |
<a href="./purge_failed?session=$session&del_files=1" onclick="return confirm('$T('purgeFailed-Files').replace("'","`") ');">$T('purgeFailed-Files')</a> |
<!--#if $isverbose#-->
<a href="./tog_verbose?session=$session">$T('hideDetails')</a> |
<!--#else#-->

View File

@@ -13,7 +13,7 @@
<title>SABnzbd $version - $T('queued'): $mbleft $T('MB')</title>
<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="${path}rss?mode=history"/>
<link rel="stylesheet" type="text/css" href="${path}static/stylesheets/jqueryui/overcast/jquery-ui-1.8.9.custom.css?$version"/>
<link rel="stylesheet" type="text/css" href="${path}static/stylesheets/jqueryui/overcast/jquery-ui-1.8.15.custom.css?$version"/>
#if $color_scheme#
<link rel="shortcut icon" type="image/ico" href="${path}static/stylesheets/colorschemes/$color_scheme/images/sabnzbdplus.ico"/>
<link rel="stylesheet" type="text/css" href="${path}static/stylesheets/colorschemes/$color_scheme/${color_scheme}.css?$version"/>

View File

@@ -79,27 +79,27 @@ jQuery(document).ready(function($){
// selections
$("#nzo_select_all").click(function(){
$("INPUT[type='checkbox']").attr('checked', true).trigger('change');
$("INPUT[type='checkbox']").prop('checked', true).trigger('change');
});
var last1, last2;
$("#nzo_select_range").click(function(){
if (last1 && last2 && last1 < last2)
$("INPUT[type='checkbox']").slice(last1,last2).attr('checked', true).trigger('change');
$("INPUT[type='checkbox']").slice(last1,last2).prop('checked', true).trigger('change');
else if (last1 && last2)
$("INPUT[type='checkbox']").slice(last2,last1).attr('checked', true).trigger('change');
$("INPUT[type='checkbox']").slice(last2,last1).prop('checked', true).trigger('change');
});
$("#nzo_select_invert").click(function(){
$("INPUT[type='checkbox']").each( function() {
$(this).attr('checked', !$(this).attr('checked')).trigger('change');
$(this).prop('checked', !$(this).prop('checked')).trigger('change');
});
});
$("#nzo_select_none").click(function(){
$("INPUT[type='checkbox']").attr('checked', false).trigger('change');
$("INPUT[type='checkbox']").prop('checked', false).trigger('change');
});
// click filenames to select
$('#config_content .nzoTable .nzf_row').click(function(event) {
$('#box-'+$(event.target).parent().attr('id')).attr('checked', !$('#box-'+$(event.target).parent().attr('id')).attr('checked')).trigger('change');
$('#box-'+$(event.target).parent().attr('id')).prop('checked', !$('#box-'+$(event.target).parent().attr('id')).prop('checked')).trigger('change');
// range event interaction -- see further above
if (last1) last2 = last1;
@@ -108,7 +108,7 @@ jQuery(document).ready(function($){
//
$('#config_content .nzoTable .nzf_row input').change(function(e){
if ($(e.target).attr('checked'))
if ($(e.target).prop('checked'))
$(e.target).parent().parent().addClass("nzo_highlight");
else
$(e.target).parent().parent().removeClass("nzo_highlight");

View File

File diff suppressed because one or more lines are too long

View File

@@ -161,20 +161,20 @@ jQuery(function($){
}).trigger('change');
// Confirm Queue Deletions toggle
$("#confirmDeleteQueue").attr('checked', $.plush.confirmDeleteQueue ).change( function() {
$.plush.confirmDeleteQueue = $("#confirmDeleteQueue").attr('checked');
$("#confirmDeleteQueue").prop('checked', $.plush.confirmDeleteQueue ).change( function() {
$.plush.confirmDeleteQueue = $("#confirmDeleteQueue").prop('checked');
$.cookie('plushConfirmDeleteQueue', $.plush.confirmDeleteQueue ? 1 : 0, { expires: 365, path: '/' });
});
// Confirm History Deletions toggle
$("#confirmDeleteHistory").attr('checked', $.plush.confirmDeleteHistory ).change( function() {
$.plush.confirmDeleteHistory = $("#confirmDeleteHistory").attr('checked');
$("#confirmDeleteHistory").prop('checked', $.plush.confirmDeleteHistory ).change( function() {
$.plush.confirmDeleteHistory = $("#confirmDeleteHistory").prop('checked');
$.cookie('plushConfirmDeleteHistory', $.plush.confirmDeleteHistory ? 1 : 0, { expires: 365, path: '/' });
});
// Block Refreshes on Hover toggle
$("#blockRefresh").attr('checked', $.plush.blockRefresh ).change( function() {
$.plush.blockRefresh = $("#blockRefresh").attr('checked');
$("#blockRefresh").prop('checked', $.plush.blockRefresh ).change( function() {
$.plush.blockRefresh = $("#blockRefresh").prop('checked');
$.cookie('plushBlockRefresh', $.plush.blockRefresh ? 1 : 0, { expires: 365, path: '/' });
});
@@ -690,22 +690,22 @@ $.plush.queueprevslots = $.plush.queuenoofslots; // for the next refresh
// selections
$("#multiops_select_all").click(function(){
$("INPUT[type='checkbox']","#queueTable").attr('checked', true).trigger('change');
$("INPUT[type='checkbox']","#queueTable").prop('checked', true).trigger('change');
});
var last1, last2;
$("#multiops_select_range").click(function(){
if (last1 && last2 && last1 < last2)
$("INPUT[type='checkbox']","#queueTable").slice(last1,last2).attr('checked', true).trigger('change');
$("INPUT[type='checkbox']","#queueTable").slice(last1,last2).prop('checked', true).trigger('change');
else if (last1 && last2)
$("INPUT[type='checkbox']","#queueTable").slice(last2,last1).attr('checked', true).trigger('change');
$("INPUT[type='checkbox']","#queueTable").slice(last2,last1).prop('checked', true).trigger('change');
});
$("#multiops_select_invert").click(function(){
$("INPUT[type='checkbox']","#queueTable").each( function() {
$(this).attr('checked', !$(this).attr('checked')).trigger('change');
$(this).prop('checked', !$(this).prop('checked')).trigger('change');
});
});
$("#multiops_select_none").click(function(){
$("INPUT[type='checkbox']","#queueTable").attr('checked', false).trigger('change');
$("INPUT[type='checkbox']","#queueTable").prop('checked', false).trigger('change');
});
$("#queue").delegate('.multiops','change',function(event) {
// range event interaction
@@ -713,7 +713,7 @@ $.plush.queueprevslots = $.plush.queuenoofslots; // for the next refresh
last1 = $(event.target).parent()[0].rowIndex ? $(event.target).parent()[0].rowIndex : $(event.target).parent().parent()[0].rowIndex;
// checkbox state persistence
if ($(this).attr('checked'))
if ($(this).prop('checked'))
$.plush.multiOpsChecks[$(this).parent().parent().attr('id')] = true;
else if ($.plush.multiOpsChecks[$(this).parent().parent().attr('id')])
delete $.plush.multiOpsChecks[$(this).parent().parent().attr('id')];
@@ -740,7 +740,7 @@ $("a","#multiops_inputs").click(function(e){
nzo_ids = nzo_ids.substr(1);
if (!nzo_ids) return;
$(this).attr('disabled',true);
$(this).prop('disabled',true);
if ($('#multi_status').val())
$.ajax({
@@ -777,7 +777,7 @@ $("a","#multiops_inputs").click(function(e){
data: {mode: 'change_script', value: nzo_ids, value2: $('#multi_script').val(), apikey: $.plush.apikey}
});
$(this).attr('disabled',false);
$(this).prop('disabled',false);
$.plush.RefreshQueue();
});
@@ -908,10 +908,10 @@ $("a","#multiops_inputs").click(function(e){
$('#delete_nzb_modal_title').text( $(this).parent().prev().prev().children('a:first').text() );
$('#delete_nzb_modal_job').val( $(this).parent().parent().attr('id') );
$('#delete_nzb_modal_mode').val( 'history' );
if ($(this).parent().parent().children('td:first').children().hasClass('sprite_hv_error'))
$('#delete_nzb_modal_remove_files').button('enable');
else
if ($(this).parent().parent().children('td:first').children().hasClass('sprite_hv_star'))
$('#delete_nzb_modal_remove_files').button('disable');
else
$('#delete_nzb_modal_remove_files').button('enable');
$.colorbox({ inline:true, href:"#delete_nzb_modal", title:$(this).text(),
innerWidth:"600px", innerHeight:"150px", initialWidth:"600px", initialHeight:"150px", speed:0, opacity:0.7
});
@@ -1073,7 +1073,7 @@ $.plush.histprevslots = $.plush.histnoofslots; // for the next refresh
$('<input type="checkbox" class="multiops" />').appendTo('#queue tr td.nzb_status_col');
if ($.plush.multiOpsChecks) // checkbox state persistence
for (var nzo_id in $.plush.multiOpsChecks)
$('#'+nzo_id+' .multiops').attr('checked',true);
$('#'+nzo_id+' .multiops').prop('checked',true);
$('#queue-pagination span').removeClass('loading'); // Remove spinner graphic from pagination

View File

@@ -287,7 +287,7 @@ body {
}
.navigation ul li a {
color:#fff;
color:#efefef;
font-weight:bold;
display: block;
padding: 0 8px 0 0;
@@ -297,9 +297,10 @@ body {
line-height: 25px;
background-color:#363636;
/* background : -webkit-gradient(linear, right top, right bottom, from(rgb(168,168,168)), to(rgb(69,69,69)));
background : -moz-linear-gradient(top, rgb(168,168,168), rgb(69,69,69)); */
background : -moz-linear-gradient(top, rgb(168,168,168), rgb(69,69,69));
-webkit-transition-property: background;
-webkit-transition-duration: 700ms;
*/
-moz-transition-property: background;
-moz-transition-duration: 700ms;
}

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 B

After

Width:  |  Height:  |  Size: 129 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 B

After

Width:  |  Height:  |  Size: 142 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -1,5 +1,5 @@
/*
* jQuery UI CSS Framework 1.8.9
* jQuery UI CSS Framework 1.8.15
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
@@ -42,7 +42,7 @@
/*
* jQuery UI CSS Framework 1.8.9
* jQuery UI CSS Framework 1.8.15
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
@@ -280,20 +280,44 @@
----------------------------------*/
/* Corner radius */
.ui-corner-tl { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; }
.ui-corner-tr { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; }
.ui-corner-bl { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; }
.ui-corner-br { -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; }
.ui-corner-top { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; }
.ui-corner-bottom { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; }
.ui-corner-right { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; }
.ui-corner-left { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; }
.ui-corner-all { -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; }
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; -khtml-border-top-left-radius: 6px; border-top-left-radius: 6px; }
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; -khtml-border-top-right-radius: 6px; border-top-right-radius: 6px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; -khtml-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; -khtml-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; }
/* Overlays */
.ui-widget-overlay { background: #eeeeee url(images/ui-bg_flat_0_eeeeee_40x100.png) 50% 50% repeat-x; opacity: .80;filter:Alpha(Opacity=80); }
.ui-widget-shadow { margin: -4px 0 0 -4px; padding: 4px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .60;filter:Alpha(Opacity=60); -moz-border-radius: 0pxdow=0px; -webkit-border-radius: 0pxdow=0px; border-radius: 0pxdow=0px; }/*
* jQuery UI Button 1.8.9
.ui-widget-shadow { margin: -4px 0 0 -4px; padding: 4px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .60;filter:Alpha(Opacity=60); -moz-border-radius: 0pxdow=0px; -khtml-border-radius: 0pxdow=0px; -webkit-border-radius: 0pxdow=0px; border-radius: 0pxdow=0px; }/*
* jQuery UI Resizable 1.8.15
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Resizable#theming
*/
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
* jQuery UI Selectable 1.8.15
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Selectable#theming
*/
.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
/*
* jQuery UI Button 1.8.15
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
@@ -331,7 +355,28 @@ input.ui-button { padding: .4em 1em; }
/* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
/*
* jQuery UI Tabs 1.8.9
* jQuery UI Dialog 1.8.15
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Dialog#theming
*/
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }
/*
* jQuery UI Tabs 1.8.15
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.

View File

@@ -8,6 +8,7 @@
<div class="centerLinks"><br />
<a onClick="if(confirm('$T('purgeHistConf')')){javascript:loadSearch('history/purge', 'historySearch', 'limit=$limit&start=0', -1,this.parentNode.parentNode.id);}">$T('smpl-purgehist')</a> |
<a onClick="if(confirm('$T('smpl-purgefailhistOK?')')){javascript:loadSearch('history/purge_failed', 'historySearch', 'limit=$limit&start=0', -1,this.parentNode.parentNode.id);}">$T('smpl-purgefailhist')</a> |
<a onClick="if(confirm('$T('smpl-purgefailhistOK?')')){javascript:loadSearch('history/purge_failed', 'historySearch', 'limit=$limit&start=0&del_files=1', -1,this.parentNode.parentNode.id);}">$T('purgeFailed-Files')</a> |
<a onClick="javascript:loadSearch('history/tog_verbose', 'historySearch', 'limit=$limit&start=0', -1,this.parentNode.parentNode.id);"><!--#if $isverbose then $T('hideDetails') else $T('showDetails')#--></a> |
<a onClick="javascript:loadSearch('history/tog_failed_only', 'historySearch', 'limit=$limit&start=0', -1,this.parentNode.parentNode.id);"><!--#if $failed_only then $T('showAllHis') else $T('showFailedHis')#--></a>
</span>

View File

@@ -1015,10 +1015,6 @@ function loadingJSON(){
document.getElementById("mbtotal").innerHTML = info["mb"].toFixed(2);
document.getElementById("ds1").innerHTML = info["diskspace1"].toFixed(2);
document.getElementById("ds2").innerHTML = info["diskspace2"].toFixed(2);
//var perc1 = 1 - (info["jobs"][0]["mbleft"].toFixed(2) / info["jobs"][0]["mb"].toFixed(2))
//alert(info["jobs"][0]);
if (info["jobs"]!="") document.getElementById("downloadinfo").innerHTML = "$T('smpl-downloading'): "+info["jobs"][0]["filename"];
else document.getElementById("downloadinfo").innerHTML = "";
document.getElementById("have_warnings").innerHTML = info["have_warnings"];
load = document.getElementById("loadavg")
if (load) load.innerHTML = info["loadavg"];
@@ -1252,7 +1248,6 @@ function loadingJSON(){
</div>
<div id="Footer">
<div id="divchart"><canvas id="graph" height="100" width="700"></canvas></div>
<span id="downloadinfo"></span><br /><br />
<p id="versions">$T("smpl-refreshr"): <select id="refreshrate" onchange="javascript:applyrefresh(this.options[this.selectedIndex].value)">
<option value="2" >2 $T("seconds")</option>
<option value="3" >3 $T("seconds")</option>

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

Binary file not shown.

34
osx/unrar/license.txt Normal file
View File

@@ -0,0 +1,34 @@
****** ***** ****** UnRAR - free utility for RAR archives
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
****** ******* ****** License for use and distribution of
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
** ** ** ** ** ** FREEWARE version
~~~~~~~~~~~~~~~~
The UnRAR utility is freeware. This means:
1. All copyrights to RAR and the utility UnRAR are exclusively
owned by the author - Alexander Roshal.
2. The UnRAR utility may be freely distributed. It is allowed
to distribute UnRAR inside of other software packages.
3. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS".
NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
OR MISUSING THIS SOFTWARE.
4. Neither RAR binary code, WinRAR binary code, UnRAR source or UnRAR
binary code may be used or reverse engineered to re-create the RAR
compression algorithm, which is proprietary, without written
permission of the author.
5. If you don't agree with terms of the license you must remove
UnRAR files from your storage devices and cease to use the
utility.
Thank you for your interest in RAR and UnRAR.
Alexander L. Roshal

View File

Binary file not shown.

View File

@@ -48,7 +48,8 @@ def DeleteFiles(name):
''' Delete one file or set of files from wild-card spec '''
for f in glob.glob(name):
try:
os.remove(f)
if os.path.exists(f):
os.remove(f)
except:
print "Cannot remove file %s" % f
exit(1)
@@ -70,26 +71,38 @@ def CheckPath(name):
def PatchVersion(name):
""" Patch in the Bazaar baseline number, but only when this is
""" Patch in the Git commit hash, but only when this is
an unmodified checkout
"""
global my_version, my_baseline
commit = ''
try:
pipe = subprocess.Popen(BzrVersion, shell=True, stdout=subprocess.PIPE).stdout
pipe = subprocess.Popen(GitVersion, shell=True, stdout=subprocess.PIPE).stdout
for line in pipe.read().split('\n'):
if 'revno: ' in line:
bzr = line.split(' ')[1].strip()
if 'commit ' in line:
commit = line.split(' ')[1].strip()
break
pipe.close()
except:
pass
print 'Cannot run %s' % GitVersion
exit(1)
if not bzr:
print "WARNING: Cannot run %s" % BzrVersion
bzr = 'unknown'
state = ' (not committed)'
try:
pipe = subprocess.Popen(GitStatus, shell=True, stdout=subprocess.PIPE).stdout
for line in pipe.read().split('\n'):
if 'nothing to commit' in line:
state = ''
break
pipe.close()
except:
print 'Cannot run %s' % GitStatus
exit(1)
if not (bzr and bzr.isdigit()):
bzr = 'unknown'
if not commit:
print "WARNING: Cannot run %s" % GitVersion
commit = 'unknown'
try:
ver = open(VERSION_FILE, 'rb')
@@ -99,12 +112,12 @@ def PatchVersion(name):
print "WARNING: cannot patch " + VERSION_FILE
return
my_baseline = bzr
my_baseline = commit + state
my_version = name
regex = re.compile(r'__baseline__\s+=\s+"\w*"')
text = re.sub(r'__baseline__\s*=\s*"[^"]*"', '__baseline__ = "%s"' % bzr, text)
text = re.sub(r'__version__\s*=\s*"[^"]*"', '__version__ = "%s"' % name, text)
text = re.sub(r'__baseline__\s*=\s*"[^"]*"', '__baseline__ = "%s"' % my_baseline, text)
text = re.sub(r'__version__\s*=\s*"[^"]*"', '__version__ = "%s"' % my_version, text)
try:
ver = open(VERSION_FILE, 'wb')
@@ -120,14 +133,14 @@ def PairList(src):
A dir returns for its root and each of its subdirs
(path, <list-of-files>)
Always return paths with Unix slashes.
Skip all Bazaar elements, .bak .pyc .pyo and *.~*
Skip all Git elements, .bak .pyc .pyo and *.~*
"""
lst = []
for item in src:
if item.endswith('/'):
for root, dirs, files in os.walk(item.rstrip('/\\')):
path = root.replace('\\', '/')
if path.find('.bzr') < 0:
if path.find('.git') < 0:
flist = []
for file in files:
if not (file.endswith('.bak') or file.endswith('.pyc') or file.endswith('.pyo') or '~' in file):
@@ -239,18 +252,27 @@ def check_runtimes():
if path:
path = os.path.join(path, 'Bazaar')
if not os.path.exists(path):
path = None
if not path:
print 'Cannot find runtime libraries, have you installed Bazaar'
print 'in %s ?' % path
exit(1)
print 'Cannot find runtime libraries, have you installed Bazaar'
print 'in %s ?' % path
exit(1)
return path
def write_dll_message(path):
f = open(path, 'w')
f.write('''
**** IMPORTANT ****
If you get a Windows error message, claiming that DLL files are missing,
please install "Microsoft Visual C++ 2008 Redistributable Package (x86)".
Download from http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=29
Install this and *not* the SP1 package (or install both).
''')
f.close()
print sys.argv[0]
Bazaar = CheckPath('bzr')
Git = CheckPath('git')
ZipCmd = CheckPath('zip')
UnZipCmd = CheckPath('unzip')
if os.name == 'nt':
@@ -258,12 +280,13 @@ if os.name == 'nt':
else:
NSIS = '-'
BzrRevertApp = Bazaar + ' revert '
BzrUpdateApp = Bazaar + ' update '
BzrRevert = Bazaar + ' revert ' + VERSION_FILE
BzrVersion = Bazaar + ' version-info'
GitRevertApp = Git + ' checkout -- '
#GitUpdateApp = Git + ' update '
GitRevertVersion = GitRevertApp + ' ' + VERSION_FILE
GitVersion = Git + ' log -1'
GitStatus = Git + ' status'
if not (BzrVersion and BzrRevert and ZipCmd and UnZipCmd and NSIS):
if not (Git and ZipCmd and UnZipCmd and NSIS):
exit(1)
if len(sys.argv) < 2:
@@ -299,6 +322,7 @@ PatchVersion(release)
# List of data elements, directories end with a '/'
data_files = [
'ABOUT.txt',
'README.txt',
'INSTALL.txt',
'GPL2.txt',
@@ -307,6 +331,7 @@ data_files = [
'COPYRIGHT.txt',
'ISSUES.txt',
'nzb.ico',
'sabnzbd.ico',
'Sample-PostProc.cmd',
'Sample-PostProc.sh',
'PKG-INFO',
@@ -341,15 +366,29 @@ options = dict(
if target == 'app':
if not platform.system() == 'Darwin':
print "Sorry, only works on Apple OSX!"
os.system(BzrRevert)
os.system(GitRevertVersion)
exit(1)
# Check which Python flavour
apple_py = 'ActiveState' not in sys.copyright
#Create sparseimage from template
os.system("unzip sabnzbd-template.sparseimage.zip")
os.rename('sabnzbd-template.sparseimage', fileImg)
os.system("unzip osx/image/template.sparseimage.zip")
os.rename('template.sparseimage', fileImg)
#mount sparseimage and modify volume label
os.system("hdiutil mount %s | grep /Volumes/SABnzbd >mount.log" % (fileImg))
# Add OS version specific background image
# Use cat-append 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
os.system('cat osx/image/sabnzbd_lion.png >>/Volumes/SABnzbd/sabnzbd.png')
else:
# Snow Leopard and lower
os.system('cat osx/image/sabnzbd_leopard.png >>/Volumes/SABnzbd/sabnzbd.png')
# Rename the volume
fp = open('mount.log', 'r')
data = fp.read()
fp.close()
@@ -366,6 +405,11 @@ if target == 'app':
#build SABnzbd.py
sys.argv[1] = 'py2app'
# Due to ApplePython bug
if apple_py:
sys.argv.append('-p');
sys.argv.append('email');
APP = ['SABnzbd.py']
DATA_FILES = ['interfaces', 'locale', 'email', ('',glob.glob("osx/resources/*"))]
@@ -378,7 +422,7 @@ if target == 'app':
LSTypeIsPackage = 0,
NSPersistentStoreTypeKey = 'Binary',
)
OPTIONS = {'argv_emulation': True, 'iconfile': 'osx/resources/sabnzbdplus.icns','plist': {
OPTIONS = {'argv_emulation': not apple_py, 'iconfile': 'osx/resources/sabnzbdplus.icns','plist': {
'NSUIElement':1,
'CFBundleShortVersionString':release,
'NSHumanReadableCopyright':'The SABnzbd-Team',
@@ -399,15 +443,15 @@ 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("find dist/SABnzbd.app -name .bzr | xargs rm -rf")
os.system("find dist/SABnzbd.app -name .git | xargs rm -rf")
#copy builded app to mounted sparseimage
os.system("cp -r dist/SABnzbd.app /Volumes/%s/>/dev/null" % volume)
#Create src tar.gz
#os.system('tar -czf %s --exclude ".bzr" --exclude "sab*.zip" --exclude "SAB*.tar.gz" --exclude "*.cmd" --exclude "*.pyc" '
# '--exclude "*.sparseimage" --exclude "dist" --exclude "build" --exclude "*.nsi" --exclude "win"'
# './ >/dev/null' % (fileOSr) )
print 'Create src %s' % fileOSr
os.system('tar -czf %s --exclude ".git*" --exclude "sab*.zip" --exclude "SAB*.tar.gz" --exclude "*.cmd" --exclude "*.pyc" '
'--exclude "*.sparseimage" --exclude "dist" --exclude "build" --exclude "*.nsi" --exclude "win" --exclude "*.dmg" '
'./ >/dev/null' % (fileOSr) )
# Copy README.txt
os.system("cp README.rtf /Volumes/%s/" % volume)
@@ -427,18 +471,17 @@ if target == 'app':
os.system("hdiutil internet-enable %s" % fileDmg)
os.system(BzrRevertApp + "NSIS_Installer.nsi")
os.system(BzrRevertApp + VERSION_FILEAPP)
os.system(BzrRevertApp + VERSION_FILE)
os.system(BzrUpdateApp)
os.system(GitRevertApp + "NSIS_Installer.nsi")
os.system(GitRevertApp + VERSION_FILEAPP)
os.system(GitRevertApp + VERSION_FILE)
elif target in ('binary', 'installer'):
if not py2exe:
print "Sorry, only works on Windows!"
os.system(BzrRevert)
os.system(GitRevertVersion)
exit(1)
run_times = check_runtimes()
#run_times = check_runtimes()
# Create MO files
os.system('tools\\make_mo.py all')
@@ -513,14 +556,21 @@ elif target in ('binary', 'installer'):
rename_file('dist', Win32HelperName, Win32ServiceHelpName)
############################
# Remove unwanted system DLL files that Py2Exe copies when running on Win7
DeleteFiles(r'dist\lib\API-MS-Win-*.dll')
DeleteFiles(r'dist\lib\MSWSOCK.DLL')
DeleteFiles(r'dist\lib\POWRPROF.DLL')
############################
# Copy MS runtime files or Curl
if run_times:
# MS Runtimes for Python 2.6+
shutil.copy2(os.path.join(run_times, r'Microsoft.VC90.CRT.manifest'), r'dist')
shutil.copy2(os.path.join(run_times, r'msvcp90.dll'), r'dist')
shutil.copy2(os.path.join(run_times, r'msvcr90.dll'), r'dist')
shutil.copy2(os.path.join(run_times, r'lib\Microsoft.VC90.CRT.manifest'), r'dist\lib')
if sys.version > (2, 5):
#Won't work with OpenSSL DLLs :(
#shutil.copy2(os.path.join(run_times, r'Microsoft.VC90.CRT.manifest'), r'dist')
#shutil.copy2(os.path.join(run_times, r'msvcp90.dll'), r'dist')
#shutil.copy2(os.path.join(run_times, r'msvcr90.dll'), r'dist')
#shutil.copy2(os.path.join(run_times, r'lib\Microsoft.VC90.CRT.manifest'), r'dist\lib')
pass
else:
# Curl for Python 2.5
os.system(r'unzip -o win\curl\curl.zip -d dist\lib')
@@ -534,12 +584,13 @@ elif target in ('binary', 'installer'):
DeleteFiles(fileBin)
write_dll_message('dist/IMPORTANT_MESSAGE.txt')
os.rename('dist', prod)
os.system('zip -9 -r -X %s %s' % (fileBin, prod))
time.sleep(1.0)
os.rename(prod, 'dist')
os.system(BzrRevert)
os.system(GitRevertVersion)
############################
# Check for uncompressed sqlite3.dll
@@ -606,5 +657,5 @@ else:
# Prepare the TAR.GZ pacakge
CreateTar('srcdist', fileSrc, prod)
os.system(BzrRevert)
os.system(GitRevertVersion)

View File

@@ -8,14 +8,14 @@ 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-01-16 09:57+0000\n"
"Last-Translator: Fox Ace <Unknown>\n"
"PO-Revision-Date: 2011-08-01 19:14+0000\n"
"Last-Translator: shypike <Unknown>\n"
"Language-Team: LANGUAGE <LL@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-01-17 05:03+0000\n"
"X-Generator: Launchpad (build 12177)\n"
"X-Launchpad-Export-Date: 2011-08-02 04:50+0000\n"
"X-Generator: Launchpad (build 13552)\n"
"Language: fr\n"
#: email/email.tmpl:1
@@ -150,14 +150,14 @@ msgstr ""
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd a ajouté $ à la file d'attente\n"
"Subject: SABnzbd a ajouté $amount fichier(s) à la file d'attente\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## Après cela vient le contenu, la ligne vide est nécessaire!\n"
"\n"
"Bonjour,\n"
"\n"
"SABnzbd a ajouté $ à la file d'attente.\n"
"SABnzbd a ajouté $amount fichier(s) à la file d'attente.\n"
"Ils proviennent du Flux RSS \"$feed\".\n"
"<!--#for $job in $jobs#-->\n"
" $job <!--#slurp#-->\n"

View File

@@ -65,32 +65,32 @@ msgid ""
"<!--#end if#-->\n"
msgstr ""
"##\n"
"## Șablon Email Original pentru SABnzbd\n"
"## Acesta este un Șablon Cheetah\n"
"## Documentație: http://sabnzbd.wikidot.com/email-templates\n"
"## sablon Email Original pentru SABnzbd\n"
"## Acesta este un sablon Cheetah\n"
"## Documentatie: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"##Rândurile noi și caracterele spațiu sunt importante!\n"
"##Rândurile noi si caracterele spatiu sunt importante!\n"
"##\n"
"## Acestea sunt antetele email\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd <!--#if $status then \"a terminat\" else \"nu a reuşit\" #--"
"Subject: SABnzbd <!--#if $status then \"a terminat\" else \"nu a reusit\" #--"
"> sarcina $name\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## După acesta urmează conţinutul, este necesar o linie goală!\n"
"## Dupã acesta urmeazã continutul, este necesar o linie goalã!\n"
"\n"
"Salut,\n"
"<!--#if $status #-->\n"
"SABnzbd a descărcat \"$name\" <!--#if $msgid==\"\" then \"\" else \"(newzbin "
"SABnzbd a descãrcat \"$name\" <!--#if $msgid==\"\" then \"\" else \"(newzbin "
"#\" + $msgid + \")\"#-->\n"
"<!--#else#-->\n"
"SABnzbd nu a reuşit să descarce \"$name\" <!--#if $msgid==\"\" then \"\" "
"SABnzbd nu a reusit sã descarce \"$name\" <!--#if $msgid==\"\" then \"\" "
"else \"(newzbin #\" + $msgid + \")\"#-->\n"
"<!--#end if#-->\n"
"Terminat la $end_time\n"
"Mărime $size\n"
"Mãrime $size\n"
"\n"
"Rezultatele sarcinii:\n"
"<!--#for $stage in $stages #-->\n"
@@ -105,7 +105,7 @@ msgstr ""
"$script_output\n"
"<!--#end if#-->\n"
"<!--#if $status #-->\n"
"Bucuraţi-vă!\n"
"Bucurati-vã!\n"
"<!--#else#-->\n"
"Ne pare rau!\n"
"<!--#end if#-->\n"
@@ -138,24 +138,24 @@ msgid ""
"\n"
"Bye\n"
msgstr ""
"## Şablon Email RSS pentru SABnzbd\n"
"## Acesta este un şablon Cheetah \n"
"## Documentaţie: http://sabnzbd.wikidot.com/email-templates\n"
"## Sablon Email RSS pentru SABnzbd\n"
"## Acesta este un sablon Cheetah \n"
"## Documentatie: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"## Rândurile noi și caracterele spațiu sunt importante!\n"
"## Rândurile noi si caracterele spatiu sunt importante!\n"
"##\n"
"## Acestea sunt antetele email\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd a adăugat $amount sarcini în coadă\n"
"Subject: SABnzbd a adãugat $amount sarcini în coadã\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## După acesta urmează conţinutul, este necesar o linie goală!\n"
"## Dupã acesta urmeazã continutul, este necesar o linie goalã!\n"
"\n"
"Salut,\n"
"\n"
"SABnzbd a adăugat $amount sarcină(e) în coadă.\n"
"SABnzbd a adãugat $amount sarcinã(e) în coadã.\n"
"Ele sunt din fluxuri RSS \"$feed\".\n"
"<!--#for $job in $jobs#-->\n"
" $job <!--#slurp#-->\n"

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -13,55 +13,55 @@ msgstr ""
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 7bit\n"
#: NSIS_Installer.nsi:347
msgid "Start SABnzbd (hidden)"
#: NSIS_Installer.nsi:350
msgid "Start SABnzbd (hidden)"
msgstr ""
#: NSIS_Installer.nsi:355
msgid "Show Release Notes"
#: NSIS_Installer.nsi:359
msgid "Show Release Notes"
msgstr ""
#: NSIS_Installer.nsi:363
msgid "Support the project, Donate!"
#: NSIS_Installer.nsi:368
msgid "Support the project, Donate!"
msgstr ""
#: NSIS_Installer.nsi:371
msgid "Please close \"SABnzbd.exe\" first"
#: NSIS_Installer.nsi:377
msgid "Please close \"SABnzbd.exe\" first"
msgstr ""
#: NSIS_Installer.nsi:379
msgid " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the release notes or go to http://wiki.sabnzbd.org/introducing-0-6-0 !"
msgstr ""
#: NSIS_Installer.nsi:387
msgid "This will uninstall SABnzbd from your system"
#: NSIS_Installer.nsi:386
msgid " >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the release notes or go to http://wiki.sabnzbd.org/introducing-0-6-0 !"
msgstr ""
#: NSIS_Installer.nsi:395
msgid "Run at startup"
msgid "This will uninstall SABnzbd from your system"
msgstr ""
#: NSIS_Installer.nsi:403
msgid "Desktop Icon"
#: NSIS_Installer.nsi:404
msgid "Run at startup"
msgstr ""
#: NSIS_Installer.nsi:411
msgid "NZB File association"
#: NSIS_Installer.nsi:413
msgid "Desktop Icon"
msgstr ""
#: NSIS_Installer.nsi:419
msgid "Delete Program"
#: NSIS_Installer.nsi:422
msgid "NZB File association"
msgstr ""
#: NSIS_Installer.nsi:427
msgid "Delete Settings"
#: NSIS_Installer.nsi:431
msgid "Delete Program"
msgstr ""
#: NSIS_Installer.nsi:435
msgid "Delete Logs"
#: NSIS_Installer.nsi:440
msgid "Delete Settings"
msgstr ""
#: NSIS_Installer.nsi:443
msgid "Delete Cache"
#: NSIS_Installer.nsi:449
msgid "Delete Logs"
msgstr ""
#: NSIS_Installer.nsi:458
msgid "Delete Cache"
msgstr ""

View File

@@ -7,34 +7,34 @@ msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-0.6.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-08 19:32+0000\n"
"POT-Creation-Date: 2011-08-20 14:21+0000\n"
"PO-Revision-Date: 2011-03-11 15:27+0000\n"
"Last-Translator: Rene <Unknown>\n"
"Language-Team: LANGUAGE <LL@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-05-09 04:50+0000\n"
"X-Generator: Launchpad (build 12959)\n"
"X-Launchpad-Export-Date: 2011-08-21 04:51+0000\n"
"X-Generator: Launchpad (build 13697)\n"
"Language: da\n"
#: NSIS_Installer.nsi:347
#: NSIS_Installer.nsi:408
msgid "Start SABnzbd (hidden)"
msgstr "Start SABnzbd"
#: NSIS_Installer.nsi:355
#: NSIS_Installer.nsi:417
msgid "Show Release Notes"
msgstr "Vis udgivelsesbemærkninger"
#: NSIS_Installer.nsi:363
#: NSIS_Installer.nsi:426
msgid "Support the project, Donate!"
msgstr "Støtte projektet, donere!"
#: NSIS_Installer.nsi:371
#: NSIS_Installer.nsi:435
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Luk 'SABnzbd.exe' først"
#: NSIS_Installer.nsi:379
#: NSIS_Installer.nsi:444
msgid ""
" >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the "
"release notes or go to http://wiki.sabnzbd.org/introducing-0-6-0 !"
@@ -42,56 +42,34 @@ msgstr ""
" >>>> WARNING <<<<\\r\\n\\r\\nVenligst, kontrollér først "
"udgivelsesnoter eller gå til http://wiki.sabnzbd.org/introducing-0-6-0 !"
#: NSIS_Installer.nsi:387
#: NSIS_Installer.nsi:453
msgid "This will uninstall SABnzbd from your system"
msgstr "Dette vil afinstallere SABnzbd fra dit system"
#: NSIS_Installer.nsi:395
#: NSIS_Installer.nsi:462
msgid "Run at startup"
msgstr "Kør ved opstart"
#: NSIS_Installer.nsi:403
#: NSIS_Installer.nsi:471
msgid "Desktop Icon"
msgstr "Skrivebords ikon"
#: NSIS_Installer.nsi:411
#: NSIS_Installer.nsi:480
msgid "NZB File association"
msgstr "NZB filtilknytning"
#: NSIS_Installer.nsi:419
#: NSIS_Installer.nsi:489
msgid "Delete Program"
msgstr "Slet program"
#: NSIS_Installer.nsi:427
#: NSIS_Installer.nsi:498
msgid "Delete Settings"
msgstr "Slet instillinger"
#: NSIS_Installer.nsi:435
#: NSIS_Installer.nsi:507
msgid "Delete Logs"
msgstr "Slet logs"
#: NSIS_Installer.nsi:443
#: NSIS_Installer.nsi:516
msgid "Delete Cache"
msgstr "Slet hukommelse"
#~ msgid ""
#~ " >>>> WARNING <<<<\r\n"
#~ "\r\n"
#~ "If not empty, download your current queue with the old program.\r\n"
#~ "The new program will ignore your current queue!"
#~ msgstr ""
#~ " >>>> ADVARSEL <<<<\r\n"
#~ "\r\n"
#~ "Hvis ikke tom, skal du downloade din nuværende kø med det gamle program. \r\n"
#~ "Det nye program vil ignorere din nuværende kø!"
#~ msgid ""
#~ " >>>> WARNING <<<<\r\n"
#~ "\r\n"
#~ "Please, first check the release notes or go to "
#~ "http://wiki.sabnzbd.org/introducing-0-6-0 !"
#~ msgstr ""
#~ " >>>> ADVARSEL <<<<\r\n"
#~ "\r\n"
#~ "Venligst, check først udgivelse notaer eller gå til "
#~ "http://wiki.sabnzbd.org/introducing-0-6-0 !"

View File

@@ -7,34 +7,34 @@ msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-0.6.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-08 19:32+0000\n"
"POT-Creation-Date: 2011-08-20 14:21+0000\n"
"PO-Revision-Date: 2011-03-12 09:03+0000\n"
"Last-Translator: shypike <Unknown>\n"
"Language-Team: LANGUAGE <LL@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-05-09 04:50+0000\n"
"X-Generator: Launchpad (build 12959)\n"
"X-Launchpad-Export-Date: 2011-08-21 04:51+0000\n"
"X-Generator: Launchpad (build 13697)\n"
"Language: de\n"
#: NSIS_Installer.nsi:347
#: NSIS_Installer.nsi:408
msgid "Start SABnzbd (hidden)"
msgstr "SABnzbd starten (unsichtbar)"
#: NSIS_Installer.nsi:355
#: NSIS_Installer.nsi:417
msgid "Show Release Notes"
msgstr "Versionshinweise anzeigen"
#: NSIS_Installer.nsi:363
#: NSIS_Installer.nsi:426
msgid "Support the project, Donate!"
msgstr "Bitte unterstützen Sie das Projekt durch eine Spende!"
#: NSIS_Installer.nsi:371
#: NSIS_Installer.nsi:435
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Schliessen Sie bitte zuerst \"SABnzbd.exe\"."
#: NSIS_Installer.nsi:379
#: NSIS_Installer.nsi:444
msgid ""
" >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the "
"release notes or go to http://wiki.sabnzbd.org/introducing-0-6-0 !"
@@ -43,56 +43,34 @@ msgstr ""
"Versionsanmerkungen lesen oder \"http://wiki.sabnzbd.org/introducing-0-6-0 "
"besuchen!\""
#: NSIS_Installer.nsi:387
#: NSIS_Installer.nsi:453
msgid "This will uninstall SABnzbd from your system"
msgstr "Dies entfernt SABnzbd von Ihrem System"
#: NSIS_Installer.nsi:395
#: NSIS_Installer.nsi:462
msgid "Run at startup"
msgstr "Beim Systemstart ausführen"
#: NSIS_Installer.nsi:403
#: NSIS_Installer.nsi:471
msgid "Desktop Icon"
msgstr "Desktop-Symbol"
#: NSIS_Installer.nsi:411
#: NSIS_Installer.nsi:480
msgid "NZB File association"
msgstr "Mit NZB-Dateien verknüpfen"
#: NSIS_Installer.nsi:419
#: NSIS_Installer.nsi:489
msgid "Delete Program"
msgstr "Programm löschen"
#: NSIS_Installer.nsi:427
#: NSIS_Installer.nsi:498
msgid "Delete Settings"
msgstr "Einstellungen löschen"
#: NSIS_Installer.nsi:435
#: NSIS_Installer.nsi:507
msgid "Delete Logs"
msgstr "Protokoll löschen"
#: NSIS_Installer.nsi:443
#: NSIS_Installer.nsi:516
msgid "Delete Cache"
msgstr "Cache löschen"
#~ msgid ""
#~ " >>>> WARNING <<<<\r\n"
#~ "\r\n"
#~ "If not empty, download your current queue with the old program.\r\n"
#~ "The new program will ignore your current queue!"
#~ msgstr ""
#~ " >>>> ACHTUNG <<<<\r\n"
#~ "\r\n"
#~ "Warten Sie, bis das alte Programm alle Downloads fertiggestellt hat.\r\n"
#~ "Das neue Programm wird die noch ausstehenden Downloads ignorieren!"
#~ msgid ""
#~ " >>>> WARNING <<<<\r\n"
#~ "\r\n"
#~ "Please, first check the release notes or go to "
#~ "http://wiki.sabnzbd.org/introducing-0-6-0 !"
#~ msgstr ""
#~ " >>>> WARNUNG <<<<\r\n"
#~ "\r\n"
#~ "Bitte zuerst die Versionsanmerkungen lesen oder "
#~ "http://wiki.sabnzbd.org/introducing-0-6-0 besuchen!"

View File

@@ -7,34 +7,34 @@ msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-0.6.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-08 19:32+0000\n"
"POT-Creation-Date: 2011-08-20 14:21+0000\n"
"PO-Revision-Date: 2011-03-10 21:33+0000\n"
"Last-Translator: Fox Ace <Unknown>\n"
"Language-Team: FRANCAIS <LL@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-05-09 04:50+0000\n"
"X-Generator: Launchpad (build 12959)\n"
"X-Launchpad-Export-Date: 2011-08-21 04:51+0000\n"
"X-Generator: Launchpad (build 13697)\n"
"Language: fr\n"
#: NSIS_Installer.nsi:347
#: NSIS_Installer.nsi:408
msgid "Start SABnzbd (hidden)"
msgstr "Démarrer SABnzbd (caché)"
#: NSIS_Installer.nsi:355
#: NSIS_Installer.nsi:417
msgid "Show Release Notes"
msgstr "Afficher les notes de version"
#: NSIS_Installer.nsi:363
#: NSIS_Installer.nsi:426
msgid "Support the project, Donate!"
msgstr "Supportez le projet, faites un don !"
#: NSIS_Installer.nsi:371
#: NSIS_Installer.nsi:435
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Quittez \"SABnzbd.exe\" avant l'installation, SVP"
#: NSIS_Installer.nsi:379
#: NSIS_Installer.nsi:444
msgid ""
" >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the "
"release notes or go to http://wiki.sabnzbd.org/introducing-0-6-0 !"
@@ -43,57 +43,34 @@ msgstr ""
"vérifiez d'abord les notes de version ou visiter "
"http://wiki.sabnzbd.org/introducing-0-6-0 !"
#: NSIS_Installer.nsi:387
#: NSIS_Installer.nsi:453
msgid "This will uninstall SABnzbd from your system"
msgstr "Ceci désinstallera SABnzbd de votre système"
#: NSIS_Installer.nsi:395
#: NSIS_Installer.nsi:462
msgid "Run at startup"
msgstr "Lancer au démarrage"
#: NSIS_Installer.nsi:403
#: NSIS_Installer.nsi:471
msgid "Desktop Icon"
msgstr "Icône sur le Bureau"
#: NSIS_Installer.nsi:411
#: NSIS_Installer.nsi:480
msgid "NZB File association"
msgstr "Association des fichiers NZB"
#: NSIS_Installer.nsi:419
#: NSIS_Installer.nsi:489
msgid "Delete Program"
msgstr "Supprimer le programme"
#: NSIS_Installer.nsi:427
#: NSIS_Installer.nsi:498
msgid "Delete Settings"
msgstr "Supprimer les Paramètres"
#: NSIS_Installer.nsi:435
#: NSIS_Installer.nsi:507
msgid "Delete Logs"
msgstr "Supprimer les logs"
#: NSIS_Installer.nsi:443
#: NSIS_Installer.nsi:516
msgid "Delete Cache"
msgstr "Supprimer le Cache"
#~ msgid ""
#~ " >>>> WARNING <<<<\r\n"
#~ "\r\n"
#~ "If not empty, download your current queue with the old program.\r\n"
#~ "The new program will ignore your current queue!"
#~ msgstr ""
#~ " >>>> ATTENTION <<<<\r\n"
#~ "\r\n"
#~ "si votre file d'attente de téléchargement n'est pas vide, terminez la avec "
#~ "la version précédente du programme.\r\n"
#~ "La nouvelle version l'ignorera!"
#~ msgid ""
#~ " >>>> WARNING <<<<\r\n"
#~ "\r\n"
#~ "Please, first check the release notes or go to "
#~ "http://wiki.sabnzbd.org/introducing-0-6-0 !"
#~ msgstr ""
#~ " >>>>ATTENTION<<<<\r\n"
#~ "\r\n"
#~ "S'il vous plaît, vérifiez d'abord les notes de version ou aller sur "
#~ "http://wiki.sabnzbd.org/introducing-0-6-0 !"

View File

@@ -7,67 +7,67 @@ msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-0.6.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-08 19:32+0000\n"
"POT-Creation-Date: 2011-08-20 14:21+0000\n"
"PO-Revision-Date: 2010-10-06 21:37+0000\n"
"Last-Translator: shypike@sabnzbd.org\n"
"Language-Team: LANGUAGE <LL@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-05-09 04:50+0000\n"
"X-Generator: Launchpad (build 12959)\n"
"X-Launchpad-Export-Date: 2011-08-21 04:51+0000\n"
"X-Generator: Launchpad (build 13697)\n"
"Language: no\n"
#: NSIS_Installer.nsi:347
#: NSIS_Installer.nsi:408
msgid "Start SABnzbd (hidden)"
msgstr ""
#: NSIS_Installer.nsi:355
#: NSIS_Installer.nsi:417
msgid "Show Release Notes"
msgstr ""
#: NSIS_Installer.nsi:363
#: NSIS_Installer.nsi:426
msgid "Support the project, Donate!"
msgstr ""
#: NSIS_Installer.nsi:371
#: NSIS_Installer.nsi:435
msgid "Please close \"SABnzbd.exe\" first"
msgstr ""
#: NSIS_Installer.nsi:379
#: NSIS_Installer.nsi:444
msgid ""
" >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the "
"release notes or go to http://wiki.sabnzbd.org/introducing-0-6-0 !"
msgstr ""
#: NSIS_Installer.nsi:387
#: NSIS_Installer.nsi:453
msgid "This will uninstall SABnzbd from your system"
msgstr ""
#: NSIS_Installer.nsi:395
#: NSIS_Installer.nsi:462
msgid "Run at startup"
msgstr ""
#: NSIS_Installer.nsi:403
#: NSIS_Installer.nsi:471
msgid "Desktop Icon"
msgstr ""
#: NSIS_Installer.nsi:411
#: NSIS_Installer.nsi:480
msgid "NZB File association"
msgstr ""
#: NSIS_Installer.nsi:419
#: NSIS_Installer.nsi:489
msgid "Delete Program"
msgstr ""
#: NSIS_Installer.nsi:427
#: NSIS_Installer.nsi:498
msgid "Delete Settings"
msgstr ""
#: NSIS_Installer.nsi:435
#: NSIS_Installer.nsi:507
msgid "Delete Logs"
msgstr ""
#: NSIS_Installer.nsi:443
#: NSIS_Installer.nsi:516
msgid "Delete Cache"
msgstr ""

View File

@@ -7,34 +7,34 @@ msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-0.6.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-08 19:32+0000\n"
"POT-Creation-Date: 2011-08-20 14:21+0000\n"
"PO-Revision-Date: 2011-03-10 17:18+0000\n"
"Last-Translator: shypike <Unknown>\n"
"Language-Team: LANGUAGE <LL@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-05-09 04:50+0000\n"
"X-Generator: Launchpad (build 12959)\n"
"X-Launchpad-Export-Date: 2011-08-21 04:51+0000\n"
"X-Generator: Launchpad (build 13697)\n"
"Language: nl\n"
#: NSIS_Installer.nsi:347
#: NSIS_Installer.nsi:408
msgid "Start SABnzbd (hidden)"
msgstr "Start SABnzbd (verborgen)"
#: NSIS_Installer.nsi:355
#: NSIS_Installer.nsi:417
msgid "Show Release Notes"
msgstr "Toon vrijgave bericht"
#: NSIS_Installer.nsi:363
#: NSIS_Installer.nsi:426
msgid "Support the project, Donate!"
msgstr "Steun het project, Doneer!"
#: NSIS_Installer.nsi:371
#: NSIS_Installer.nsi:435
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Sluit \"SABnzbd.exe\" eerst af"
#: NSIS_Installer.nsi:379
#: NSIS_Installer.nsi:444
msgid ""
" >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the "
"release notes or go to http://wiki.sabnzbd.org/introducing-0-6-0 !"
@@ -42,56 +42,34 @@ msgstr ""
" >>>> WAARSCHUWING <<<<\\r\\n\\r\\nLees eerst het vrijgave "
"bericht of ga naar \"http://wiki.sabnzbd.org/introducing-0-6-0 !\""
#: NSIS_Installer.nsi:387
#: NSIS_Installer.nsi:453
msgid "This will uninstall SABnzbd from your system"
msgstr "Dit verwijdert SABnzbd van je systeem"
#: NSIS_Installer.nsi:395
#: NSIS_Installer.nsi:462
msgid "Run at startup"
msgstr "Opstarten bij systeem start"
#: NSIS_Installer.nsi:403
#: NSIS_Installer.nsi:471
msgid "Desktop Icon"
msgstr "Pictogram op bureaublad"
#: NSIS_Installer.nsi:411
#: NSIS_Installer.nsi:480
msgid "NZB File association"
msgstr "NZB bestanden koppelen aan SABnzbd"
#: NSIS_Installer.nsi:419
#: NSIS_Installer.nsi:489
msgid "Delete Program"
msgstr "Verwijder programma"
#: NSIS_Installer.nsi:427
#: NSIS_Installer.nsi:498
msgid "Delete Settings"
msgstr "Verwijder instellingen"
#: NSIS_Installer.nsi:435
#: NSIS_Installer.nsi:507
msgid "Delete Logs"
msgstr "Verwijder logging"
#: NSIS_Installer.nsi:443
#: NSIS_Installer.nsi:516
msgid "Delete Cache"
msgstr "Verwijder Cache"
#~ msgid ""
#~ " >>>> WARNING <<<<\r\n"
#~ "\r\n"
#~ "If not empty, download your current queue with the old program.\r\n"
#~ "The new program will ignore your current queue!"
#~ msgstr ""
#~ " >>>> WAARSCHUWING <<<<\r\n"
#~ "\r\n"
#~ "Indien niet leeg, download eerst de gehele huidige wachtrij met het oude "
#~ "programma.\r\n"
#~ "Het nieuwe programma zal je huidige wachtrij negeren!"
#~ msgid ""
#~ " >>>> WARNING <<<<\r\n"
#~ "\r\n"
#~ "Please, first check the release notes or go to "
#~ "http://wiki.sabnzbd.org/introducing-0-6-0 !"
#~ msgstr ""
#~ " >>>> WAARSCHUWING <<<<\r\n"
#~ "Lees eerst het vrijgave bericht of ga naar "
#~ "http://wiki.sabnzbd.org/introducing-0-6-0 !"

View File

@@ -7,33 +7,33 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-05-08 19:32+0000\n"
"POT-Creation-Date: 2011-08-20 14:21+0000\n"
"PO-Revision-Date: 2011-05-07 04:50+0000\n"
"Last-Translator: nicusor <Unknown>\n"
"Language-Team: Romanian <ro@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-05-09 04:50+0000\n"
"X-Generator: Launchpad (build 12959)\n"
"X-Launchpad-Export-Date: 2011-08-21 04:51+0000\n"
"X-Generator: Launchpad (build 13697)\n"
#: NSIS_Installer.nsi:347
#: NSIS_Installer.nsi:408
msgid "Start SABnzbd (hidden)"
msgstr "Porneşte SABnzbd (ascuns)"
#: NSIS_Installer.nsi:355
#: NSIS_Installer.nsi:417
msgid "Show Release Notes"
msgstr "Arată Notele de Publicare"
#: NSIS_Installer.nsi:363
#: NSIS_Installer.nsi:426
msgid "Support the project, Donate!"
msgstr "Susţine proiectul, Donează!"
#: NSIS_Installer.nsi:371
#: NSIS_Installer.nsi:435
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Închideţi mai întâi \"SABnzbd.exe\""
#: NSIS_Installer.nsi:379
#: NSIS_Installer.nsi:444
msgid ""
" >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the "
"release notes or go to http://wiki.sabnzbd.org/introducing-0-6-0 !"
@@ -42,34 +42,34 @@ msgstr ""
"întâi notele de publicare sau mergeţi la http://wiki.sabnzbd.org/introducing-"
"0-6-0 !"
#: NSIS_Installer.nsi:387
#: NSIS_Installer.nsi:453
msgid "This will uninstall SABnzbd from your system"
msgstr "Acest lucru va dezinstala SABnzbd din sistem"
#: NSIS_Installer.nsi:395
#: NSIS_Installer.nsi:462
msgid "Run at startup"
msgstr "Executare la pornire"
#: NSIS_Installer.nsi:403
#: NSIS_Installer.nsi:471
msgid "Desktop Icon"
msgstr "Icoană Desktop"
#: NSIS_Installer.nsi:411
#: NSIS_Installer.nsi:480
msgid "NZB File association"
msgstr "Asociere cu Fişierele NZB"
#: NSIS_Installer.nsi:419
#: NSIS_Installer.nsi:489
msgid "Delete Program"
msgstr "Şterge Program"
#: NSIS_Installer.nsi:427
#: NSIS_Installer.nsi:498
msgid "Delete Settings"
msgstr "Ştergeţi Setări"
#: NSIS_Installer.nsi:435
#: NSIS_Installer.nsi:507
msgid "Delete Logs"
msgstr "Ştergeţi Activitate"
#: NSIS_Installer.nsi:443
#: NSIS_Installer.nsi:516
msgid "Delete Cache"
msgstr "Ştergeţi Cache"

View File

@@ -7,34 +7,34 @@ msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-0.6.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-08 19:32+0000\n"
"POT-Creation-Date: 2011-08-20 14:21+0000\n"
"PO-Revision-Date: 2011-05-09 12:25+0000\n"
"Last-Translator: Jerry Malmström <Unknown>\n"
"Language-Team: LANGUAGE <LL@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-05-10 05:44+0000\n"
"X-Generator: Launchpad (build 12959)\n"
"X-Launchpad-Export-Date: 2011-08-21 04:51+0000\n"
"X-Generator: Launchpad (build 13697)\n"
"Language: sv\n"
#: NSIS_Installer.nsi:347
#: NSIS_Installer.nsi:408
msgid "Start SABnzbd (hidden)"
msgstr "Starta SABnzbd (dold)"
#: NSIS_Installer.nsi:355
#: NSIS_Installer.nsi:417
msgid "Show Release Notes"
msgstr "Visa release noteringar"
#: NSIS_Installer.nsi:363
#: NSIS_Installer.nsi:426
msgid "Support the project, Donate!"
msgstr "Donera och stöd detta projekt!"
#: NSIS_Installer.nsi:371
#: NSIS_Installer.nsi:435
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Var vänlig stäng \"SABnzbd.exe\" först"
#: NSIS_Installer.nsi:379
#: NSIS_Installer.nsi:444
msgid ""
" >>>> WARNING <<<<\\r\\n\\r\\nPlease, first check the "
"release notes or go to http://wiki.sabnzbd.org/introducing-0-6-0 !"
@@ -42,45 +42,34 @@ msgstr ""
" >>>> VARNING <<<<\\r\\n\\r\\nVar vänlig och läs versions "
"noteringarna eller gå till http://wiki.sabnzbd.org/introducing-0-6-0 !"
#: NSIS_Installer.nsi:387
#: NSIS_Installer.nsi:453
msgid "This will uninstall SABnzbd from your system"
msgstr "Detta kommer att avinstallera SABnzbd från systemet"
#: NSIS_Installer.nsi:395
#: NSIS_Installer.nsi:462
msgid "Run at startup"
msgstr "Kör vid uppstart"
#: NSIS_Installer.nsi:403
#: NSIS_Installer.nsi:471
msgid "Desktop Icon"
msgstr "Skrivbordsikon"
#: NSIS_Installer.nsi:411
#: NSIS_Installer.nsi:480
msgid "NZB File association"
msgstr "NZB Filassosication"
#: NSIS_Installer.nsi:419
#: NSIS_Installer.nsi:489
msgid "Delete Program"
msgstr "Ta bort programmet"
#: NSIS_Installer.nsi:427
#: NSIS_Installer.nsi:498
msgid "Delete Settings"
msgstr "Ta bort inställningar"
#: NSIS_Installer.nsi:435
#: NSIS_Installer.nsi:507
msgid "Delete Logs"
msgstr "Ta bort logg"
#: NSIS_Installer.nsi:443
#: NSIS_Installer.nsi:516
msgid "Delete Cache"
msgstr "Ta bort temporär-mapp"
#~ msgid ""
#~ " >>>> WARNING <<<<\r\n"
#~ "\r\n"
#~ "If not empty, download your current queue with the old program.\r\n"
#~ "The new program will ignore your current queue!"
#~ msgstr ""
#~ " >>>> VARNING <<<<\r\n"
#~ "\r\n"
#~ "Om kön inte är tom, hämta din nuvarande kö med det gamla programmet.\r\n"
#~ "Det nya programmet kommer att ignorera din nuvarande kö!"

View File

Binary file not shown.

View File

@@ -68,6 +68,7 @@ from sabnzbd.downloader import Downloader
from sabnzbd.assembler import Assembler
from sabnzbd.newzbin import Bookmarks, MSGIDGrabber
import sabnzbd.misc as misc
import sabnzbd.powersup as powersup
from sabnzbd.dirscanner import DirScanner, ProcessArchiveFile, ProcessSingleFile
from sabnzbd.urlgrabber import URLGrabber
import sabnzbd.scheduler as scheduler
@@ -85,7 +86,7 @@ import sabnzbd.api
from sabnzbd.decorators import *
from sabnzbd.constants import *
LINUX_POWER = misc.HAVE_DBUS
LINUX_POWER = powersup.HAVE_DBUS
START = datetime.datetime.now()
@@ -103,7 +104,6 @@ DIR_PID = None
QUEUECOMPLETE = None #stores the nice name of the action
QUEUECOMPLETEACTION = None #stores the name of the function to be called
QUEUECOMPLETEARG = None #stores an extra arguments that need to be passed
QUEUECOMPLETEACTION_GO = False # Booleen value whether to run an action or not at the queue end.
DAEMON = None
@@ -115,6 +115,7 @@ LOG_ALL = False
AMBI_LOCALHOST = False
WIN_SERVICE = None # Instance of our Win32 Service Class
BROWSER_URL = None
CMDLINE = '' # Rendering of original command line arguments
WEB_DIR = None
WEB_DIR2 = None
@@ -249,12 +250,12 @@ def initialize(pause_downloader = False, clean_up = False, evalSched=False, repa
pause_downloader = True
else:
# Check crash detection file
if load_admin(TERM_FLAG_FILE, remove=True):
#if load_admin(TERM_FLAG_FILE, remove=True):
# Repair mode 2 is a bit over an over-reaction!
pass # repair = 2
pass # repair = 2
# Set crash detection file
save_admin(1, TERM_FLAG_FILE)
#save_admin(1, TERM_FLAG_FILE)
###
### Initialize threads
@@ -369,7 +370,11 @@ def halt():
pass
## Save State ##
save_state(flag=True)
try:
save_state(flag=True)
except:
logging.error('Fatal error at saving state', exc_info=True)
# The Scheduler cannot be stopped when the stop was scheduled.
# Since all warm-restarts have been removed, it's not longer
@@ -453,9 +458,9 @@ def save_state(flag=False):
Bookmarks.do.save()
DirScanner.do.save()
PostProcessor.do.save()
if flag:
# Remove crash detector
load_admin(TERM_FLAG_FILE, remove=True)
#if flag:
# # Remove crash detector
# load_admin(TERM_FLAG_FILE, remove=True)
def pause_all():
""" Pause all activities than cause disk access
@@ -608,33 +613,33 @@ def system_shutdown():
time.sleep(1.0)
if sabnzbd.WIN32:
misc.win_shutdown()
powersup.win_shutdown()
elif DARWIN:
misc.osx_shutdown()
powersup.osx_shutdown()
else:
misc.linux_shutdown()
powersup.linux_shutdown()
def system_hibernate():
""" Hibernate system """
logging.info("Performing system hybernation")
if sabnzbd.WIN32:
misc.win_hibernate()
powersup.win_hibernate()
elif DARWIN:
misc.osx_hibernate()
powersup.osx_hibernate()
else:
misc.linux_hibernate()
powersup.linux_hibernate()
def system_standby():
""" Standby system """
logging.info("Performing system standby")
if sabnzbd.WIN32:
misc.win_standby()
powersup.win_standby()
elif DARWIN:
misc.osx_standby()
powersup.osx_standby()
else:
misc.linux_standby()
powersup.linux_standby()
def shutdown_program():
@@ -767,11 +772,16 @@ def save_data(data, _id, path, do_pickle = True, silent=False):
try:
_f = open(path, 'wb')
if do_pickle:
cPickle.dump(data, _f, 2)
pickler = cPickle.Pickler(_f, 2)
pickler.dump(data)
_f.flush()
_f.close()
pickler.clear_memo()
del pickler
else:
_f.write(data)
_f.flush()
_f.close()
_f.flush()
_f.close()
except:
logging.error(Ta('Saving %s failed'), path)
logging.info("Traceback: ", exc_info = True)
@@ -828,13 +838,18 @@ def save_admin(data, _id, do_pickle=True):
logging.info("Saving data for %s in %s", _id, path)
try:
f = open(path, 'wb')
_f = open(path, 'wb')
if do_pickle:
cPickle.dump(data, f, 2)
pickler = cPickle.Pickler(_f, 2)
pickler.dump(data)
_f.flush()
_f.close()
pickler.clear_memo()
del pickler
else:
f.write(data)
f.flush()
f.close()
_f.write(data)
_f.flush()
_f.close()
except:
logging.error(Ta('Saving %s failed'), path)
logging.info("Traceback: ", exc_info = True)

View File

@@ -45,7 +45,7 @@ from sabnzbd.utils.rsslib import RSS, Item
from sabnzbd.utils.json import JsonWriter
from sabnzbd.utils.pathbrowser import folders_at_path
from sabnzbd.misc import loadavg, to_units, diskfree, disktotal, get_ext, \
get_filename, int_conv, globber, time_format
get_filename, int_conv, globber, time_format, remove_all
from sabnzbd.encoding import xml_name, unicoder, special_fixer, platform_encode
from sabnzbd.postproc import PostProcessor
from sabnzbd.articlecache import ArticleCache
@@ -70,6 +70,13 @@ _MSG_NO_SUCH_CONFIG = 'Config item does not exist'
_MSG_BAD_SERVER_PARMS = 'Incorrect server settings'
#------------------------------------------------------------------------------
# For Windows: determine executable extensions
if os.name == 'nt':
PATHEXT = os.environ.get('PATHEXT', '').lower().split(';')
else:
PATHEXT = []
#------------------------------------------------------------------------------
def api_handler(kwargs):
""" API Dispatcher
@@ -393,15 +400,17 @@ def _api_history(name, output, kwargs):
if name == 'delete':
special = value.lower()
del_files = bool(int_conv(kwargs.get('del_files')))
if special in ('all', 'failed', 'completed'):
history_db = cherrypy.thread_data.history_db
if value in ('all', 'failed'):
if special in ('all', 'failed'):
if del_files:
del_job_files(history_db.get_failed_paths())
history_db.remove_failed()
if value in ('all', 'completed'):
if special in ('all', 'completed'):
history_db.remove_completed()
return report(output)
elif value:
del_files = bool(int_conv(kwargs.get('del_files')))
jobs = value.split(',')
for job in jobs:
del_hist_job(job, del_files)
@@ -1031,6 +1040,8 @@ def build_queue(web_dir=None, root=None, verbose=False, prim=True, verbose_list=
slot['status'] = "%s" % (status)
if priority == TOP_PRIORITY:
slot['priority'] = 'Force'
elif priority == REPAIR_PRIORITY:
slot['priority'] = 'Repair'
elif priority == HIGH_PRIORITY:
slot['priority'] = 'High'
elif priority == LOW_PRIORITY:
@@ -1367,17 +1378,29 @@ def retry_job(job, new_nzb):
return False
#------------------------------------------------------------------------------
def del_job_files(job_paths):
""" Remove files of each path in the list """
for path in job_paths:
if path and path.lower().startswith(cfg.download_dir.get_path().lower()):
remove_all(path, recursive=True)
#------------------------------------------------------------------------------
def del_hist_job(job, del_files):
""" Remove history element """
if job:
history_db = cherrypy.thread_data.history_db
path = history_db.get_path(job)
PostProcessor.do.delete(job, del_files=del_files)
history_db.remove_history(job)
path = PostProcessor.do.get_path(job)
if path:
PostProcessor.do.delete(job, del_files=del_files)
else:
history_db = cherrypy.thread_data.history_db
path = history_db.get_path(job)
PostProcessor.do.delete(job, del_files=del_files)
history_db.remove_history(job)
if path and del_files and path.lower().startswith(cfg.download_dir.get_path().lower()):
nzbstuff.clean_folder(os.path.join(path, JOB_ADMIN))
nzbstuff.clean_folder(path)
remove_all(path, recursive=True)
return True
#------------------------------------------------------------------------------
@@ -1393,7 +1416,7 @@ def Tspec(txt):
_SKIN_CACHE = {} # Stores pre-translated acronyms
# This special is to be used in interface.py for template processing
# to be paased for the $T function: so { ..., 'T' : Ttemplate, ...}
# to be passed for the $T function: so { ..., 'T' : Ttemplate, ...}
def Ttemplate(txt):
""" Translation function for Skin texts
"""
@@ -1506,10 +1529,6 @@ def build_header(prim):
#------------------------------------------------------------------------------
def get_history_size():
history_db = cherrypy.thread_data.history_db
bytes, month, week = history_db.get_history_size()
return (format_bytes(bytes), format_bytes(month), format_bytes(week))
def build_history(start=None, limit=None, verbose=False, verbose_list=None, search=None, failed_only=0):
@@ -1756,7 +1775,8 @@ def list_scripts(default=False):
if path and os.access(path, os.R_OK):
for script in globber(path):
if os.path.isfile(script):
if (sabnzbd.WIN32 and not (win32api.GetFileAttributes(script) & win32file.FILE_ATTRIBUTE_HIDDEN)) or \
if (sabnzbd.WIN32 and os.path.splitext(script)[1].lower() in PATHEXT and \
not (win32api.GetFileAttributes(script) & win32file.FILE_ATTRIBUTE_HIDDEN)) or \
(not sabnzbd.WIN32 and os.access(script, os.X_OK) and not os.path.basename(script).startswith('.')):
lst.append(os.path.basename(script))
lst.insert(0, 'None')

View File

@@ -91,11 +91,13 @@ class Assembler(Thread):
logging.error(Ta('Disk full! Forcing Pause'))
else:
logging.error(Ta('Disk error on creating file %s'), latin1(filepath))
sabnzbd.downloader.pause_downloader()
# Pause without saving
sabnzbd.downloader.Downloader.do.pause(save=False)
except:
logging.error('Fatal error in Assembler', exc_info = True)
break
nzf.remove_admin()
setname = nzf.setname
if nzf.is_par2 and (nzo.md5packs.get(setname) is None):
pack = GetMD5Hashes(filepath)

View File

@@ -35,8 +35,8 @@ from sabnzbd.config import OptionBool, OptionNumber, OptionPassword, \
#
RE_VAL = re.compile('[^@ ]+@[^.@ ]+\.[^.@ ]')
def validate_email(value):
global email_endjob, email_full
if email_endjob() or email_full():
global email_endjob, email_full, email_rss
if email_endjob() or email_full() or email_rss():
if isinstance(value, list):
values = value
else:
@@ -49,8 +49,8 @@ def validate_email(value):
def validate_server(value):
""" Check if server non-empty"""
global email_endjob, email_full
if value == '' and (email_endjob() or email_full()):
global email_endjob, email_full, email_rss
if value == '' and (email_endjob() or email_full() or email_rss()):
return T('Server address required'), None
else:
return None, value
@@ -97,6 +97,7 @@ nice = OptionStr('misc', 'nice', '', validation=no_nonsense)
ionice = OptionStr('misc', 'ionice', '', validation=no_nonsense)
ignore_wrong_unrar = OptionBool('misc', 'ignore_wrong_unrar', False)
par2_multicore = OptionBool('misc', 'par2_multicore', True)
allow_64bit_tools = OptionBool('misc', 'allow_64bit_tools', True)
allow_streaming = OptionBool('misc', 'allow_streaming', False)
newzbin_username = OptionStr('newzbin', 'username')
@@ -105,7 +106,7 @@ newzbin_bookmarks = OptionBool('newzbin', 'bookmarks', False)
newzbin_unbookmark = OptionBool('newzbin', 'unbookmark', True)
bookmark_rate = OptionNumber('newzbin', 'bookmark_rate', 60, minval=15, maxval=24*60)
top_only = OptionBool('misc', 'top_only', True)
top_only = OptionBool('misc', 'top_only', False)
autodisconnect = OptionBool('misc', 'auto_disconnect', True)
queue_complete = OptionStr('misc', 'queue_complete')
queue_complete_pers = OptionBool('misc', 'queue_complete_pers', False)

View File

@@ -186,30 +186,26 @@ class OptionDir(Option):
""" Set new root, is assumed to be valid """
self.__root = root
def set(self, value):
def set(self, value, create=False):
""" Set new dir value, validate and create if needed
Return None when directory is accepted
Return error-string when not accepted, value will not be changed
'create' means try to create (but don't set permanent create flag)
"""
error = None
if value != None and value != self.get():
if value != None and (create or value != self.get()):
value = value.strip()
if self.__validation:
error, value = self.__validation(self.__root, value, self._Option__default_val)
if not error:
if value and self.__create:
if value and (self.__create or create):
res, path = sabnzbd.misc.create_real_path(self.ident()[1], self.__root, value, self.__apply_umask)
if not res:
error = "Cannot create %s folder %s" % (self.ident()[1], path)
error = Ta("Cannot create %s folder %s") % (self.ident()[1], path)
if not error:
self._Option__set(value)
return error
def set_create(self):
""" Enable auto-creation and create now """
self.__create = True
self.get_path()
class OptionList(Option):
""" List option class """
@@ -318,6 +314,8 @@ def delete_from_database(section, keyword):
""" Remove section/keyword from INI database """
global database, CFG, modified
del database[section][keyword]
if section == 'servers' and '[' in keyword:
keyword = keyword.replace('[', '{').replace(']', '}')
try:
del CFG[section][keyword]
except KeyError:

View File

@@ -104,6 +104,7 @@ MIN_DECODE_QUEUE = 5
MAX_DECODE_QUEUE = 10
MAX_WARNINGS = 20
REPAIR_PRIORITY = 3
TOP_PRIORITY = 2
HIGH_PRIORITY = 1
NORMAL_PRIORITY = 0

View File

@@ -143,6 +143,14 @@ class HistoryDB(object):
def remove_completed(self):
return self.execute("""DELETE FROM history WHERE status = 'Completed'""", save=True)
def get_failed_paths(self):
""" Return list of all storage paths of failed jobs (may contain non-existing or empty paths) """
fetch_ok = self.execute("""SELECT path FROM history WHERE status = 'Failed'""")
if fetch_ok:
return [item.get('path') for item in self.c.fetchall()]
else:
return []
def remove_failed(self):
return self.execute("""DELETE FROM history WHERE status = 'Failed'""", save=True)

View File

@@ -759,7 +759,7 @@ def clues_login(text):
""" Check for any "failed login" clues in the response code
"""
text = text.lower()
for clue in ('username', 'password', 'invalid', 'authen'):
for clue in ('username', 'password', 'invalid', 'authen', 'access denied'):
if clue in text:
return True
return False

View File

@@ -33,6 +33,9 @@ from sabnzbd.misc import to_units, split_host, time_format
from sabnzbd.encoding import EmailFilter, latin1
import sabnzbd.cfg as cfg
def errormsg(msg):
logging.error(latin1(msg))
return msg
################################################################################
# EMAIL_SEND
@@ -41,9 +44,6 @@ import sabnzbd.cfg as cfg
################################################################################
def send(message, recipient):
""" Send message if message non-empty and email-parms are set """
def errormsg(msg):
logging.error(latin1(msg))
return msg
if not message.strip('\n\r\t '):
return "Skipped empty message"
@@ -99,7 +99,7 @@ def send(message, recipient):
return errormsg(T('Failed to authenticate to mail server'))
try:
mailconn.sendmail(cfg.email_from(), cfg.email_to(), message)
mailconn.sendmail(cfg.email_from(), recipient, message)
msg = None
except smtplib.SMTPHeloError:
msg = errormsg('The server didn\'t reply properly to the helo greeting.')
@@ -160,22 +160,30 @@ def send_with_template(prefix, parm):
else:
lst = [os.path.join(path, '%s-en.tmpl' % prefix)]
ret = T('No email templates found')
sent = False
for temp in lst:
if os.access(temp, os.R_OK):
source = _decode_file(temp)
if source:
for recipient in cfg.email_to():
parm['to'] = recipient
message = Template(source=source,
searchList=[parm],
filter=EmailFilter,
compilerSettings={'directiveStartToken': '<!--#',
'directiveEndToken': '#-->'})
ret = send(message.respond(), recipient)
del message
sent = True
if len(cfg.email_to()):
for recipient in cfg.email_to():
parm['to'] = recipient
message = Template(source=source,
searchList=[parm],
filter=EmailFilter,
compilerSettings={'directiveStartToken': '<!--#',
'directiveEndToken': '#-->'})
ret = send(message.respond(), recipient)
del message
else:
ret = T('No recipients given, no email sent')
else:
ret = T('Invalid encoding of email template %s') % temp
errormsg(ret)
if not sent:
ret = T('No email templates found')
errormsg(ret)
return ret

View File

@@ -36,7 +36,8 @@ from Cheetah.Template import Template
import sabnzbd.emailer as emailer
from sabnzbd.misc import real_path, to_units, \
diskfree, sanitize_foldername, time_format, HAVE_AMPM, \
cat_to_opts, int_conv, panic_old_queue, globber, clean_folder
cat_to_opts, int_conv, globber, remove_all
from sabnzbd.panic import panic_old_queue
from sabnzbd.newswrapper import GetServerParms
from sabnzbd.newzbin import Bookmarks
from sabnzbd.bpsmeter import BPSMeter
@@ -56,7 +57,7 @@ from sabnzbd.lang import list_languages, set_language
from sabnzbd.api import list_scripts, list_cats, del_from_section, \
api_handler, build_queue, rss_qstatus, \
retry_job, build_header, build_history, \
retry_job, build_header, build_history, del_job_files, \
format_bytes, calc_age, std_time, report, del_hist_job, Ttemplate
#------------------------------------------------------------------------------
@@ -913,7 +914,10 @@ class HistoryPage(object):
def purge_failed(self, **kwargs):
msg = check_session(kwargs)
if msg: return msg
del_files = bool(int_conv(kwargs.get('del_files')))
history_db = cherrypy.thread_data.history_db
if del_files:
del_job_files(history_db.get_failed_paths())
history_db.remove_failed()
raise queueRaiser(self.__root, kwargs)
@@ -1056,8 +1060,7 @@ def orphan_delete(kwargs):
path = kwargs.get('name')
if path:
path = os.path.join(cfg.download_dir.get_path(), path)
clean_folder(os.path.join(path, JOB_ADMIN))
clean_folder(path)
remove_all(path, recursive=True)
def orphan_add(kwargs):
path = kwargs.get('name')
@@ -1104,12 +1107,14 @@ class ConfigDirectories(object):
msg = check_session(kwargs)
if msg: return msg
cfg.complete_dir.set_create()
for kw in LIST_DIRPAGE:
value = kwargs.get(kw)
if value != None:
value = platform_encode(value)
msg = config.get_config('misc', kw).set(value)
if kw == 'complete_dir':
msg = config.get_config('misc', kw).set(value, create=True)
else:
msg = config.get_config('misc', kw).set(value)
if msg:
return badParameterResponse(msg)
@@ -1560,6 +1565,8 @@ class ConfigRss(object):
self.__refresh_ignore = False
msg = sabnzbd.rss.run_feed(active_feed, download=self.__refresh_download, force=self.__refresh_force, \
ignoreFirst=self.__refresh_ignore, readout=readout)
if readout:
sabnzbd.rss.save()
self.__refresh_readout = None
conf['error'] = msg
@@ -1681,6 +1688,7 @@ class ConfigRss(object):
kwargs['section'] = 'rss'
kwargs['keyword'] = kwargs.get('feed')
del_from_section(kwargs)
sabnzbd.rss.clear_feed(kwargs.get('feed'))
raise dcRaiser(self.__root, kwargs)
@cherrypy.expose
@@ -2038,7 +2046,10 @@ class ConfigCats(object):
name = newname.lower()
if kwargs.get('dir'):
kwargs['dir'] = platform_encode(kwargs['dir'])
config.ConfigCat(name, kwargs)
folder = config.ConfigCat(name, kwargs).dir
msg = folder.set(folder(), create=True)
if msg:
return badParameterResponse(msg)
config.save_config()
raise dcRaiser(self.__root, kwargs)
@@ -2336,15 +2347,15 @@ def ShowOK(url):
def GetRssLog(feed):
def make_item(job):
url = job.get('url', '')
title = job.get('title', '')
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)
else:
title = xml_name(title)
title = title
if sabnzbd.rss.special_rss_site(url):
nzbname = ""
else:
nzbname = sanitize_foldername(xml_name(title))
nzbname = xml_name(sanitize_foldername(job.get('title', '')))
return url, \
title, \
'*' * int(job.get('status', '').endswith('*')), \

View File

@@ -24,8 +24,6 @@ import sys
import logging
import urllib
import re
import webbrowser
import tempfile
import shutil
import threading
import subprocess
@@ -40,23 +38,10 @@ import sabnzbd.config as config
import sabnzbd.cfg as cfg
from sabnzbd.encoding import unicoder, latin1
if sabnzbd.FOUNDATION:
import Foundation
RE_VERSION = re.compile('(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)(\d*)')
RE_UNITS = re.compile('(\d+\.*\d*)\s*([KMGTP]{0,1})', re.I)
TAB_UNITS = ('', 'K', 'M', 'G', 'T', 'P')
PANIC_NONE = 0
PANIC_PORT = 1
PANIC_TEMPL = 2
PANIC_QUEUE = 3
PANIC_FWALL = 4
PANIC_OTHER = 5
PANIC_XPORT = 6
PANIC_SQLITE = 7
PANIC_HOST = 8
# Check if strings are defined for AM and PM
HAVE_AMPM = bool(time.strftime('%p', time.localtime()))
@@ -227,7 +212,7 @@ def sanitize_filename(name):
return name + ext
FL_ILLEGAL = CH_ILLEGAL + ':\x92"'
FL_LEGAL = CH_LEGAL + ";''"
FL_LEGAL = CH_LEGAL + "-''"
uFL_ILLEGAL = FL_ILLEGAL.decode('latin-1')
uFL_LEGAL = FL_LEGAL.decode('latin-1')
@@ -482,237 +467,6 @@ def set_serv_parms(service, args):
################################################################################
# Launch a browser for various purposes
# including panic messages
#
################################################################################
def MSG_BAD_NEWS():
return r'''
<html>
<head>
<title>''' + Ta('Problem with') + ''' %s %s</title>
</head>
<body>
<h1><font color="#0000FF"> %s %s</font></h1>
<p align="center">&nbsp;</p>
<p align="center"><font size="5">
<blockquote>
%s
</blockquote>
<br>%s<br>
</body>
</html>
'''
def MSG_BAD_FWALL():
return Ta(r'''
SABnzbd is not compatible with some software firewalls.<br>
%s<br>
Sorry, but we cannot solve this incompatibility right now.<br>
Please file a complaint at your firewall supplier.<br>
<br>
''')
def MSG_BAD_PORT():
return Ta(r'''
SABnzbd needs a free tcp/ip port for its internal web server.<br>
Port %s on %s was tried , but it is not available.<br>
Some other software uses the port or SABnzbd is already running.<br>
<br>
Please restart SABnzbd with a different port number.''') + \
'''<br>
<br>
%s<br>
&nbsp;&nbsp;&nbsp;&nbsp;%s --server %s:%s<br>
<br>''' + \
Ta(r'If you get this error message again, please try a different number.<br>')
def MSG_ILL_PORT():
return Ta(r'''
SABnzbd needs a free tcp/ip port for its internal web server.<br>
Port %s on %s was tried , but the account used for SABnzbd has no permission to use it.<br>
On OSX and Linux systems, normal users must use ports above 1023.<br>
<br>
Please restart SABnzbd with a different port number.''') + \
'''<br>
<br>
%s<br>
&nbsp;&nbsp;&nbsp;&nbsp;%s --server %s:%s<br>
<br>''' + \
Ta(r'If you get this error message again, please try a different number.<br>')
def MSG_BAD_HOST():
return Ta(r'''
SABnzbd needs a valid host address for its internal web server.<br>
You have specified an invalid address.<br>
Safe values are <b>localhost</b> and <b>0.0.0.0</b><br>
<br>
Please restart SABnzbd with a proper host address.''') + \
'''<br>
<br>
%s<br>
&nbsp;&nbsp;&nbsp;&nbsp;%s --server %s:%s<br>
<br>
'''
def MSG_BAD_QUEUE():
return Ta(r'''
SABnzbd detected saved data from an other SABnzbd version<br>
but cannot re-use the data of the other program.<br><br>
You may want to finish your queue first with the other program.<br><br>
After that, start this program with the "--clean" option.<br>
This will erase the current queue and history!<br>
SABnzbd read the file "%s".''') + \
'''<br>
<br>
%s<br>
&nbsp;&nbsp;&nbsp;&nbsp;%s --clean<br>
<br>
'''
def MSG_BAD_TEMPL():
return Ta(r'''
SABnzbd cannot find its web interface files in %s.<br>
Please install the program again.<br>
<br>
''')
def MSG_OTHER():
return Ta('SABnzbd detected a fatal error:') + '<br>%s<br><br>%s<br>'
def MSG_OLD_QUEUE():
return Ta(r'''
SABnzbd detected a Queue and History from an older (0.4.x) release.<br><br>
Both queue and history will be ignored and may get lost!<br><br>
You may choose to stop SABnzbd and finish the queue with the older program.<br><br>
Click OK to proceed to SABnzbd''') + \
('''<br><br><FORM><input type="button" onclick="this.form.action='/.'; this.form.submit(); return false;" value="%s"/></FORM>''' % Ta('OK'))
def MSG_SQLITE():
return Ta(r'''
SABnzbd detected that the file sqlite3.dll is missing.<br><br>
Some poorly designed virus-scanners remove this file.<br>
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.<br>
<br>
''')
def panic_message(panic, a=None, b=None):
"""Create the panic message from templates
"""
if sabnzbd.WIN32:
os_str = Ta('Press Startkey+R and type the line (example):')
prog_path = '"%s"' % sabnzbd.MY_FULLNAME
else:
os_str = Ta('Open a Terminal window and type the line (example):')
prog_path = sabnzbd.MY_FULLNAME
if panic == PANIC_PORT:
newport = int(b) + 1
newport = "%s" % newport
msg = MSG_BAD_PORT() % (b, a, os_str, prog_path, a, newport)
elif panic == PANIC_XPORT:
if int(b) < 1023:
newport = 1024
else:
newport = int(b) + 1
newport = "%s" % newport
msg = MSG_ILL_PORT() % (b, a, os_str, prog_path, a, newport)
elif panic == PANIC_TEMPL:
msg = MSG_BAD_TEMPL() % a
elif panic == PANIC_QUEUE:
msg = MSG_BAD_QUEUE() % (a, os_str, prog_path)
elif panic == PANIC_FWALL:
if a:
msg = MSG_BAD_FWALL() % Ta('It is likely that you are using ZoneAlarm on Vista.<br>')
else:
msg = MSG_BAD_FWALL() % "<br>"
elif panic == PANIC_SQLITE:
msg = MSG_SQLITE()
elif panic == PANIC_HOST:
msg = MSG_BAD_HOST() % (os_str, prog_path, 'localhost', b)
else:
msg = MSG_OTHER() % (a, b)
msg = MSG_BAD_NEWS() % (sabnzbd.MY_NAME, sabnzbd.__version__, sabnzbd.MY_NAME, sabnzbd.__version__,
msg, Ta('Program did not start!'))
if sabnzbd.WIN_SERVICE:
sabnzbd.WIN_SERVICE.ErrLogger('Panic exit', msg)
if (not cfg.autobrowser()) or sabnzbd.DAEMON:
return
msgfile, url = tempfile.mkstemp(suffix='.html')
os.write(msgfile, msg)
os.close(msgfile)
return url
def panic_fwall(vista):
launch_a_browser(panic_message(PANIC_FWALL, vista))
def panic_port(host, port):
launch_a_browser(panic_message(PANIC_PORT, host, port))
def panic_host(host, port):
launch_a_browser(panic_message(PANIC_HOST, host, port))
def panic_xport(host, port):
launch_a_browser(panic_message(PANIC_XPORT, host, port))
logging.error(Ta('You have no permisson to use port %s'), port)
def panic_queue(name):
launch_a_browser(panic_message(PANIC_QUEUE, name, 0))
def panic_tmpl(name):
launch_a_browser(panic_message(PANIC_TEMPL, name, 0))
def panic_sqlite(name):
launch_a_browser(panic_message(PANIC_SQLITE, name, 0))
def panic_old_queue():
msg = MSG_OLD_QUEUE()
return MSG_BAD_NEWS() % (sabnzbd.MY_NAME, sabnzbd.__version__, sabnzbd.MY_NAME, sabnzbd.__version__, msg, '')
def panic(reason, remedy=""):
print "\n%s:\n %s\n%s" % (Ta('Fatal error'), reason, remedy)
launch_a_browser(panic_message(PANIC_OTHER, reason, remedy))
def launch_a_browser(url, force=False):
"""Launch a browser pointing to the URL
"""
if not force and not cfg.autobrowser() or sabnzbd.DAEMON:
return
if cfg.enable_https() and not cfg.https_port.get_int():
# Must use https, because http is not available
url = url.replace('http:', 'https:')
logging.info("Lauching browser with %s", url)
try:
webbrowser.open(url, 2, 1)
except:
logging.warning(Ta('Cannot launch the browser, probably not found'))
logging.info("Traceback: ", exc_info = True)
def error_page_401(status, message, traceback, version):
""" Custom handler for 401 error """
title = T('Access denied')
body = T('Error %s: You need to provide a valid username and password.') % status
return r'''
<html>
<head>
<title>%s</title>
</head>
<body>
<br/><br/>
<font color="#0000FF">%s</font>
</body>
</html>
''' % (title, body)
@@ -888,16 +642,6 @@ def exit_sab(value):
sys.exit(value)
#------------------------------------------------------------------------------
def notify(notificationName, message):
""" Send a notification to the OS (OSX-only) """
if sabnzbd.FOUNDATION:
pool = Foundation.NSAutoreleasePool.alloc().init()
nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
nc.postNotificationName_object_(notificationName, message)
del pool
#------------------------------------------------------------------------------
def split_host(srv):
""" Split host:port notation, allowing for IPV6 """
@@ -1140,12 +884,9 @@ def on_cleanup_list(filename, skip_nzb=False):
"""
lst = cfg.cleanup_list()
if lst:
ext = os.path.splitext(filename)[1].strip().strip('.')
if sabnzbd.WIN32:
ext = ext.lower()
ext = os.path.splitext(filename)[1].strip().strip('.').lower()
for k in lst:
item = k.strip().strip('.')
item = k.strip().strip('.').lower()
if item == ext and not (skip_nzb and item == 'nzb'):
return True
return False
@@ -1221,34 +962,9 @@ def int_conv(value):
#------------------------------------------------------------------------------
# Diskfree
try:
os.statvfs
import statvfs
# posix diskfree
def diskfree(_dir):
""" Return amount of free diskspace in GBytes
"""
try:
s = os.statvfs(_dir)
return (s[statvfs.F_BAVAIL] * s[statvfs.F_FRSIZE]) / GIGI
except OSError:
return 0.0
def disktotal(_dir):
""" Return amount of total diskspace in GBytes
"""
try:
s = os.statvfs(_dir)
return (s[statvfs.F_BLOCKS] * s[statvfs.F_FRSIZE]) / GIGI
except OSError:
return 0.0
except AttributeError:
try:
import win32api
except ImportError:
pass
if sabnzbd.WIN32:
# windows diskfree
import win32api
def diskfree(_dir):
""" Return amount of free diskspace in GBytes
"""
@@ -1265,6 +981,37 @@ except AttributeError:
return disk_size / GIGI
except:
return 0.0
else:
try:
os.statvfs
# posix diskfree
def diskfree(_dir):
""" Return amount of free diskspace in GBytes
"""
try:
s = os.statvfs(_dir)
if s.f_bavail < 0:
return float(sys.maxint) * float(s.f_frsize) / GIGI
else:
return float(s.f_bavail) * float(s.f_frsize) / GIGI
except OSError:
return 0.0
def disktotal(_dir):
""" Return amount of total diskspace in GBytes
"""
try:
s = os.statvfs(_dir)
if s.f_blocks < 0:
return float(sys.maxint) * float(s.f_frsize) / GIGI
else:
return float(s.f_blocks) * float(s.f_frsize) / GIGI
except OSError:
return 0.0
except ImportError:
def diskfree(_dir):
return 10.0
def disktotal(_dir):
return 20.0
def create_https_certificates(ssl_cert, ssl_key):
@@ -1355,208 +1102,6 @@ def ip_extract():
return ips
#------------------------------------------------------------------------------
# Power management for Windows
def win_hibernate():
""" Hibernate Windows system, returns after wakeup
"""
try:
subprocess.Popen("rundll32 powrprof.dll,SetSuspendState Hibernate")
time.sleep(10)
except:
logging.error(Ta('Failed to hibernate system'))
logging.info("Traceback: ", exc_info = True)
def win_standby():
""" Standby Windows system, returns after wakeup
"""
try:
subprocess.Popen("rundll32 powrprof.dll,SetSuspendState Standby")
time.sleep(10)
except:
logging.error(Ta('Failed to standby system'))
logging.info("Traceback: ", exc_info = True)
def win_shutdown():
""" Shutdown Windows system, never returns
"""
try:
import win32security
import win32api
import ntsecuritycon
flags = ntsecuritycon.TOKEN_ADJUST_PRIVILEGES | ntsecuritycon.TOKEN_QUERY
htoken = win32security.OpenProcessToken(win32api.GetCurrentProcess(), flags)
id_ = win32security.LookupPrivilegeValue(None, ntsecuritycon.SE_SHUTDOWN_NAME)
newPrivileges = [(id_, ntsecuritycon.SE_PRIVILEGE_ENABLED)]
win32security.AdjustTokenPrivileges(htoken, 0, newPrivileges)
win32api.InitiateSystemShutdown("", "", 30, 1, 0)
finally:
os._exit(0)
#------------------------------------------------------------------------------
# Power management for OSX
def osx_shutdown():
""" Shutdown OSX system, never returns
"""
try:
subprocess.call(['osascript', '-e', 'tell app "System Events" to shut down'])
except:
logging.error(Ta('Error while shutting down system'))
logging.info("Traceback: ", exc_info = True)
os._exit(0)
def osx_standby():
""" Make OSX system sleep, returns after wakeup
"""
try:
subprocess.call(['osascript', '-e','tell app "System Events" to sleep'])
time.sleep(10)
except:
logging.error(Ta('Failed to standby system'))
logging.info("Traceback: ", exc_info = True)
def osx_hibernate():
""" Make OSX system sleep, returns after wakeup
"""
osx_standby()
#------------------------------------------------------------------------------
# Power management for linux.
#
# Requires DBus plus either HAL [1] or the more modern ConsoleKit [2] and
# DeviceKit(-power) [3]. HAL will eventually be deprecated but older systems
# might still use it.
# [1] http://people.freedesktop.org/~hughsient/temp/dbus-interface.html
# [2] http://www.freedesktop.org/software/ConsoleKit/doc/ConsoleKit.html
# [3] http://hal.freedesktop.org/docs/DeviceKit-power/
#
# Original code was contributed by Marcel de Vries <marceldevries@phannet.cc>
#
try:
import dbus
HAVE_DBUS = True
except ImportError:
HAVE_DBUS = False
def _get_sessionproxy():
""" Return (proxy-object, interface), (None, None) if not available
"""
name = 'org.freedesktop.PowerManagement'
path = '/org/freedesktop/PowerManagement'
interface = 'org.freedesktop.PowerManagement'
try:
bus = dbus.SessionBus()
return bus.get_object(name, path), interface
except dbus.exceptions.DBusException:
return None, None
def _get_systemproxy(method):
""" Return (proxy-object, interface, pinterface), (None, None, None) if not available
"""
if method == 'ConsoleKit':
name = 'org.freedesktop.ConsoleKit'
path = '/org/freedesktop/ConsoleKit/Manager'
interface = 'org.freedesktop.ConsoleKit.Manager'
pinterface = None
elif method == 'DeviceKit':
name = 'org.freedesktop.DeviceKit.Power'
path = '/org/freedesktop/DeviceKit/Power'
interface = 'org.freedesktop.DeviceKit.Power'
pinterface = 'org.freedesktop.DBus.Properties'
elif method == 'UPower':
name = 'org.freedesktop.UPower'
path = '/org/freedesktop/UPower'
interface = 'org.freedesktop.UPower'
pinterface = 'org.freedesktop.DBus.Properties'
try:
bus = dbus.SystemBus()
return bus.get_object(name, path), interface, pinterface
except dbus.exceptions.DBusException, msg:
logging.info('DBus not reachable (%s)', msg)
return None, None, None
def linux_shutdown():
""" Make Linux system shutdown, never returns
"""
if not HAVE_DBUS: os._exit(0)
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanShutdown():
proxy.Shutdown(dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('ConsoleKit')
if proxy:
if proxy.CanStop(dbus_interface=interface):
try:
proxy.Stop(dbus_interface=interface)
except dbus.exceptions.DBusException, msg:
logging.info('Received a DBus exception %s', latin1(msg))
else:
logging.info('DBus does not support Stop (shutdown)')
os._exit(0)
def linux_hibernate():
""" Make Linux system go into hibernate, returns after wakeup
"""
if not HAVE_DBUS: return
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanHibernate():
proxy.Hibernate(dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('UPower')
if not proxy:
proxy, interface, pinterface = _get_systemproxy('DeviceKit')
if proxy:
if proxy.Get(interface, 'can-hibernate', dbus_interface=pinterface):
try:
proxy.Hibernate(dbus_interface=interface)
except dbus.exceptions.DBusException, msg:
logging.info('Received a DBus exception %s', latin1(msg))
else:
logging.info('DBus does not support Hibernate')
time.sleep(10)
def linux_standby():
""" Make Linux system go into standby, returns after wakeup
"""
if not HAVE_DBUS: return
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanSuspend():
proxy.Suspend(dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('UPower')
if not proxy:
proxy, interface, pinterface = _get_systemproxy('DeviceKit')
if proxy:
if proxy.Get(interface, 'can-suspend', dbus_interface=pinterface):
try:
proxy.Suspend(dbus_interface=interface)
except dbus.exceptions.DBusException, msg:
logging.info('Received a DBus exception %s', latin1(msg))
else:
logging.info('DBus does not support Suspend (standby)')
time.sleep(10)
#------------------------------------------------------------------------------
def renamer(old, new):
@@ -1599,26 +1144,25 @@ def remove_dir(path):
os.rmdir(path)
def remove_all(path, pattern='*'):
""" Remove folder and all its content
def remove_all(path, pattern='*', keep_folder=False, recursive=False):
""" Remove folder and all its content (optionally recursive)
"""
if os.path.exists(path):
for f in globber(path, pattern):
os.remove(f)
try:
os.rmdir(path)
except:
pass
files = globber(path, pattern)
if pattern == '*' and not sabnzbd.WIN32:
files.extend(globber(path, '.*'))
for f in files:
if os.path.isfile(f):
try:
os.remove(f)
except:
logging.info('Cannot remove file %s', f)
elif recursive:
remove_all(f, pattern, False, True)
if not keep_folder:
try:
os.rmdir(path)
except:
logging.info('Cannot remove folder %s', path)
def clean_folder(path, pattern='*'):
""" Remove all files in root of folder, remove folder if empty afterwards """
for file in globber(path, pattern):
try:
os.remove(file)
except:
pass
try:
os.rmdir(path)
except:
pass

View File

@@ -96,7 +96,7 @@ def find_programs(curdir):
sabnzbd.newsunpack.RAR_COMMAND = check(curdir, 'osx/unrar/unrar')
if sabnzbd.WIN32:
if sabnzbd.WIN64:
if sabnzbd.WIN64 and cfg.allow_64bit_tools.get():
sabnzbd.newsunpack.PAR2_COMMAND = check(curdir, 'win/par2/x64/par2.exe')
sabnzbd.newsunpack.RAR_COMMAND = check(curdir, 'win/unrar/x64/UnRAR.exe')
if not sabnzbd.newsunpack.PAR2_COMMAND:
@@ -949,7 +949,7 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False):
extrapars = parfile_nzf.extrapars
logging.info("%s", extrapars)
logging.info("Extra pars = %s", extrapars)
## Look for the smallest par2file
block_table = {}
@@ -964,6 +964,13 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False):
nzo.add_parfile(nzf)
## mark for readd
readd = True
else:
msg = T('Invalid par2 files, cannot verify or repair')
nzo.fail_msg = msg
msg = u'[%s] %s' % (unicoder(setname), msg)
nzo.set_unpack_info('Repair', msg, set=setname)
nzo.status = 'Failed'
elif line.startswith('You need'):
chunks = line.split()

View File

@@ -263,6 +263,13 @@ class NewsWrapper(object):
self.pass_sent = True
self.pass_ok = True
if code == '501' and self.user_sent:
# Server asked for username, we sent empty one,
# but it doesn't accept
code = '481'
self.user_ok = True
self.pass_sent = True
if code == '480':
self.force_login = True
self.connected = False
@@ -271,7 +278,7 @@ class NewsWrapper(object):
self.pass_sent = False
self.pass_ok = False
if code == '400':
if code in ('400', '502'):
raise NNTPPermanentError(self.lines[0])
elif not self.user_sent:
command = 'authinfo user %s\r\n' % (self.server.username)
@@ -280,6 +287,12 @@ class NewsWrapper(object):
elif not self.user_ok:
if code == '381':
self.user_ok = True
elif code == '281':
# No login required
self.user_ok = True
self.pass_sent = True
self.pass_ok = True
self.connected = True
if self.user_ok and not self.pass_sent:
command = 'authinfo pass %s\r\n' % (self.server.password)

View File

@@ -27,13 +27,14 @@ import datetime
import sabnzbd
from sabnzbd.trylist import TryList
from sabnzbd.nzbstuff import NzbObject
from sabnzbd.misc import panic_queue, exit_sab, cat_to_opts, \
from sabnzbd.misc import exit_sab, cat_to_opts, \
get_admin_path, remove_all, globber
from sabnzbd.panic import panic_queue
import sabnzbd.database as database
from sabnzbd.decorators import NZBQUEUE_LOCK, synchronized, synchronized_CV
from sabnzbd.constants import QUEUE_FILE_NAME, QUEUE_VERSION, FUTURE_Q_FOLDER, JOB_ADMIN, \
LOW_PRIORITY, NORMAL_PRIORITY, HIGH_PRIORITY, TOP_PRIORITY, \
PNFO_BYTES_FIELD, PNFO_BYTES_LEFT_FIELD
REPAIR_PRIORITY, PNFO_BYTES_FIELD, PNFO_BYTES_LEFT_FIELD
import sabnzbd.cfg as cfg
from sabnzbd.articlecache import ArticleCache
import sabnzbd.downloader
@@ -57,7 +58,6 @@ class NzbQueue(TryList):
self.__nzo_list = []
self.__nzo_table = {}
self.__auto_sort = cfg.auto_sort()
NzbQueue.do = self
def read_queue(self, repair):
@@ -230,7 +230,7 @@ class NzbQueue(TryList):
future.priority = None
self.set_priority(future.nzo_id, priority)
if self.__auto_sort:
if cfg.auto_sort():
self.sort_by_avg_age()
self.reset_try_list()
@@ -278,8 +278,6 @@ class NzbQueue(TryList):
@synchronized(NZBQUEUE_LOCK)
def add(self, nzo, save=True, quiet=False):
assert isinstance(nzo, NzbObject)
sabnzbd.QUEUECOMPLETEACTION_GO = False
if not nzo.nzo_id:
nzo.nzo_id = sabnzbd.get_new_id('nzo', nzo.workpath, self.__nzo_table)
@@ -297,9 +295,8 @@ class NzbQueue(TryList):
nzo.deleted = False
priority = nzo.priority
self.__nzo_table[nzo.nzo_id] = nzo
if priority == TOP_PRIORITY:
#A top priority item (usually a completed download fetching pars)
#is added to the top of the queue
if priority > HIGH_PRIORITY:
#Top and repair priority items are added to the top of the queue
self.__nzo_list.insert(0, nzo)
elif priority == LOW_PRIORITY:
self.__nzo_list.append(nzo)
@@ -314,9 +311,9 @@ class NzbQueue(TryList):
for position in self.__nzo_list:
if position.priority < priority:
self.__nzo_list.insert(pos, nzo)
added=True
added = True
break
pos+=1
pos += 1
if not added:
#if there are no other items classed as a lower priority
#then it will be added to the bottom of the queue
@@ -330,7 +327,7 @@ class NzbQueue(TryList):
if not (quiet or nzo.status in ('Fetching',)):
osx.sendGrowlMsg(T('NZB added to queue'), nzo.filename, osx.NOTIFICATION['download'])
if self.__auto_sort:
if cfg.auto_sort():
self.sort_by_avg_age()
@synchronized(NZBQUEUE_LOCK)
@@ -688,20 +685,28 @@ class NzbQueue(TryList):
logging.warning(Ta('%s -> Unknown encoding'), filename)
if post_done:
if not self.__nzo_list:
# Close server connections
if cfg.autodisconnect():
sabnzbd.downloader.Downloader.do.disconnect()
# Sets the end-of-queue back on if disabled
# adding an nzb and re-adding for more blocks disables it
if sabnzbd.QUEUECOMPLETEACTION:
sabnzbd.QUEUECOMPLETEACTION_GO = True
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):
""" Return amount of non-paused jobs, optionally with 'grabbing' items
"""
n = 0
for nzo in self.__nzo_list:
# Ignore any items that are paused
if grabs and nzo.status == 'Grabbing':
n += 1
elif nzo.status not in ('Paused', 'Grabbing'):
n += 1
return n
@synchronized(NZBQUEUE_LOCK)
def queue_info(self, for_cli = False):
bytes_left = 0
@@ -778,17 +783,20 @@ def _nzo_size_cmp(nzo1, nzo2):
return cmp(nzo1.bytes, nzo2.bytes)
def sort_queue_function(nzo_list, method, reverse):
ultra_high_priority = [nzo for nzo in nzo_list if nzo.priority == REPAIR_PRIORITY]
super_high_priority = [nzo for nzo in nzo_list if nzo.priority == TOP_PRIORITY]
high_priority = [nzo for nzo in nzo_list if nzo.priority == HIGH_PRIORITY]
normal_priority = [nzo for nzo in nzo_list if nzo.priority == NORMAL_PRIORITY]
low_priority = [nzo for nzo in nzo_list if nzo.priority == LOW_PRIORITY]
ultra_high_priority.sort(cmp=method, reverse=reverse)
super_high_priority.sort(cmp=method, reverse=reverse)
high_priority.sort(cmp=method, reverse=reverse)
normal_priority.sort(cmp=method, reverse=reverse)
low_priority.sort(cmp=method, reverse=reverse)
new_list = super_high_priority
new_list = ultra_high_priority
new_list.extend(super_high_priority)
new_list.extend(high_priority)
new_list.extend(normal_priority)
new_list.extend(low_priority)

View File

@@ -38,7 +38,7 @@ from sabnzbd.constants import sample_match, GIGI, ATTRIB_FILE, JOB_ADMIN, \
DEFAULT_PRIORITY, LOW_PRIORITY, NORMAL_PRIORITY, \
HIGH_PRIORITY, PAUSED_PRIORITY, TOP_PRIORITY, DUP_PRIORITY
from sabnzbd.misc import to_units, cat_to_opts, cat_convert, sanitize_foldername, \
get_unique_path, get_admin_path, remove_all, clean_folder, \
get_unique_path, get_admin_path, remove_all, \
sanitize_filename, globber, sanitize_foldername, int_conv
import sabnzbd.cfg as cfg
from sabnzbd.trylist import TryList
@@ -200,7 +200,7 @@ class NzbFile(TryList):
""" Load the article objects from disk """
logging.debug("Finishing import on %s", self.subject)
article_db = sabnzbd.load_data(self.nzf_id, self.nzo.workpath)
article_db = sabnzbd.load_data(self.nzf_id, self.nzo.workpath, remove=False)
if article_db:
for partnum in article_db:
art_id = article_db[partnum][0]
@@ -271,6 +271,13 @@ class NzbFile(TryList):
""" Get lowest article number of this file """
return min(self.decodetable)
def remove_admin(self):
""" Remove article database from disk (sabnzbd_nzf_<id>)"""
try:
os.remove(os.path.join(self.nzo.workpath, self.nzf_id))
except:
pass
def __getstate__(self):
""" Save to pickle file, translating attributes """
dict_ = {}
@@ -297,7 +304,7 @@ class NzbFile(TryList):
################################################################################
class NzbParser(xml.sax.handler.ContentHandler):
""" Forgiving parser for NZB's """
def __init__ (self, nzo):
def __init__ (self, nzo, remove_samples=False):
self.nzo = nzo
assert isinstance(self.nzo, NzbObject)
self.in_nzb = False
@@ -312,9 +319,10 @@ class NzbParser(xml.sax.handler.ContentHandler):
self.skipped_files = 0
self.nzf_list = []
self.groups = []
self.filter = remove_samples
def startDocument(self):
self.filter = cfg.ignore_samples()
pass
def startElement(self, name, attrs):
if name == 'segment' and self.in_nzb and self.in_file and self.in_segments:
@@ -338,7 +346,7 @@ class NzbParser(xml.sax.handler.ContentHandler):
else:
self.filename = subject.strip()
if self.filter == 2 and RE_SAMPLE.search(subject):
if self.filter and RE_SAMPLE.search(subject):
logging.info('Skipping sample file %s', subject)
else:
self.in_file = True
@@ -635,7 +643,7 @@ class NzbObject(TryList):
if 'A&A)' in nzb:
# Fix needed to compensate for some dumb NZB posters
nzb = nzb.replace('A&A)', 'A&amp;A)')
handler = NzbParser(self)
handler = NzbParser(self, cfg.ignore_samples() == 2 and not reuse)
parser = xml.sax.make_parser()
parser.setFeature(xml.sax.handler.feature_external_ges, 0)
parser.setContentHandler(handler)
@@ -1116,12 +1124,12 @@ class NzbObject(TryList):
if self.new_caching and not self.futuretype:
if keep_basic:
clean_folder(wpath, 'SABnzbd_nz?_*')
clean_folder(wpath, 'SABnzbd_article_*')
remove_all(wpath, 'SABnzbd_nz?_*')
remove_all(wpath, 'SABnzbd_article_*')
else:
clean_folder(wpath)
remove_all(wpath, recursive=True)
if del_files:
clean_folder(self.downpath)
remove_all(self.downpath, recursive=True)
else:
try:
os.rmdir(self.downpath)
@@ -1344,33 +1352,33 @@ def split_filename(name):
def format_time_string(seconds, days=0):
""" Given seconds and days, return formatted day/hour/min/sec string
LACKS I18N !!
"""
def unit(n, single):
if n == 1:
return n, Tx(single)
else:
return n, Tx(single + 's')
try:
seconds = int(seconds)
except:
except ValueError:
seconds = 0
completestr = ''
if days:
completestr += '%s day%s ' % (days, s_returner(days))
completestr += '%s %s ' % unit(days, 'day')
if (seconds/3600) >= 1:
completestr += '%s hour%s ' % (seconds/3600, s_returner((seconds/3600)))
completestr += '%s %s ' % unit(seconds/3600, 'hour')
seconds -= (seconds/3600)*3600
if (seconds/60) >= 1:
completestr += '%s minute%s ' % (seconds/60, s_returner((seconds/60)))
completestr += '%s %s ' % unit(seconds/60, 'minute')
seconds -= (seconds/60)*60
if seconds > 0:
completestr += '%s second%s ' % (seconds, s_returner(seconds))
completestr += '%s %s ' % unit(seconds, 'second')
else:
completestr += '%s %s' % unit(0, 'second')
return completestr.strip()
def s_returner(value):
if value > 1:
return 's'
else:
return ''
RE_PASSWORD1 = re.compile(r'([^/\\]+)[/\\](.+)')
RE_PASSWORD2 = re.compile(r'(.+){{([^{}]+)}}$')

View File

@@ -38,7 +38,8 @@ import sabnzbd
import sabnzbd.cfg
from sabnzbd.constants import *
from sabnzbd.misc import launch_a_browser,get_filename,get_ext,diskfree
from sabnzbd.misc import get_filename, get_ext, diskfree
from sabnzbd.panic import launch_a_browser
from sabnzbd.utils import osx
from sabnzbd.nzbqueue import NzbQueue
@@ -53,7 +54,7 @@ from sabnzbd.api import check_trans
status_icons = {'idle':'../Resources/sab_idle.png','pause':'../Resources/sab_pause.png','clicked':'../Resources/sab_clicked.png'}
start_time = NSDate.date()
debug = 1
debug = 0
class SABnzbdDelegate(NSObject):
@@ -704,22 +705,18 @@ class SABnzbdDelegate(NSObject):
def application_openFiles_(self, nsapp, filenames):
#logging.info('[osx] file open')
#logging.info('[osx] file : %s' % (filenames))
pp = None
script = None
cat = None
priority = None
for name in filenames :
#logging.info('[osx] processing : %s' % (name))
logging.info('[osx] receiving from OSX : %s' % name)
if os.path.exists(name):
fn = get_filename(name)
#logging.info('[osx] filename : %s' % (fn))
if fn:
if get_ext(name) in ('.zip','.rar', '.gz'):
if get_ext(name) in ('.zip', '.rar'):
#logging.info('[osx] archive')
dirscanner.ProcessArchiveFile(fn, name, pp=pp, script=script, cat=cat, priority=priority, keep=True)
elif get_ext(name) in ('.nzb'):
dirscanner.ProcessArchiveFile(fn, name, keep=True)
elif get_ext(name) in ('.nzb', '.gz'):
#logging.info('[osx] nzb')
dirscanner.ProcessSingleFile(fn, name, pp=pp, script=script, cat=cat, priority=priority, keep=True)
dirscanner.ProcessSingleFile(fn, name, keep=True)
#logging.info('opening done')
def applicationShouldTerminate_(self, sender):
@@ -737,3 +734,13 @@ class SABnzbdDelegate(NSObject):
sys.stdout.flush()
return NSTerminateNow
#------------------------------------------------------------------------------
def notify(notificationName, message):
""" Send a notification to the OS (OSX-only) """
if sabnzbd.FOUNDATION:
pool = Foundation.NSAutoreleasePool.alloc().init()
nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
nc.postNotificationName_object_(notificationName, message)
del pool

265
sabnzbd/panic.py Normal file
View File

@@ -0,0 +1,265 @@
#!/usr/bin/python -OO
# Copyright 2008-2011 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
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
sabnzbd.panic - Send panic message to the browser
"""
import os
import logging
import webbrowser
import tempfile
import sabnzbd
import sabnzbd.cfg as cfg
PANIC_NONE = 0
PANIC_PORT = 1
PANIC_TEMPL = 2
PANIC_QUEUE = 3
PANIC_FWALL = 4
PANIC_OTHER = 5
PANIC_XPORT = 6
PANIC_SQLITE = 7
PANIC_HOST = 8
def MSG_BAD_NEWS():
return r'''
<html>
<head>
<title>''' + Ta('Problem with') + ''' %s %s</title>
</head>
<body>
<h1><font color="#0000FF"> %s %s</font></h1>
<p align="center">&nbsp;</p>
<p align="center"><font size="5">
<blockquote>
%s
</blockquote>
<br>%s<br>
</body>
</html>
'''
def MSG_BAD_FWALL():
return Ta(r'''
SABnzbd is not compatible with some software firewalls.<br>
%s<br>
Sorry, but we cannot solve this incompatibility right now.<br>
Please file a complaint at your firewall supplier.<br>
<br>
''')
def MSG_BAD_PORT():
return Ta(r'''
SABnzbd needs a free tcp/ip port for its internal web server.<br>
Port %s on %s was tried , but it is not available.<br>
Some other software uses the port or SABnzbd is already running.<br>
<br>
Please restart SABnzbd with a different port number.''') + \
'''<br>
<br>
%s<br>
&nbsp;&nbsp;&nbsp;&nbsp;%s --server %s:%s<br>
<br>''' + \
Ta(r'If you get this error message again, please try a different number.<br>')
def MSG_ILL_PORT():
return Ta(r'''
SABnzbd needs a free tcp/ip port for its internal web server.<br>
Port %s on %s was tried , but the account used for SABnzbd has no permission to use it.<br>
On OSX and Linux systems, normal users must use ports above 1023.<br>
<br>
Please restart SABnzbd with a different port number.''') + \
'''<br>
<br>
%s<br>
&nbsp;&nbsp;&nbsp;&nbsp;%s --server %s:%s<br>
<br>''' + \
Ta(r'If you get this error message again, please try a different number.<br>')
def MSG_BAD_HOST():
return Ta(r'''
SABnzbd needs a valid host address for its internal web server.<br>
You have specified an invalid address.<br>
Safe values are <b>localhost</b> and <b>0.0.0.0</b><br>
<br>
Please restart SABnzbd with a proper host address.''') + \
'''<br>
<br>
%s<br>
&nbsp;&nbsp;&nbsp;&nbsp;%s --server %s:%s<br>
<br>
'''
def MSG_BAD_QUEUE():
return Ta(r'''
SABnzbd detected saved data from an other SABnzbd version<br>
but cannot re-use the data of the other program.<br><br>
You may want to finish your queue first with the other program.<br><br>
After that, start this program with the "--clean" option.<br>
This will erase the current queue and history!<br>
SABnzbd read the file "%s".''') + \
'''<br>
<br>
%s<br>
&nbsp;&nbsp;&nbsp;&nbsp;%s --clean<br>
<br>
'''
def MSG_BAD_TEMPL():
return Ta(r'''
SABnzbd cannot find its web interface files in %s.<br>
Please install the program again.<br>
<br>
''')
def MSG_OTHER():
return Ta('SABnzbd detected a fatal error:') + '<br>%s<br><br>%s<br>'
def MSG_OLD_QUEUE():
return Ta(r'''
SABnzbd detected a Queue and History from an older (0.4.x) release.<br><br>
Both queue and history will be ignored and may get lost!<br><br>
You may choose to stop SABnzbd and finish the queue with the older program.<br><br>
Click OK to proceed to SABnzbd''') + \
('''<br><br><FORM><input type="button" onclick="this.form.action='/.'; this.form.submit(); return false;" value="%s"/></FORM>''' % Ta('OK'))
def MSG_SQLITE():
return Ta(r'''
SABnzbd detected that the file sqlite3.dll is missing.<br><br>
Some poorly designed virus-scanners remove this file.<br>
Please check your virus-scanner, try to re-install SABnzbd and complain to your virus-scanner vendor.<br>
<br>
''')
def panic_message(panic, a=None, b=None):
"""Create the panic message from templates
"""
if sabnzbd.WIN32:
os_str = Ta('Press Startkey+R and type the line (example):')
prog_path = '"%s"' % sabnzbd.MY_FULLNAME
else:
os_str = Ta('Open a Terminal window and type the line (example):')
prog_path = sabnzbd.MY_FULLNAME
if panic == PANIC_PORT:
newport = int(b) + 1
newport = "%s" % newport
msg = MSG_BAD_PORT() % (b, a, os_str, prog_path, a, newport)
elif panic == PANIC_XPORT:
if int(b) < 1023:
newport = 1024
else:
newport = int(b) + 1
newport = "%s" % newport
msg = MSG_ILL_PORT() % (b, a, os_str, prog_path, a, newport)
elif panic == PANIC_TEMPL:
msg = MSG_BAD_TEMPL() % a
elif panic == PANIC_QUEUE:
msg = MSG_BAD_QUEUE() % (a, os_str, prog_path)
elif panic == PANIC_FWALL:
if a:
msg = MSG_BAD_FWALL() % Ta('It is likely that you are using ZoneAlarm on Vista.<br>')
else:
msg = MSG_BAD_FWALL() % "<br>"
elif panic == PANIC_SQLITE:
msg = MSG_SQLITE()
elif panic == PANIC_HOST:
msg = MSG_BAD_HOST() % (os_str, prog_path, 'localhost', b)
else:
msg = MSG_OTHER() % (a, b)
msg = MSG_BAD_NEWS() % (sabnzbd.MY_NAME, sabnzbd.__version__, sabnzbd.MY_NAME, sabnzbd.__version__,
msg, Ta('Program did not start!'))
if sabnzbd.WIN_SERVICE:
sabnzbd.WIN_SERVICE.ErrLogger('Panic exit', msg)
if (not cfg.autobrowser()) or sabnzbd.DAEMON:
return
msgfile, url = tempfile.mkstemp(suffix='.html')
os.write(msgfile, msg)
os.close(msgfile)
return url
def panic_fwall(vista):
launch_a_browser(panic_message(PANIC_FWALL, vista))
def panic_port(host, port):
launch_a_browser(panic_message(PANIC_PORT, host, port))
def panic_host(host, port):
launch_a_browser(panic_message(PANIC_HOST, host, port))
def panic_xport(host, port):
launch_a_browser(panic_message(PANIC_XPORT, host, port))
logging.error(Ta('You have no permisson to use port %s'), port)
def panic_queue(name):
launch_a_browser(panic_message(PANIC_QUEUE, name, 0))
def panic_tmpl(name):
launch_a_browser(panic_message(PANIC_TEMPL, name, 0))
def panic_sqlite(name):
launch_a_browser(panic_message(PANIC_SQLITE, name, 0))
def panic_old_queue():
msg = MSG_OLD_QUEUE()
return MSG_BAD_NEWS() % (sabnzbd.MY_NAME, sabnzbd.__version__, sabnzbd.MY_NAME, sabnzbd.__version__, msg, '')
def panic(reason, remedy=""):
print "\n%s:\n %s\n%s" % (Ta('Fatal error'), reason, remedy)
launch_a_browser(panic_message(PANIC_OTHER, reason, remedy))
def launch_a_browser(url, force=False):
"""Launch a browser pointing to the URL
"""
if not force and not cfg.autobrowser() or sabnzbd.DAEMON:
return
if cfg.enable_https() and not cfg.https_port.get_int():
# Must use https, because http is not available
url = url.replace('http:', 'https:')
logging.info("Lauching browser with %s", url)
try:
webbrowser.open(url, 2, 1)
except:
logging.warning(Ta('Cannot launch the browser, probably not found'))
logging.info("Traceback: ", exc_info = True)
def error_page_401(status, message, traceback, version):
""" Custom handler for 401 error """
title = T('Access denied')
body = T('Error %s: You need to provide a valid username and password.') % status
return r'''
<html>
<head>
<title>%s</title>
</head>
<body>
<br/><br/>
<font color="#0000FF">%s</font>
</body>
</html>
''' % (title, body)

View File

@@ -34,7 +34,7 @@ from sabnzbd.misc import real_path, get_unique_path, create_dirs, move_to_path,
get_unique_filename, make_script_path, \
on_cleanup_list, renamer, remove_dir, remove_all, globber
from sabnzbd.tvsort import Sorter
from sabnzbd.constants import TOP_PRIORITY, POSTPROC_QUEUE_FILE_NAME, \
from sabnzbd.constants import REPAIR_PRIORITY, POSTPROC_QUEUE_FILE_NAME, \
POSTPROC_QUEUE_VERSION, sample_match, JOB_ADMIN
from sabnzbd.encoding import TRANS, unicoder
from sabnzbd.newzbin import Bookmarks
@@ -88,6 +88,8 @@ class PostProcessor(Thread):
self.history_queue = []
logging.info("Loading postproc queue")
data = sabnzbd.load_admin(POSTPROC_QUEUE_FILE_NAME)
if data is None:
return
try:
version, history_queue = data
if POSTPROC_QUEUE_VERSION != version:
@@ -138,21 +140,39 @@ class PostProcessor(Thread):
""" Return list of NZOs that still need to be processed """
return [nzo for nzo in self.history_queue if nzo.work_name]
def get_path(self, nzo_id):
""" Return download path for given nzo_id or None when not found """
for nzo in self.history_queue:
if nzo.nzo_id == nzo_id:
return nzo.downpath
return None
def run(self):
""" Actual processing """
while 1:
check_eoq = False
while not self.__stop:
self.__busy = False
if self.queue.empty(): handle_empty_queue()
while (not self.__stop) and self.paused:
if self.paused:
time.sleep(5)
continue
## Get a job from the queue, quit on empty job
nzo = self.queue.get()
if not nzo: break
try:
nzo = self.queue.get(timeout=3)
except Queue.Empty:
if check_eoq:
check_eoq = False
handle_empty_queue()
continue
## This job was already deleted.
## Stop job
if not nzo:
continue
## Job was already deleted.
if not nzo.work_name:
check_eoq = True
continue
## Flag NZO as being processed
@@ -161,11 +181,11 @@ class PostProcessor(Thread):
## Pause downloader, if users wants that
if cfg.pause_on_post_processing():
sabnzbd.downloader.Downloader.do.wait_for_postproc()
cfg.complete_dir.set_create()
self.__busy = True
if process_job(nzo):
self.remove(nzo)
check_eoq = True
## Allow download to proceed
sabnzbd.downloader.Downloader.do.resume_from_postproc()
@@ -321,7 +341,11 @@ def process_job(nzo):
cleanup_list(tmp_workdir_complete, True)
## Check if this is an NZB-only download, if so redirect to queue
nzb_list = nzb_redirect(tmp_workdir_complete, nzo.final_name, nzo.pp, script, cat, priority=nzo.priority)
## except when PP was Download-only
if flag_repair:
nzb_list = nzb_redirect(tmp_workdir_complete, nzo.final_name, nzo.pp, script, cat, priority=nzo.priority)
else:
nzb_list = None
if nzb_list:
nzo.set_unpack_info('Download', T('Sent %s to queue') % unicoder(nzb_list))
try:
@@ -456,8 +480,7 @@ def process_job(nzo):
try:
if os.path.exists(workdir):
logging.debug('Removing workdir %s', workdir)
remove_all(os.path.join(workdir, JOB_ADMIN))
remove_dir(workdir)
remove_all(workdir, recursive=True)
except:
logging.error(Ta('Error removing workdir (%s)'), workdir)
logging.info("Traceback: ", exc_info = True)
@@ -497,8 +520,7 @@ def parring(nzo, workdir):
if re_add:
logging.info('Readded %s to queue', filename)
sabnzbd.QUEUECOMPLETEACTION_GO = False
nzo.priority = TOP_PRIORITY
nzo.priority = REPAIR_PRIORITY
sabnzbd.nzbqueue.add_nzo(nzo)
sabnzbd.downloader.Downloader.do.resume_from_postproc()
@@ -575,7 +597,7 @@ def addPrefixes(path, dirprefix):
def handle_empty_queue():
""" Check if empty queue calls for action """
if sabnzbd.QUEUECOMPLETEACTION_GO:
if sabnzbd.nzbqueue.NzbQueue.do.actives() == 0:
sabnzbd.save_state()
logging.info("Queue has finished, launching: %s (%s)", \
sabnzbd.QUEUECOMPLETEACTION, sabnzbd.QUEUECOMPLETEARG)
@@ -584,7 +606,6 @@ def handle_empty_queue():
else:
Thread(target=sabnzbd.QUEUECOMPLETEACTION).start()
sabnzbd.QUEUECOMPLETEACTION_GO = False
sabnzbd.change_queue_complete_action(cfg.queue_complete(), new=False)
@@ -596,15 +617,18 @@ def cleanup_list(wdir, skip_nzb):
files = os.listdir(wdir)
except:
files = ()
for file_ in files:
if on_cleanup_list(file_, skip_nzb):
path = os.path.join(wdir, file_)
try:
logging.info("Removing unwanted file %s", path)
os.remove(path)
except:
logging.error(Ta('Removing %s failed'), path)
logging.info("Traceback: ", exc_info = True)
for file in files:
path = os.path.join(wdir, file)
if os.path.isdir(path):
cleanup_list(path, skip_nzb)
else:
if on_cleanup_list(file, skip_nzb):
try:
logging.info("Removing unwanted file %s", path)
os.remove(path)
except:
logging.error(Ta('Removing %s failed'), path)
logging.info("Traceback: ", exc_info = True)
def prefix(path, pre):

228
sabnzbd/powersup.py Normal file
View File

@@ -0,0 +1,228 @@
#!/usr/bin/python -OO
# Copyright 2008-2011 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
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
sabnzbd.powersup - System power management support
"""
import os
import subprocess
import logging
import time
from sabnzbd.encoding import latin1
#------------------------------------------------------------------------------
# Power management for Windows
def win_hibernate():
""" Hibernate Windows system, returns after wakeup
"""
try:
subprocess.Popen("rundll32 powrprof.dll,SetSuspendState Hibernate")
time.sleep(10)
except:
logging.error(Ta('Failed to hibernate system'))
logging.info("Traceback: ", exc_info = True)
def win_standby():
""" Standby Windows system, returns after wakeup
"""
try:
subprocess.Popen("rundll32 powrprof.dll,SetSuspendState Standby")
time.sleep(10)
except:
logging.error(Ta('Failed to standby system'))
logging.info("Traceback: ", exc_info = True)
def win_shutdown():
""" Shutdown Windows system, never returns
"""
try:
import win32security
import win32api
import ntsecuritycon
flags = ntsecuritycon.TOKEN_ADJUST_PRIVILEGES | ntsecuritycon.TOKEN_QUERY
htoken = win32security.OpenProcessToken(win32api.GetCurrentProcess(), flags)
id_ = win32security.LookupPrivilegeValue(None, ntsecuritycon.SE_SHUTDOWN_NAME)
newPrivileges = [(id_, ntsecuritycon.SE_PRIVILEGE_ENABLED)]
win32security.AdjustTokenPrivileges(htoken, 0, newPrivileges)
win32api.InitiateSystemShutdown("", "", 30, 1, 0)
finally:
os._exit(0)
#------------------------------------------------------------------------------
# Power management for OSX
def osx_shutdown():
""" Shutdown OSX system, never returns
"""
try:
subprocess.call(['osascript', '-e', 'tell app "System Events" to shut down'])
except:
logging.error(Ta('Error while shutting down system'))
logging.info("Traceback: ", exc_info = True)
os._exit(0)
def osx_standby():
""" Make OSX system sleep, returns after wakeup
"""
try:
subprocess.call(['osascript', '-e','tell app "System Events" to sleep'])
time.sleep(10)
except:
logging.error(Ta('Failed to standby system'))
logging.info("Traceback: ", exc_info = True)
def osx_hibernate():
""" Make OSX system sleep, returns after wakeup
"""
osx_standby()
#------------------------------------------------------------------------------
# Power management for linux.
#
# Requires DBus plus either HAL [1] or the more modern ConsoleKit [2] and
# DeviceKit(-power) [3]. HAL will eventually be deprecated but older systems
# might still use it.
# [1] http://people.freedesktop.org/~hughsient/temp/dbus-interface.html
# [2] http://www.freedesktop.org/software/ConsoleKit/doc/ConsoleKit.html
# [3] http://hal.freedesktop.org/docs/DeviceKit-power/
#
# Original code was contributed by Marcel de Vries <marceldevries@phannet.cc>
#
try:
import dbus
HAVE_DBUS = True
except ImportError:
HAVE_DBUS = False
def _get_sessionproxy():
""" Return (proxy-object, interface), (None, None) if not available
"""
name = 'org.freedesktop.PowerManagement'
path = '/org/freedesktop/PowerManagement'
interface = 'org.freedesktop.PowerManagement'
try:
bus = dbus.SessionBus()
return bus.get_object(name, path), interface
except dbus.exceptions.DBusException:
return None, None
def _get_systemproxy(method):
""" Return (proxy-object, interface, pinterface), (None, None, None) if not available
"""
if method == 'ConsoleKit':
name = 'org.freedesktop.ConsoleKit'
path = '/org/freedesktop/ConsoleKit/Manager'
interface = 'org.freedesktop.ConsoleKit.Manager'
pinterface = None
elif method == 'DeviceKit':
name = 'org.freedesktop.DeviceKit.Power'
path = '/org/freedesktop/DeviceKit/Power'
interface = 'org.freedesktop.DeviceKit.Power'
pinterface = 'org.freedesktop.DBus.Properties'
elif method == 'UPower':
name = 'org.freedesktop.UPower'
path = '/org/freedesktop/UPower'
interface = 'org.freedesktop.UPower'
pinterface = 'org.freedesktop.DBus.Properties'
try:
bus = dbus.SystemBus()
return bus.get_object(name, path), interface, pinterface
except dbus.exceptions.DBusException, msg:
logging.info('DBus not reachable (%s)', msg)
return None, None, None
def linux_shutdown():
""" Make Linux system shutdown, never returns
"""
if not HAVE_DBUS: os._exit(0)
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanShutdown():
proxy.Shutdown(dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('ConsoleKit')
if proxy:
if proxy.CanStop(dbus_interface=interface):
try:
proxy.Stop(dbus_interface=interface)
except dbus.exceptions.DBusException, msg:
logging.info('Received a DBus exception %s', latin1(msg))
else:
logging.info('DBus does not support Stop (shutdown)')
os._exit(0)
def linux_hibernate():
""" Make Linux system go into hibernate, returns after wakeup
"""
if not HAVE_DBUS: return
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanHibernate():
proxy.Hibernate(dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('UPower')
if not proxy:
proxy, interface, pinterface = _get_systemproxy('DeviceKit')
if proxy:
if proxy.Get(interface, 'can-hibernate', dbus_interface=pinterface):
try:
proxy.Hibernate(dbus_interface=interface)
except dbus.exceptions.DBusException, msg:
logging.info('Received a DBus exception %s', latin1(msg))
else:
logging.info('DBus does not support Hibernate')
time.sleep(10)
def linux_standby():
""" Make Linux system go into standby, returns after wakeup
"""
if not HAVE_DBUS: return
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanSuspend():
proxy.Suspend(dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('UPower')
if not proxy:
proxy, interface, pinterface = _get_systemproxy('DeviceKit')
if proxy:
if proxy.Get(interface, 'can-suspend', dbus_interface=pinterface):
try:
proxy.Suspend(dbus_interface=interface)
except dbus.exceptions.DBusException, msg:
logging.info('Received a DBus exception %s', latin1(msg))
else:
logging.info('DBus does not support Suspend (standby)')
time.sleep(10)

View File

@@ -23,6 +23,8 @@ import re
import logging
import time
import threading
import urllib
import os
import sabnzbd
from sabnzbd.constants import *
@@ -125,6 +127,23 @@ def convert_filter(text):
logging.error(Ta('Could not compile regex: %s'), text)
return None
_EXPIRE_SEC = 3*24*3600 # 3 days
def remove_obsolete(jobs, new_jobs):
""" Expire G/B links that are not in new_jobs (mark them 'X')
Expired links older than 3 days are removed from 'jobs'
"""
now = time.time()
limit = now - _EXPIRE_SEC
olds = jobs.keys()
for old in olds:
tm = jobs[old]['time']
if old not in new_jobs:
if jobs[old].get('status', ' ')[0] in ('G', 'B'):
jobs[old]['status'] = 'X'
if jobs[old]['status'] == 'X' and tm < limit:
logging.debug("Purging link %s", old)
del jobs[old]
LOCK = threading.RLock()
class RSSQueue(object):
@@ -140,9 +159,13 @@ class RSSQueue(object):
self.jobs = {}
try:
defined = config.get_rss().keys()
feeds = sabnzbd.load_admin(RSS_FILE_NAME)
if type(feeds) == type({}):
for feed in feeds:
if feed not in defined:
logging.debug('Dropping obsolete data for feed "%s"', feed)
continue
self.jobs[feed] = {}
for link in feeds[feed]:
data = feeds[feed][link]
@@ -168,7 +191,8 @@ class RSSQueue(object):
item = feeds[feed][link]
if not isinstance(item, dict) or not isinstance(item.get('title'), unicode):
raise IndexError
if not item.get('status', ' ')[0] not in ('D', 'G', 'B', 'X'): item['status'] = 'X'
if item.get('status', ' ')[0] not in ('D', 'G', 'B', 'X'):
item['status'] = 'X'
if not isinstance(item.get('url'), unicode): item['url'] = ''
if not check_str(item.get('cat')): item['cat'] = ''
if not check_str(item.get('orgcat')): item['orgcat'] = ''
@@ -182,6 +206,8 @@ class RSSQueue(object):
except (KeyError, IndexError):
logging.info('Incorrect entry in %s detected, discarding %s', RSS_FILE_NAME, item)
remove_obsolete(self.jobs[feed], self.jobs[feed].keys())
except IOError:
logging.debug('Cannot read file %s', RSS_FILE_NAME)
@@ -298,6 +324,12 @@ class RSSQueue(object):
logging.info(msg)
return unicoder(msg)
status = d.get('status', 999)
if status in (401, 402, 403):
msg = Ta('Do not have valid authentication for feed %s') % feed
logging.info(msg)
return unicoder(msg)
entries = d.get('entries')
if 'bozo_exception' in d and not entries:
msg = Ta('Failed to retrieve RSS from %s: %s') % (uri, xml_name(str(d['bozo_exception'])))
@@ -337,12 +369,20 @@ class RSSQueue(object):
title = unicoder(atitle)
if link:
# Make sure there are no spaces in the URL
link = link.replace(' ','')
# Make sure spaces are quoted in the URL
if 'nzbclub.com' in link:
link, path = os.path.split(link.strip())
link = '%s/%s' % (link, urllib.quote(path))
else:
link = link.strip().replace(' ','%20')
newlinks.append(link)
if (link not in jobs) or (jobs[link].get('status', ' ') in ('G', 'B', 'G*', 'B*')):
if link in jobs:
jobstat = jobs[link].get('status', ' ')[0]
else:
jobstat = 'N'
if jobstat in 'NGB' or (jobstat == 'X' and readout):
# Match this title against all filters
logging.debug('Trying title %s', atitle)
result = False
@@ -402,7 +442,7 @@ class RSSQueue(object):
logging.info("Ignoring duplicate job %s", atitle)
continue
else:
priority = DUP_PRIORITY
myPrio = DUP_PRIORITY
act = download and not first
if link in jobs:
@@ -425,25 +465,7 @@ class RSSQueue(object):
if new_downloads and cfg.email_rss() and not force:
emailer.rss_mail(feed, new_downloads)
# If links are in table for more than 1 week, remove
# Flag old D/B links as obsolete, so that they don't show up in Preview
now = time.time()
limit = now - 1*7*24*3600
olds = jobs.keys()
for old in olds:
if old not in newlinks:
if jobs[old].get('status', ' ')[0] in ('G', 'B'):
jobs[old]['status'] = 'X'
try:
tm = float(jobs[old]['time'])
except:
# Fix missing timestamp in older RSS_DATA.SAB file
jobs[old]['time'] = now
tm = now
if tm < limit:
logging.debug("Purging link %s", old)
del jobs[old]
remove_obsolete(jobs, newlinks)
return ''

View File

@@ -42,6 +42,7 @@ SKIN_TEXT = {
'post-Verifying' : TT('Verifying...'), #: PP status
'post-Downloading' : TT('Downloading'), #: Pseudo-PP status, in reality used for Queue-status
'post-Grabbing' : TT('Get NZB'), #: Pseudo-PP status, in reality used for Grabbing status
'post-Checking' : TT('Checking'), #: PP status
'sch-frequency' : TT('Frequency'), #: #: Config->Scheduler
'sch-action' : TT('Action'), #: #: Config->Scheduler
@@ -115,6 +116,7 @@ SKIN_TEXT = {
'cmenu-servers' : TT('Servers'), #: Main menu item
'cmenu-scheduling' : TT('Scheduling'), #: Main menu item
'cmenu-rss' : TT('RSS'), #: Main menu item
'cmenu-emailN' : TT('Notifications'), #: Main menu item
'cmenu-email' : TT('Email'), #: Main menu item
'cmenu-newzbin' : TT('Index Sites'), #: Main menu item
'cmenu-cat' : TT('Categories'), #: Main menu item
@@ -154,6 +156,7 @@ SKIN_TEXT = {
'pp-u' : TT('U'),
'pp-d' : TT('D'),
'pr-force' : TT('Force'),
'pr-repair' : TT('Repair'),
'pr-normal' : TT('Normal'),
'pr-high' : TT('High'),
'pr-low' : TT('Low'),
@@ -194,6 +197,7 @@ SKIN_TEXT = {
'removeNZB-Files' : TT('Remove NZB & Delete Files'), #: Queue page button
'AofB' : TT('of'), #: Queue page, as in "4G *of* 10G"
'missingArt': TT('Missing articles'), #: Caption for missing articles in Queue
'quotum-left' : TT('Quotum left'), #: Remaining quotum (displayed in Queue)
# History page
'purgeHist' : TT('Purge History'), #: History page button
@@ -419,6 +423,17 @@ SKIN_TEXT = {
'swtag-queue' : TT('Queue'),
'swtag-pp' : TT('Post processing'),
'swtag-naming' : TT('Naming'),
'swtag-quotum' : TT('Quotum'),
'opt-quotum_size' : TT('Size'), #: Size of the download quotum
'explain-quotum_size' : TT('How much can be downloaded this month (K/M/G)'),
'opt-quotum_day' : TT('Reset day'), #: Reset day of the download quotum
'explain-quotum_day' : TT('On which day of the month or week (1=Monday) does your ISP reset the quotum? (Optionally with hh:mm)'),
'opt-quotum_resume' : TT('Auto resume'), #: Auto-resume download on the reset day
'explain-quotum_resume' : TT('Should downloading resume after the quotum is reset?'),
'opt-quotum_period' : TT('Quotum period'), #: Does the quotum get reset every day, week or month?
'explain-quotum_period' : TT('Does the quotum get reset each day, week or month?'),
'opt-pre_check' : TT('Check before download'),
'explain-pre_check' : TT('Try to predict successful completion before actual download (slower!)'),
# Config->Server
@@ -485,12 +500,12 @@ SKIN_TEXT = {
'filters' : TT('Filters'), #: Tab title for Config->Feeds
# Config->Email
'configEmail' : TT('Email Notification'),
'emailOptions' : TT('Email Options'),
'configEmail' : TT('Email Notifications'), #: Main Config page
'emailOptions' : TT('Email Options'), #: Section header
'opt-email_endjob' : TT('Email Notification On Job Completion'),
'email-never' : TT('Never'),
'email-always' : TT('Always'),
'email-errorOnly' : TT('Error-only'),
'email-never' : TT('Never'), #: When to send email
'email-always' : TT('Always'), #: When to send email
'email-errorOnly' : TT('Error-only'), #: When to send email
'opt-email_full' : TT('Disk Full Notifications'),
'explain-email_full' : TT('Send email when disk is full and SABnzbd is paused.'),
'opt-email_rss' : TT('Send RSS notifications'),
@@ -506,6 +521,16 @@ SKIN_TEXT = {
'explain-email_account' : TT('For authenticated email, account name.'),
'opt-email_pwd' : TT('OPTIONAL Account Password'),
'explain-email_pwd' : TT('For authenticated email, password.'),
'growlSettings' : TT('Notifications'), #: Section header
'opt-growl_enable' : TT('Enable Growl'), #: Don't translate "Growl"
'explain-growl_enable' : TT('Send notifications to Growl'), #: Don't translate "Growl"
'opt-growl_server' : TT('Server address'), #: Address of Growl server
'explain-growl_server' : TT('Only use for remote Growl server (host:port)'), #: Don't translate "Growl"
'opt-growl_password' : TT('Server password'), #: Growl server password
'explain-growl_password' : TT('Optional password for Growl server'), #: Don't translate "Growl"
'opt-ntfosd_enable' : TT('Enable NotifyOSD'), #: Don't translate "NotifyOSD"
'explain-ntfosd_enable' : TT('Send notifications to NotifyOSD'), #: Don't translate "NotifyOSD"
'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.'),
@@ -741,6 +766,7 @@ SKIN_TEXT = {
'smpl-downloading' : TT('Downloading'),
'smpl-idle' : TT('Idle'),
'smpl-emailsent' : TT('Email Sent!'),
'smpl-notesent' : TT('Notification Sent!'),
'smpl-saving' : TT('Saving..'),
'smpl-saved' : TT('Saved'),
'smpl-failed' : TT('Failed'),

View File

@@ -524,12 +524,13 @@ class GenericSorter(object):
""" Collect and construct all the values needed for path replacement """
## - Get Year
dirname = self.original_dirname.replace('_', ' ')
RE_YEAR = re.compile(year_match, re.I)
year_m = RE_YEAR.search(self.original_dirname)
year_m = RE_YEAR.search(dirname)
if year_m:
# Find the last matched date
# Keep year_m to use in getTitles
year = RE_YEAR.findall(self.original_dirname)[-1][0]
year = RE_YEAR.findall(dirname)[-1][0]
self.movie_info['year'] = year
else:
self.movie_info['year'] = ''
@@ -921,6 +922,10 @@ def getTitles(match, name):
xtitled = titler(x)
title = replace_word(title, xtitled, x)
# Make sure the first letter of the title is always uppercase
if title:
title = titler(title[0]) + title[1:]
# The title with spaces replaced by dots
dots = title.replace(" - ", "-").replace(' ','.').replace('_','.')
dots = dots.replace('(', '.').replace(')','.').replace('..','.').rstrip('.')

View File

@@ -194,10 +194,12 @@ class URLGrabber(Thread):
if res == 0:
NzbQueue.do.remove(future_nzo.nzo_id, add_to_history=False)
elif res == -2:
self.add(url, future_nzo)
elif matrix_id and length > 0:
# Keep retrying NzbMatrix forever (if file not empty)
self.add(url, future_nzo)
retry_count -= 1
if retry_count > 0:
logging.info('Incomplete NZB, retry %s', url)
self.queue.put((url, future_nzo, retry_count))
else:
misc.bad_fetch(future_nzo, url, retry=True, content=True)
else:
misc.bad_fetch(future_nzo, url, retry=True, content=True)
# Check if a supported archive

View File

@@ -261,13 +261,19 @@ class Scheduler:
if sys.version_info>=(2,6):
# code for sched module of python 2.6+
def _getqueuetoptime(self):
return self.sched._queue[0].time
try:
return self.sched._queue[0].time
except IndexError:
return 0.0
def _clearschedqueue(self):
self.sched._queue[:] = []
else:
# code for sched module of python 2.5 and older
def _getqueuetoptime(self):
return self.sched.queue[0][0]
try:
return self.sched.queue[0][0]
except IndexError:
return 0.0
def _clearschedqueue(self):
self.sched.queue[:] = []

View File

@@ -22,6 +22,19 @@
#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'}
# 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
}
try:
import Growl
import os.path

View File

@@ -109,7 +109,11 @@ def test_nntp_server(host, port, server=None, username=None, password=None, ssl=
return False, xml_name(str(sys.exc_info()[1]))
# Could do with making a function for return codes to be used by downloader
code = nw.lines[0][:3]
try:
code = nw.lines[0][:3]
except IndexError:
code = ''
nw.lines.append('')
if code == '480':
return False, T('Server requires username and password.')

View File

@@ -181,7 +181,7 @@ print 'Creating the NSIS POT file'
if not os.path.exists(PON_DIR):
os.makedirs(PON_DIR)
src = open(NSIS, 'r')
dst = open(os.path.join(PON_DIR, DOMAIN_NSIS+'.pot'), 'w')
dst = open(os.path.join(PON_DIR, DOMAIN_NSIS+'.pot'), 'wb')
dst.write(HEADER.replace('__TYPE__', 'NSIS'))
dst.write('\n')
count = 0

View File

@@ -49,7 +49,12 @@ def add(id, str, fuzzy):
"Add a non-fuzzy translation to the dictionary."
global MESSAGES
if not fuzzy and str:
MESSAGES[id] = str
if id.count('%s') == str.count('%s'):
MESSAGES[id] = str
else:
print 'WARNING: %s mismatch, skipping!'
print ' %s' % id
print ' %s' % str

View File

Binary file not shown.

View File

Binary file not shown.