Compare commits

...

136 Commits
1.2.0 ... 1.0.3

Author SHA1 Message Date
shypike
927ba3cd9d Update text files for 1.0.3 2016-06-04 13:34:11 +02:00
Safihre
6296fc1762 #568 Add code 482 to check for too-many-connections 2016-06-03 23:24:07 +02:00
shypike
60fbe44724 Support X-DNZB-PASSWORD header. 2016-06-03 22:18:56 +02:00
shypike
29e45da431 Fix NZB association for Windows.
Make sure that the second SABnzbd instance sends an UTF-8 encoded URL to the first instance.
Otherwise CherryPy will reject the API call.
2016-06-03 22:07:44 +02:00
shypike
d82e69eef4 Handle checksum error reports from unrar. 2016-06-02 23:19:57 +02:00
shypike
8c7d557252 Prevent job from hanging when adding back par2 files.
Sometimes already completed par2 files are being re-added to the queue as extra par2 files.
Because these files are already complete, there will be no attempt to download them
and as a result they will never leave the queue.
2016-06-02 22:11:59 +02:00
shypike
7548d9e975 Correct base version number for 1.0.x releases. 2016-05-10 14:43:14 +02:00
shypike
b7e2bd9684 Update text files for 1.0.2 2016-05-03 19:39:45 +02:00
shypike
f0a243e3d3 Fix API status issues.
Remove the "ToPP" status, it serves no purpose.
Only truly deleted jobs should get the "Deleted" status,
not jobs moving from Download to PP queue.
2016-05-01 14:42:07 +02:00
shypike
6e108c9ef2 Prevent Completed and Failed jobs from getting status Deleted. 2016-04-30 11:47:03 +02:00
shypike
89edcc1924 Log the preferred character encoding 2016-04-30 11:18:32 +02:00
shypike
8a6aca47a1 Prevent stalling at 100% when QuickCheck is Off and "Download-all-pars" is On.
The repair function sent all extra par2 files back to the queue
even though they were already downloaded.
2016-04-28 22:42:51 +02:00
shypike
d03e5780b8 Fix API compatibility of queue statuses.
The new statuses TO_PP and DELETED should not be returned by the API.
Tools may not be able to handle them and they are only useful for internal purposes.
2016-04-27 12:03:37 +02:00
shypike
209d8f9b40 NNTP error 502 should not aways be interpreted as bad login.
It can also mean "too many connections".
2016-04-27 11:52:56 +02:00
shypike
c257b1be3d Update text files for 1.0.1 2016-04-26 19:57:22 +02:00
Safihre
2c48c8de2e Force MIME types for CSS and JS files
Caused problems on Windows if external programs overwriten it in registery.
See: http://forums.sabnzbd.org/viewtopic.php?f=2&t=20490
And: https://www.reddit.com/r/usenet/comments/4fkmcx/my_sab_interface_is_text_only/
2016-04-26 19:48:47 +02:00
shypike
a767ef6aed Fix API compatibility of queue.
The new statuses TO_PP and DELETED should not be returned by the API.
Tools may not be able to handle them and they are only useful for internal purposes.
2016-04-26 19:47:38 +02:00
shypike
ad61d1dd03 The pre-queue script can now return an accept value of 2, meaning immediate failure.
Supports front-ends which need the signal that an NZB has been
rejected by the pre-queue script.
2016-04-22 21:54:45 +02:00
shypike
33c3d187a0 Add start script for portable Windows installations 2016-04-22 16:44:37 +02:00
shypike
4eb486d4e2 Update text files for 1.0.0RC1 2016-04-16 15:31:48 +02:00
shypike
bfb6c167a4 Another attempt to set the default cache to 450M. 2016-04-16 15:27:35 +02:00
shypike
44abf3bdf6 Update text files for 1.0.1RC1 2016-04-15 23:12:22 +02:00
shypike
c950572592 Set default cache to 450M 2016-04-15 23:11:53 +02:00
shypike
3999cb13fd Update text files for 1.0.1RC1 2016-04-15 21:06:55 +02:00
shypike
af65075f0c Update text files for 1.0.0RC1 2016-04-15 21:05:53 +02:00
shypike
de2a2b465b Update text files for 1.0.1RC1 2016-04-13 22:41:13 +02:00
shypike
cd7a77f02d Revert "Set default cache size to 750MB on Windows and OSX."
This reverts commit 9b420e91c9.
2016-04-13 22:30:05 +02:00
shypike
f4a5394b63 Prevent creating orphan items in "incomplete" when deleting downloading jobs.
Due to previous issues where articles could be lost,
the nzf.deleted and no.deleted flags were not obeyed.
This could lead to creation of orphans when lost articles would be flushed.

Better solution: drop articles only when job is in a final state.
Also prevent NZO files from being saved when job is in "deleted" state.
2016-04-13 18:32:23 +02:00
jdfalk
3fb6a8dedb Update sabnzbd@.service
1. Added requirement for network to be up before sab starts.
2. Explicitly set service type to simple.
3. Enabled sabnzbd restart on service failure via systemd.
2016-04-13 18:22:11 +02:00
Safihre
50c8f84eba #448-#126 Forced item with missing articles caused overflow in paused queue
Closes #448
Closes #126
2016-04-13 18:21:41 +02:00
Safihre
2c7ecdee92 #464 Grabbing items don't always have status=grabbing
But now they do!
2016-04-07 21:45:28 +02:00
Safihre
72390a793a Add Optional label to Retry password 2016-04-07 21:45:17 +02:00
Safihre
04ad4e5d3e Update cache text to more 2016 values 2016-04-07 21:45:05 +02:00
Safihre
5ef9c6a433 #530 do not ignore files in QuickCheck
Par2 wouldn't ignore them either
2016-04-07 21:44:51 +02:00
shypike
e6baffc839 Prevent API crashes when 'mode' or 'name' have double entries. 2016-04-07 21:35:07 +02:00
shypike
e361eb25a5 Fix potential race condition in BPSmeter. 2016-04-01 21:18:19 +02:00
shypike
9b420e91c9 Set default cache size to 750MB on Windows and OSX.
To make handling of posts with large files more efficient.
2016-04-01 21:09:15 +02:00
Safihre
3a4bf971b2 #529 Fix unicode strip in OptionStr 2016-04-01 20:47:11 +02:00
Safihre
1128691c5d #527 Fix "Download all par2 files" behavior 2016-03-29 21:03:48 +02:00
Safihre
15043aef3f DB Strings should be encapsulated in ' not " 2016-03-29 21:03:30 +02:00
savef
2a3b4afa03 Treat ambiguous numeric values as number of minutes for custom pause time.
Currently if you just type "100" into the custom pause field it'll think you want 143015 minutes, that's useless. A lot of people are probably used to the old Plush behaviour of entering the number of minutes you want to pause for, it's also a much saner default. So in the case that the user just enters some numbers and nothing else, this assumes they want to pause for that many minutes.
2016-03-24 21:01:04 +01:00
shypike
00a98efa81 Fix race-condition when deleting an actively downloading job.
Closes #237
2016-03-24 20:57:27 +01:00
shypike
f013dd7f0d Accept MIME records that have only LF line endings.
Some tool developers just ignore the rule requiring CRLF.
2016-03-23 23:29:12 +01:00
shypike
7b91b1c769 Fix race condition when API and postprocessor both want to delete a history item. 2016-03-23 23:03:28 +01:00
shypike
5583cce322 When urlgrabber receives a 404, stop trying. 2016-03-23 23:00:38 +01:00
shypike
b995c5f992 Fix PushOver support.
Adjust priority levels to the current PushOver API.
Re-enable device field now that the PushOver API supports readable device labels.
2016-03-22 21:25:05 +01:00
shypike
214ac4a53d Prevent incompatibility due to missing 'script_log' field.
Fixes commit c0f2f59fc1
2016-03-20 15:24:07 +01:00
Safihre
c0f2f59fc1 Fix breaking Glitter bug with large script_log 2016-03-18 14:11:54 +01:00
shypike
b90a847a6f Fix omission in README.mkd 2016-03-15 21:42:16 +01:00
shypike
a58bb385f5 Update text files for 1.0.0 2016-03-15 20:12:50 +01:00
shypike
9754baeb1c Fix handling of changed "ignore_samples" option.
Closes #510
2016-03-15 20:08:35 +01:00
shypike
ffcd154966 Update text files for 1.0.0 Final. 2016-03-14 19:12:59 +01:00
shypike
97cfe9488c Update text files for 1.0.0RC5 2016-03-11 19:24:27 +01:00
shypike
374b6f616a Fix crash in CherryPy when it reports problems with some IPv6 addresses.
A bug in Python's traceback logging causes a crash when an IPv6 address with an embedded % is reported.
2016-03-11 19:22:49 +01:00
Sander Jonkers
e2f51595b6 Because of dual IPv4/IPv6 clients, finding the public ipv4 needs special attention 2016-03-10 22:52:22 +01:00
shypike
04091a16aa Fix display of SABnzbd's icon by OSX Notification Center.
El Capitan doesn't accept the -sender parameter, so just omit it.
2016-03-08 16:40:44 +01:00
shypike
9d9d2fd9a2 Revert "Fix Plush dashboard"
This reverts commit 42f1a4926c.
2016-03-08 16:00:24 +01:00
shypike
5746115331 Suppress errors/warnings about bad "Rating" files when the feature is disabled. 2016-03-08 15:53:52 +01:00
Safihre
42f1a4926c Fix Plush dashboard 2016-03-05 11:23:19 +01:00
Safihre
7d87fd461b Fix Glitter display in <1MB/s range 2016-03-05 11:22:57 +01:00
shypike
1ba9976979 Update text files for 1.0.0RC4 2016-03-05 08:52:09 +01:00
shypike
659c199043 Fix --ipv6_hosting option.
Repairs commit 1cbff28
2016-03-05 08:50:13 +01:00
shypike
81a3f53226 Update text files for 1.0.0RC3 2016-03-04 20:39:01 +01:00
shypike
1cbff28f67 Disable listening on IPv6 addresses by the internal web server.
Setting Config->Special->ipv6_hosting to 1 will enable IPv6 listening.
Command line option --ipv6_hosting allows forcing the choice, should SABnzbd not start.
Closes #492
2016-03-04 19:26:50 +01:00
shypike
8e15acbf30 Update translations 2016-03-04 18:55:20 +01:00
Safihre
e07be60db6 #489 wrongly encoded & in the preload 2016-03-01 22:20:51 +01:00
Safihre
539c9662ff 'Default' not translated in Server-category 2016-03-01 22:20:35 +01:00
shypike
b396014f8d Fix IP test at startup.
Correction of problem introduced by commit afff88b "Use self-test.sabnzbd.org for connection tests".
2016-02-24 22:30:02 +01:00
shypike
1db32415b6 Update translations 2016-02-24 21:37:22 +01:00
shypike
b24629db6b Update text files for 1.0.0RC2 2016-02-24 21:11:43 +01:00
Safihre
9b5cdcf8fb Add trailing "/" to href's 2016-02-24 21:05:12 +01:00
shypike
4831415d14 Use self-test.sabnzbd.org for connection tests 2016-02-24 20:34:04 +01:00
Chris Thorn
a4c51f0b20 Parse bandwidth limit as a float instead of an integer so that non-integer values can be used as bandwidth limit 2016-02-24 20:09:02 +01:00
shypike
ec3ba1fb93 Changing server priorities during a download could lead to unexpected results and lockups.
Target priority of articles must be kept at the TryList level so that they
are reset when the try_list is reset.
Closes #378
2016-02-24 20:08:51 +01:00
Safihre
61966f7036 Plush dashboard local IPv4 wouldn't show if external failed
Typo!
For 1.0.0
2016-02-24 20:08:38 +01:00
Safihre
4f69e81841 Add link to information about SSL/yEnc 2016-02-24 20:07:48 +01:00
Safihre
d0d90581df Tweak first Config page 2016-02-24 20:07:35 +01:00
Safihre
8ea5c27633 Improve display of message on blocked server 2016-02-24 20:07:16 +01:00
shypike
517500fdf3 Add link to issue list on support site. 2016-02-19 22:42:30 +01:00
shypike
c4c1c9b6ab Prevent UI errors due to history_db handle not being available. 2016-02-19 22:22:42 +01:00
Safihre
2388889ede Filegrabber did not sanatize filename 2016-02-19 22:21:28 +01:00
Safihre
55cfe878d7 Catch failing Windows Notification
I assumed Windows notifications could not fail, but clearly they can:
http://forums.sabnzbd.org/viewtopic.php?f=11&t=20211&p=104438
When no tray-icon is available, it will fail and in the case of
completed NZB message it will restart the whole of SABnzbd.
2016-02-17 21:25:42 +01:00
Safihre
a2daaee468 Add Pystone score to Glitter status 2016-02-17 21:06:43 +01:00
Safihre
2c360e395e Limit to max 250 items per page (realistic limit) 2016-02-17 21:05:55 +01:00
Jonathon Saine
399cfee594 Add pyOpenSSL info to startup/utility/config base. Add OpenSSL & yEnc to config base as well. 2016-02-17 21:04:13 +01:00
shypike
be646ae6ab Set default for https verification to off. 2016-02-17 20:50:24 +01:00
shypike
b470253d9f Disable https verification when uploading NZB to running instance of SABnzbd. 2016-02-13 16:12:04 +01:00
shypike
b83c493492 Update translations 2016-02-11 01:06:52 +01:00
Safihre
991277bb01 Glitter broke on empty preload strings
See
http://forums.sabnzbd.org/viewtopic.php?f=11&t=20192&p=104368#p104368
In case of UnicodeError
2016-02-10 22:59:11 +01:00
Safihre
5626013b81 Don't allow name change or filesview on grabbing 2016-02-10 22:58:56 +01:00
Safihre
2810d37758 Make disabled servers look more disabled 2016-02-10 22:58:40 +01:00
Safihre
c2f08f01e0 #408 Show red when Add-NZB left empty 2016-02-10 22:57:30 +01:00
Safihre
17ff087e06 Do not confirm clearing warnings 2016-02-05 23:36:47 +01:00
Safihre
77de565b7c Link in message about Orphans was broken 2016-02-05 23:36:36 +01:00
Safihre
54d238aa4d Message labels were not translated
INFO and WARNING
2016-02-05 23:36:23 +01:00
Safihre
379d09f8cc Improve message about no localStorage
It happens more than I expected, so better make a proper message.
2016-02-05 23:35:23 +01:00
shypike
00de72b127 Update text files for 1.0.xRC1 2016-02-03 21:18:42 +01:00
shypike
f9c84fa7dd Fix trouble with disk speed meter (especially on Windows) Part 2.
Improve the benchmark by reducing Python overhead by writing larger blocks.
2016-02-03 21:08:47 +01:00
shypike
c8e46691bb Solve file name encoding issues for OSX.
- Names returned by unrar-commandline need to be Unicoded.
- For yEnc embedded names, only test for UTF-8 and CP1252, but not the local codepage.
- Suppress some bogus warnings
- Log the output of the unrar tool
2016-02-03 20:59:12 +01:00
shypike
df1bb636e5 Fix links in text files to pooit to 1.0.0 entries in the Wiki. 2016-02-03 20:51:19 +01:00
shypike
ff886fad0d Fix all links in the templates to point to 1.0.0 (or 1-0) entries in the Wiki. 2016-02-03 20:50:13 +01:00
shypike
6dbee7a413 Fix trouble with disk speed meter (especially on Windows) Part 2.
Move fix outside of the measurement loop.
Don't remove the test-file within the loop, but only after it's finished,
otherwise we'll still get a "Permission denied".
2016-01-30 10:52:28 +01:00
shypike
3f8fcd7172 Fix trouble with disk speed meter (especially on Windows).
Better handling when folder is not available or writable.
Windows requires some access outside of the Python code to avoid "permission denied".
2016-01-29 23:54:32 +01:00
shypike
d94f7388e6 Add a link on the main Config page, to the "issues" page on the Wiki 2016-01-29 19:55:04 +01:00
Safihre
ad8b49fea8 #408 Firefox-fix: word-wrap instead of word-break 2016-01-29 19:21:59 +01:00
Safihre
ce00270c12 #447 only show arguments-field for speedlimit 2016-01-29 19:21:41 +01:00
Safihre
8c501f8f58 #447 Servers in scheduler more clear 2016-01-29 19:21:30 +01:00
Safihre
ce313ebc65 #445 Reduce statusinfo timeout on startup 2016-01-29 19:21:18 +01:00
Safihre
887ad881a2 #444 HTTPS instead of HTTP for RSS favicon 2016-01-29 19:21:07 +01:00
Safihre
ce40827552 Fix breaking RSS page
Fixes http://forums.sabnzbd.org/viewtopic.php?f=11&t=20114
2016-01-29 19:20:52 +01:00
shypike
2777d89482 Fix typos that prevented notifications about disk full being sent. 2016-01-28 23:19:36 +01:00
shypike
727b300a0e Update translations 2016-01-24 16:34:40 +01:00
shypike
652b021a8e Update text files for 0.8.0Beta6 2016-01-24 16:26:26 +01:00
shypike
fdf33acfbb Allow "None" as selection for secondary skin. 2016-01-24 16:15:02 +01:00
shypike
b001bc9b6f Prevent multiple resume notifications.
Only report "Resume" when coming from Paused mode.
2016-01-24 15:18:24 +01:00
shypike
8802cb1d8c Notifications template contained two instances of "ncenter_enable", leading to problems.
The result was a list instead of a single value.
2016-01-24 15:18:07 +01:00
shypike
e19a2fbae7 Improve handling of an old queue when upgrading to 0.8.0+
Warn only for a non-empty queue.
For Windows, when using a relative "download_dir" based on the user profile,
prepend the path with "Documents".
No action when the -f parameter was used.
This way it will be easier to restore existing jobs.
2016-01-24 15:17:47 +01:00
Safihre
53e38f98f9 Firefox needs more time to process the Server AJAX 2016-01-24 15:16:52 +01:00
Safihre
e783e227f6 #438 Try to stop Firefox from checking checkboxes 2016-01-24 15:16:39 +01:00
shypike
f3dfbe4181 Fix problem where a stray RAR file would cause a failed unpack run.
When a job of which the RAR files are renamed by par2,
needs repair of one more more files, the original damaged files will stay behind.
This will cause SABnzbd to try a doomed attempt at unpacking.
SABnzbd should keep track of such files and delete them after repair.
2016-01-24 15:15:57 +01:00
shypike
bcd8ca8bc4 Fix potential crash when reverting par2 renames.
Can happen when files have been modified outside of SABnzbd's control.
2016-01-24 15:12:06 +01:00
shypike
816d6a63cd For SSL protocol choice, default to auto-negotiation.
The "V23" method is interpreted by OpenSSL as "negotiate the highest available protocol"
and should therefor be a safe choice (best chance of working and best security).
If a user wants to, it is possible to fix the protocol, to prevent interference in the negotiation.
We cannot just assume that we can use our highest fixed protocol, because some Usenet servers
are being slow with implementing TLS1.2
2016-01-24 15:11:30 +01:00
shypike
88d3f25700 Perform IPv6 test on port 443 instead of 80.
Works better with some proxies.
Closes issue #274
2016-01-19 18:13:42 +01:00
shypike
80f69b11db When trying to connect to another SABnzbd instance over HTTPS, don't verify certificates.
Very few SABnzbd installations will have valid certificates.
2016-01-19 18:03:33 +01:00
Safihre
81a11f20c8 Re-order Switches page 2016-01-19 17:30:01 +01:00
Safihre
9e2a839953 Config fixes 2016-01-19 17:30:01 +01:00
Safihre
3cefcde270 #408 Refresh on Config Special save to update the * 2016-01-19 17:30:01 +01:00
Safihre
87a1eacfe7 #408 Also close history-details on history-row click
Before it would only open
2016-01-19 17:30:01 +01:00
Safihre
7cbc1a8419 #408 Browser navbar to black on mobile 2016-01-19 17:30:01 +01:00
Safihre
7b5570eb0b #408 Extra space next to Folder icon 2016-01-19 17:30:00 +01:00
Safihre
1a43a4dcf0 #432 Change filename to name in Add NZB 2016-01-19 17:30:00 +01:00
Safihre
2c2a6592c7 End of queue script was forgotten in Glitter 2016-01-19 17:30:00 +01:00
shypike
f31de6ee4e The compiled OSX build wasn't restarted with original command line arguments.
Rare use case where the App was originally started with parameters.
Essential for correct preservation of the -f parameter.
2016-01-19 17:29:11 +01:00
shypike
8fcd1f6b6c Merge branch 'develop' into R0.8.0 2016-01-16 12:25:38 +01:00
shypike
d7f3a473d7 Merge branch 'develop' into R0.8.0 2016-01-13 21:51:51 +01:00
shypike
ab2eb0c94e Update text files for 0.8.0Beta5 2016-01-13 20:17:32 +01:00
75 changed files with 14872 additions and 13681 deletions

View File

@@ -1,5 +1,5 @@
*******************************************
*** This is SABnzbd 0.8.0 ***
*** This is SABnzbd 1.0.3 ***
*******************************************
SABnzbd is an open-source cross-platform binary newsreader.
It simplifies the process of downloading from Usenet dramatically,
@@ -12,8 +12,8 @@ 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.8.0:
http://wiki.sabnzbd.org/introducing-0-8-0
IMPORTANT INFORMATION about release 1.0.0:
http://wiki.sabnzbd.org/introducing-1-0-0
Please also read the file "ISSUES.txt"
@@ -37,6 +37,6 @@ Install new version
Start SABnzbd.
The organization of the download queue is different from 0.7.x (and older).
0.8.0 will not finish downloading an existing queue.
1.0.0 will not finish downloading an existing queue.
Also, your sabnzbd.ini file will be upgraded, making it
incompatible with older releases.

View File

@@ -1,4 +1,4 @@
SABnzbd 0.8.0
SABnzbd 1.0.3
-------------------------------------------------------------------------------
0) LICENSE

View File

@@ -24,13 +24,13 @@
For these the server blocking method is not very favourable.
There is an INI-only option that will limit blocks to 1 minute.
no_penalties = 1
See: http://wiki.sabnzbd.org/configure-special-0-8
See: http://wiki.sabnzbd.org/configure-special-1-0
- Some third-party utilties try to probe SABnzbd API in such a way that you will
often see warnings about unauthenticated access.
If you are sure these probes are harmless, you can suppress the warnings by
setting the option "api_warnings" to 0.
See: http://wiki.sabnzbd.org/configure-special-0-8
See: http://wiki.sabnzbd.org/configure-special-1-0
- On OSX you may encounter downloaded files with foreign characters.
The par2 repair may fail when the files were created on a Windows system.
@@ -41,7 +41,7 @@
You will see this only when downloaded files contain accented characters.
You need to fix it yourself by running the convmv utility (available for most Linux platforms).
Possible the file system override setting 'fsys_type' might be solve things:
See: http://wiki.sabnzbd.org/configure-special-0-8
See: http://wiki.sabnzbd.org/configure-special-1-0
- The "Watched Folder" sometimes fails to delete the NZB files it has
processed. This happens when other software still accesses these files.
@@ -81,4 +81,4 @@
- Squeeze Linux
There is a "special" option that will allow you to select an alternative library.
use_pickle = 1
See: http://wiki.sabnzbd.org/configure-special-0-8
See: http://wiki.sabnzbd.org/configure-special-1-0

View File

@@ -1,7 +1,7 @@
Metadata-Version: 1.0
Name: SABnzbd
Version: 0.8.0Beta4
Summary: SABnzbd-0.8.0Beta4
Version: 1.0.3
Summary: SABnzbd-1.0.3
Home-page: http://sabnzbd.org
Author: The SABnzbd Team
Author-email: team@sabnzbd.org

View File

@@ -1,71 +1,60 @@
Release Notes - SABnzbd 0.8.0Beta4
====================================
Release Notes - SABnzbd 1.0.3
===============================
## Changes in Beta4
- Unicode crashes in user interface fixed
- Glitter skin improved
- Resume can now give notification
- In Config->Server, show active servers before inactive ones
- Update unrar to 5.30
- Added Windows Notifications (local)
- Updated many localizations
## Bugfixes in 1.0.3
- Fix jobs hanging at 99% or 100%
- Support X-DNZB-PASSWORD header for inders that use this
- Prevent fatal "too many connections" issue
- Show checksum errors reported by unrar
- Windows: fix coupling of NZB files to SABnzbd, when the name contains non-US-ASCII characters
## Changes in Beta3
- Speedlimit corrections
- Windows build now verifies https certificates
- Windows build now supports TLS 1.2
- Fixed bug that could lead to all NZBs being reported as duplicates
- Skin improvements
## Changes in Beta2
- Improvements in IPv6 handling
- Extension of SSL protocols (where supported)
- Many improvemnts in the Glitter skin
- On Windows, Season Sort often failed
- Speedlimiting can now be absolute or in percentage
- Scheduler action to remove completed history items
## Changes in Beta1
- Glitter is now the default skin
- Glitter fixes and improvements
- Removed Classic and Mobile skins
- Removed Config parts of smpl and Plush skins
- API-call "history" now accepts one or more "category" parameters in order to filter.
- API-call "addurl" now returns a list of nzo_id's, which will be valid for the actual jobs.
- Update unrar to release 5.21
- Enable renaming of Usenet servers.
- Add Pushbullet support.
- Implement Pushover support.
- Restore Rating function
- Newsserver IPv6 load balancing aka Happy Eyeballs / RFC 6555
- Lots of bug fixes
## Changes in Alpha3
- New skin: Glitter
- Assign servers to categories
- When upgrading from 0.7.x, a backup server will get priority 1
- Lots of bug fixes
## Changes in Alpha2
- Server priorities instead of primary/backup ==> REVIEW YOUR SERVER SETTINGS!
- Work-arounds to avoid bugs in PyOpenSSL 0.14
- Support RAR's REV files to some extent
- Diagnostic dashboard tab for "Status" page
## Bugfixes in 1.0.2
- Fix hangups at 100% when QuickCheck is off and "all-pars" is on
- Fix handling of "too many connections" for some Usenet servers
## What's new in 0.8.0
## What's new in 1.0.1
- Prevent creating orphan items in "incomplete" when deleting downloading jobs.
- Forced item with missing articles caused overflow into paused jobs
- Do QuickCheck even on files that would be removed by the Cleanup-list (problematic for RAR files).
- Fix "Download all par2 files" behavior
- Treat ambiguous numeric values as number of minutes for custom pause time.
- Accept MIME records that have only LF line endings (error in some third-party utilities)
- Fix PushOver support.
- Fix breaking Glitter bug with large script_log
- Fix issues with deleting jobs via the API
- Fix issue where Sonarr could not read using the History-API
- Increase default cache to 450M
- The pre-queue script can now return an accept value of 2, meaning immediate failure. (Useful for Sonarr.)
- Add start script for portable Windows installations
## What's new in 1.0.0
- Full Unicode support with Chinese and Russian translations
- Improved Notifications (including Prowl)
- New default UI: Glitter
- Server priorities instead of primary/backup ==> REVIEW YOUR SERVER SETTINGS!
- Newsserver IPv6 load balancing aka Happy Eyeballs / RFC 6555
- Duplicate detection for series
- Bonjour/ZeroConfig support
- More filters in RSS
- 7zip support
- Option to save repair time by downloading all par2 files
- Support for long paths in Windows (above 260)
- Improved security for external access
- Lots of small improvements and bug fixes
- The "Classic" skin is gone
- Redesign of notifications classes
- More notification services supported
- Diagnostic dashboard tab for "Status" page
- Bonjour/ZeroConfig support
## Remarks
- SABnzbd's webserver now doesn't listen to IPv6 addresses by default.
- Use Config->Special->ipv6_hosting if you want this enabled.
- "localhost" will be replaced with "127.0.0.1", check any browser bookmark and third-party tool
- Classic skin has been removed
- Support extra parameters for par2 on other platforms than Windows
- Option to verify HTTPS connections (default off)
- Auto-negotiates best Usenet ssl protocol (override possible)
- When upgrading from 0.7.x, a backup server will get priority 1
## About
SABnzbd is an open-source cross-platform binary newsreader.
@@ -77,8 +66,8 @@ Release Notes - SABnzbd 0.8.0Beta4
(c) Copyright 2007-2016 by "The SABnzbd-team" \<team@sabnzbd.org\>
### IMPORTANT INFORMATION about release 0.8.0
<http://wiki.sabnzbd.org/introducing-0-8-0>
### IMPORTANT INFORMATION about release 1.0.0
<http://wiki.sabnzbd.org/introducing-1-0-0>
### Known problems and solutions
- Read the file "ISSUES.txt"
@@ -90,8 +79,7 @@ Release Notes - SABnzbd 0.8.0Beta4
- Start SABnzbd
The organization of the download queue is different from older versions.
0.8.x will not see the existing queue, but you can go to
1.0.x will not see the existing queue, but you can go to
Status->QueueRepair and "Repair" the old queue.
Also, your sabnzbd.ini file will be upgraded, making it
incompatible with releases older than 0.7.9

View File

@@ -278,7 +278,7 @@ def print_help():
print " --log-all Log all article handling (for developers)"
print " --console Force console logging for OSX app"
print " --new Run a new instance of SABnzbd"
print " --no_ipv6 Do not listen on IPv6 address [::1]"
print " --ipv6_hosting <0|1> Listen on IPv6 address [::1]"
def print_version():
@@ -699,7 +699,7 @@ def get_webhost(cherryhost, cherryport, https_port):
def attach_server(host, port, cert=None, key=None, chain=None):
""" Define and attach server, optionally HTTPS """
if not (sabnzbd.cfg.no_ipv6() and '::1' in host):
if sabnzbd.cfg.ipv6_hosting() or '::1' not in host:
http_server = _cpwsgi_server.CPWSGIServer()
http_server.bind_addr = (host, port)
if cert and key:
@@ -714,7 +714,10 @@ def is_sabnzbd_running(url, timeout=None):
""" Return True when there's already a SABnzbd instance running. """
try:
url = '%s&mode=version' % (url)
# Do this without certificate verification, few installations will have that
prev = sabnzbd.set_https_verification(False)
ver = sabnzbd.newsunpack.get_from_url(url, timeout=timeout)
sabnzbd.set_https_verification(prev)
return bool(ver and re.search(r'\d+\.\d+\.', ver))
except:
return False
@@ -743,8 +746,10 @@ def check_for_sabnzbd(url, upload_nzbs, allow_browser=True):
# Upload any specified nzb files to the running instance
if upload_nzbs:
from sabnzbd.utils.upload import upload_file
prev = sabnzbd.set_https_verification(0)
for f in upload_nzbs:
upload_file(url, f)
sabnzbd.set_https_verification(prev)
else:
# Launch the web browser and quit since sabnzbd is already running
# Trim away everything after the final slash in the URL
@@ -827,7 +832,7 @@ def commandline_handler(frozen=True):
try:
opts, args = getopt.getopt(info, "phdvncw:l:s:f:t:b:2:",
['pause', 'help', 'daemon', 'nobrowser', 'clean', 'logging=',
'weblogging=', 'server=', 'templates', 'no_ipv6',
'weblogging=', 'server=', 'templates', 'ipv6_hosting=',
'template2', 'browser=', 'config-file=', 'force',
'version', 'https=', 'autorestarted', 'repair', 'repair-all',
'log-all', 'no-login', 'pid=', 'new', 'sessions', 'console', 'pidfile=',
@@ -905,7 +910,7 @@ def main():
new_instance = False
force_sessions = False
osx_console = False
no_ipv6 = False
ipv6_hosting = None
_service, sab_opts, _serv_opts, upload_nzbs = commandline_handler()
@@ -996,9 +1001,9 @@ def main():
elif opt in ('--console',):
re_argv.append(opt)
osx_console = True
elif opt in ('--no_ipv6',):
no_ipv6 = True
elif opt in ('--ipv6_hosting',):
ipv6_hosting = arg
sabnzbd.MY_FULLNAME = os.path.normpath(os.path.abspath(sabnzbd.MY_FULLNAME))
sabnzbd.MY_NAME = os.path.basename(sabnzbd.MY_FULLNAME)
sabnzbd.DIR_PROG = os.path.dirname(sabnzbd.MY_FULLNAME)
@@ -1075,8 +1080,8 @@ def main():
# Set root folders for HTTPS server file paths
sabnzbd.cfg.set_root_folders2()
if no_ipv6:
sabnzbd.cfg.no_ipv6.set(True)
if ipv6_hosting is not None:
sabnzbd.cfg.ipv6_hosting.set(ipv6_hosting)
# Determine web host address
cherryhost, cherryport, browserhost, https_port = get_webhost(cherryhost, cherryport, https_port)
@@ -1237,6 +1242,7 @@ def main():
logging.info('--------------------------------')
logging.info('%s-%s (rev=%s)', sabnzbd.MY_NAME, sabnzbd.__version__, sabnzbd.__baseline__)
logging.info('Full executable path = %s', sabnzbd.MY_FULLNAME)
if sabnzbd.WIN32:
suffix = ''
if vista_plus:
@@ -1251,9 +1257,14 @@ def main():
logging.info('Platform = %s', os.name)
logging.info('Python-version = %s', sys.version)
logging.info('Arguments = %s', sabnzbd.CMDLINE)
try:
logging.info('Preferred encoding = %s', locale.getpreferredencoding())
except:
logging.info('Preferred encoding = ERROR')
if sabnzbd.cfg.log_level() > 1:
from sabnzbd.utils.getipaddress import localipv4, publicipv4, ipv6
from sabnzbd.getipaddress import localipv4, publicipv4, ipv6
mylocalipv4 = localipv4()
if mylocalipv4:
@@ -1359,6 +1370,7 @@ def main():
import sabnzbd.utils.sslinfo
logging.info("SSL version %s", sabnzbd.utils.sslinfo.ssl_version())
logging.info("pyOpenSSL version %s", sabnzbd.utils.sslinfo.pyopenssl_version())
logging.info("SSL potentially supported protocols %s", str(sabnzbd.utils.sslinfo.ssl_potential()))
logging.info("SSL actually supported protocols %s", str(sabnzbd.utils.sslinfo.ssl_protocols()))
@@ -1468,9 +1480,10 @@ def main():
'error_page.404': sabnzbd.panic.error_page_404
})
static = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(web_dir, 'static')}
staticcfg = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(web_dirc, 'staticcfg')}
wizard_static = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(wizard_dir, 'static')}
forced_mime_types = {'css': 'text/css', 'js': 'application/javascript'}
static = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(web_dir, 'static'), 'tools.staticdir.content_types': forced_mime_types}
staticcfg = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(web_dirc, 'staticcfg'), 'tools.staticdir.content_types': forced_mime_types}
wizard_static = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(wizard_dir, 'static'), 'tools.staticdir.content_types': forced_mime_types}
appconfig = {'/sabnzbd/api': {'tools.basic_auth.on': False},
'/api': {'tools.basic_auth.on': False},
@@ -1489,7 +1502,7 @@ def main():
}
if web_dir2:
static2 = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(web_dir2, 'static')}
static2 = {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(web_dir2, 'static'), 'tools.staticdir.content_types': forced_mime_types}
appconfig['/sabnzbd/m/api'] = {'tools.basic_auth.on': False}
appconfig['/sabnzbd/m/rss'] = {'tools.basic_auth.on': False}
appconfig['/sabnzbd/m/shutdown'] = {'streamResponse': True}
@@ -1671,16 +1684,20 @@ def main():
sys.argv = re_argv
os.chdir(org_dir)
if sabnzbd.DARWIN:
args = sys.argv[:]
args.insert(0, sys.executable)
# TODO: when executing from sources on osx, after a restart, process is detached from console
# If OSX frozen restart of app instead of embedded python
if getattr(sys, 'frozen', None) == 'macosx_app':
# [[NSProcessInfo processInfo] processIdentifier]]
# logging.info("%s" % (NSProcessInfo.processInfo().processIdentifier()))
logging.info(os.getpid())
os.system('kill -9 %s && open "%s"' % (os.getpid(), sabnzbd.MY_FULLNAME.replace("/Contents/MacOS/SABnzbd", "")))
my_pid = os.getpid()
my_name = sabnzbd.MY_FULLNAME.replace('/Contents/MacOS/SABnzbd', '')
my_args = ' '.join(sys.argv[1:])
cmd = 'kill -9 %s && open "%s" --args %s' % (my_pid, my_name, my_args)
logging.info('Launching: ', cmd)
os.system(cmd)
else:
args = sys.argv[:]
args.insert(0, sys.executable)
pid = os.fork()
if pid == 0:
os.execv(sys.executable, args)

View File

@@ -608,10 +608,10 @@ class Part(Entity):
# No more data--illegal end of headers
raise EOFError("Illegal end of headers.")
if line == ntob('\r\n'):
if line == ntob('\r\n') or line == ntob('\n'):
# Normal end of headers
break
if not line.endswith(ntob('\r\n')):
if not line.endswith(ntob('\n')):
raise ValueError("MIME requires CRLF terminators: %r" % line)
if line[0] in ntob(' \t'):

View File

@@ -442,7 +442,13 @@ class Bus(object):
def log(self, msg="", level=20, traceback=False):
"""Log the given message. Append the last traceback if requested."""
if traceback:
msg += "\n" + "".join(_traceback.format_exception(*sys.exc_info()))
# Work-around for bug in Python's traceback implementation
# which crashes when the error message contains %1, %2 etc.
errors = sys.exc_info()
if '%' in errors[1].message:
errors[1].message = errors[1].message.replace('%', '#')
errors[1].args = [item.replace('%', '#') for item in errors[1].args]
msg += "\n" + "".join(_traceback.format_exception(*errors))
self.publish('log', msg, level)
bus = Bus()

View File

@@ -1,60 +1,117 @@
<!--#set global $pane="Config"#-->
<!--#set global $help_uri="configure-0-7"#-->
<!--#set global $help_uri="configure-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<div class="section padTable">
<table id="infoTable">
<tbody>
<tr class="alt">
<td class="infoTableHeader">$T('version'): </td>
<td class="infoTableCell">$version [$build]</td>
</tr>
<tr>
<td class="infoTableHeader">$T('uptime'): </td>
<td class="infoTableCell">$uptime</td>
</tr>
<tr class="alt">
<td class="infoTableHeader">$T('confgFile'): </td>
<td class="infoTableCell">$configfn</td>
</tr>
<tr>
<td class="infoTableHeader">$T('cache').capitalize(): </td>
<td class="infoTableCell"><!--#set $msg=$T('ft-buffer@2')%($cache_art, $cache_size)#-->$msg</td>
</tr>
<tr class="alt">
<td class="infoTableHeader">$T('parameters'): </td>
<td class="infoTableCell">$cmdline</td>
</tr>
<tr>
<td class="infoTableHeader">$T('pythonVersion'): </td>
<td class="infoTableCell">$sys.version[:120]</td>
</tr>
<tr class="infoTableSeperator alt">
<td class="infoTableHeader">$T('homePage') </td>
<td class="infoTableCell"><a href="http://sabnzbd.org/" target="_blank">http://sabnzbd.org/</a></td>
</tr>
<tr>
<td class="infoTableHeader">$T('menu-wiki') </td>
<td class="infoTableCell"><a href="http://wiki.sabnzbd.org/faq" target="_blank">http://wiki.sabnzbd.org/faq</a></td>
</tr>
<tr class="alt">
<td class="infoTableHeader">$T('menu-forums') </td>
<td class="infoTableCell"><a href="http://forums.sabnzbd.org/" target="_blank">http://forums.sabnzbd.org/</a></td>
</tr>
<tr>
<td class="infoTableHeader">$T('source') </td>
<td class="infoTableCell"><a href="https://github.com/sabnzbd/sabnzbd" target="_blank">https://github.com/sabnzbd/sabnzbd</a></td>
</tr>
<tr class="alt">
<td class="infoTableHeader">$T('menu-irc') </td>
<td class="infoTableCell"><a href="irc://irc.synirc.net/#sabnzbd"><i>#sabnzbd</i> on <i>irc.synirc.net</i></a> $T('or') (<a href="http://sabnzbd.org/live-chat/" target="_blank">webchat</a>)</td>
</tr>
</tbody>
</table>
<!--#from sabnzbd.newswrapper import HAVE_SSL#-->
<!--#import sabnzbd.utils.sslinfo#-->
<!--#from sabnzbd.decoder import HAVE_YENC#-->
<!--#from sabnzbd.newsunpack import PAR2_COMMAND, PAR2C_COMMAND, RAR_COMMAND, ZIP_COMMAND, SEVEN_COMMAND, NICE_COMMAND, IONICE_COMMAND#-->
<div class="colmask">
<div class="section padTable">
<table class="table table-striped">
<tbody>
<tr>
<th scope="row">$T('version'): </th>
<td>$version [$build]</td>
</tr>
<tr>
<th scope="row">$T('uptime'): </th>
<td>$uptime</td>
</tr>
<tr>
<th scope="row">$T('confgFile'): </th>
<td>$configfn</td>
</tr>
<tr>
<th scope="row">$T('cache').capitalize(): </th>
<td><!--#set $msg=$T('ft-buffer@2')%($cache_art, $cache_size)#-->$msg</td>
</tr>
<tr>
<th scope="row">$T('parameters'): </th>
<td>$cmdline</td>
</tr>
<tr>
<th scope="row">$T('pythonVersion'): </th>
<td>$sys.version[:120]</td>
</tr>
<tr>
<th scope="row">OpenSSL:</th>
<td>
<!--#if HAVE_SSL#-->
<!--#set $sslversions = ', '.join(sabnzbd.utils.sslinfo.ssl_protocols())#-->
$sabnzbd.utils.sslinfo.ssl_version() <em>[$sslversions]</em>
<!--#else#-->
<span class="label label-warning">$T('notAvailable')</span>
<a href="$helpuri$help_uri#no_ssl" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
<!--#end if#-->
</td>
</tr>
<tr>
<th scope="row">pyOpenSSL:</th>
<td>
<!--#if HAVE_SSL#-->
$sabnzbd.utils.sslinfo.pyopenssl_version()
<!--#else#-->
<span class="label label-warning">$T('notAvailable')</span>
<a href="$helpuri$help_uri#no_ssl" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
<!--#end if#-->
</td>
</tr>
<tr>
<th scope="row">yEnc:</th>
<td>
<!--#if HAVE_YENC#-->
<span class="glyphicon glyphicon-ok"></span>
<!--#else#-->
<span class="label label-warning">$T('notAvailable')</span>
<a href="$helpuri$help_uri#no_yenc" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
<!--#end if#-->
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="padding alt">
<h5 class="copyright">Copyright &copy; 2008-2016 The SABnzbd Team &lt;<a href="mailto:team@sabnzbd.org">team@sabnzbd.org</a>&gt;</h5>
<p class="copyright"><small>$T('yourRights')</small></p>
<div class="colmask">
<div class="section padTable">
<table class="table table-striped">
<tbody>
<tr>
<th scope="row">$T('homePage') </th>
<td><a href="http://sabnzbd.org/" target="_blank">http://sabnzbd.org/</a></td>
</tr>
<tr>
<th scope="row">$T('menu-wiki') </th>
<td><a href="http://wiki.sabnzbd.org/faq" target="_blank">http://wiki.sabnzbd.org/faq</a></td>
</tr>
<tr>
<th scope="row">$T('menu-forums') </th>
<td><a href="http://forums.sabnzbd.org/" target="_blank">http://forums.sabnzbd.org/</a></td>
</tr>
<tr>
<th scope="row">$T('source') </th>
<td><a href="https://github.com/sabnzbd/sabnzbd" target="_blank">https://github.com/sabnzbd/sabnzbd</a></td>
</tr>
<tr>
<th scope="row">$T('menu-irc') </th>
<td><a href="irc://irc.synirc.net/#sabnzbd"><i>#sabnzbd</i> on <i>irc.synirc.net</i></a> $T('or') (<a href="http://sabnzbd.org/live-chat/" target="_blank">webchat</a>)</td>
</tr>
<tr>
<th scope="row">$T('menu-issues') </th>
<td><a href="http://wiki.sabnzbd.org/issues-1-0-0" target="_blank">http://wiki.sabnzbd.org/issues-1-0-0</a></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="colmask">
<div class="padding alt">
<h5 class="copyright">Copyright &copy; 2008-2016 The SABnzbd Team &lt;<a href="mailto:team@sabnzbd.org">team@sabnzbd.org</a>&gt;</h5>
<p class="copyright"><small>$T('yourRights')</small></p>
</div>
</div>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -1,5 +1,5 @@
<!--#set global $pane="Categories"#-->
<!--#set global $help_uri="configure-categories-0-7"#-->
<!--#set global $help_uri="configure-categories-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<div class="section">

View File

@@ -1,5 +1,5 @@
<!--#set global $pane="Folders"#-->
<!--#set global $help_uri="configure-folders-0-7"#-->
<!--#set global $help_uri="configure-folders-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">

View File

@@ -1,5 +1,5 @@
<!--#set global $pane="General"#-->
<!--#set global $help_uri="configure-general-0-8"#-->
<!--#set global $help_uri="configure-general-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
@@ -49,6 +49,7 @@
<div class="field-pair">
<label class="config" for="web_dir2">$T('opt-web_dir2')</label>
<select name="web_dir2" id="web_dir2">
<option value="None" selected="selected">$T("None")</option>
<!--#for $webline in $web_list#-->
<!--#if $webline.lower() == $web_dir2.lower()#-->
<option value="$webline" selected="selected">$webline</option>

View File

@@ -1,5 +1,5 @@
<!--#set global $pane="Email"#-->
<!--#set global $help_uri="configure-notifications-0-8"#-->
<!--#set global $help_uri="configure-notifications-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
@@ -82,11 +82,6 @@
</div><!-- /col2 -->
<div class="col1" <!--#if int($ncenter_enable) > 0 then '' else 'style="display:none"'#-->>
<fieldset>
<div class="field-pair">
<label class="config wide" for="ncenter_enable">$T('opt-ncenter_enable')</label>
<input type="checkbox" name="ncenter_enable" id="ncenter_enable" value="1" <!--#if int($ncenter_enable) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-ncenter_enable')</span>
</div>
<div class="field-pair">
<label class="config wide" for="ncenter_prio_startup">$T($notify_texts['startup']).replace('/', ' / ')</label>
<input type="checkbox" name="ncenter_prio_startup" id="ncenter_prio_startup" value="1" <!--#if int($ncenter_prio_startup) > 0 then 'checked="checked"' else ""#--> />
@@ -490,7 +485,7 @@
<input type="text" name="pushover_userkey" id="pushover_userkey" value="$pushover_userkey" />
<span class="desc">$T('explain-pushover_userkey')</span>
</div>
<div class="field-pair" style="display:none">
<div class="field-pair">
<label class="config" for="pushover_device">$T('opt-pushover_device')</label>
<input type="text" name="pushover_device" id="pushover_device" value="$pushover_device" />
<span class="desc">$T('explain-pushover_device')</span>
@@ -498,91 +493,111 @@
<div class="field-pair">
<label class="config" for="pushover_prio_startup">$T($notify_texts['startup']).replace('/', ' / ')</label>
<select name="pushover_prio_startup" id="pushover_prio_startup">
<option value="-2" <!--#if $pushover_prio_startup == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_startup == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_startup == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_startup == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_startup == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_startup == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_startup == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_startup == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="pushover_prio_download">$T($notify_texts['download']) / $T('link-pause') / $T('link-resume')</label>
<select name="pushover_prio_download" id="pushover_prio_download">
<option value="-2" <!--#if $pushover_prio_download == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_download == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_download == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_download == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_download == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_download == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_download == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_download == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="pushover_prio_pp">$T($notify_texts['pp'])</label>
<select name="pushover_prio_pp" id="pushover_prio_pp">
<option value="-2" <!--#if $pushover_prio_pp == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_pp == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_pp == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_pp == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_pp == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_pp == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_pp == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_pp == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="pushover_prio_complete">$T($notify_texts['complete'])</label>
<select name="pushover_prio_complete" id="pushover_prio_complete">
<option value="-2" <!--#if $pushover_prio_complete == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_complete == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_complete == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_complete == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_complete == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_complete == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_complete == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_complete == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="pushover_prio_failed">$T($notify_texts['failed'])</label>
<select name="pushover_prio_failed" id="pushover_prio_failed">
<option value="-2" <!--#if $pushover_prio_failed == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_failed == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_failed == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_failed == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_failed == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_failed == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_failed == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_failed == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="pushover_prio_queue_done">$T($notify_texts['queue_done'])</label>
<select name="pushover_prio_queue_done" id="pushover_prio_queue_done">
<option value="-2" <!--#if $pushover_prio_queue_done == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_queue_done == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_queue_done == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_queue_done == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_queue_done == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_queue_done == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_queue_done == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_queue_done == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="pushover_prio_disk_full">$T($notify_texts['disk_full'])</label>
<select name="pushover_prio_disk_full" id="pushover_prio_disk_full">
<option value="-2" <!--#if $pushover_prio_disk_full == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_disk_full == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_disk_full == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_disk_full == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_disk_full == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_disk_full == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_disk_full == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_disk_full == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="pushover_prio_warning">$T($notify_texts['warning'])</label>
<select name="pushover_prio_warning" id="pushover_prio_warning">
<option value="-2" <!--#if $pushover_prio_warning == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_warning == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_warning == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_warning == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_warning == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_warning == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_warning == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_warning == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="pushover_prio_error">$T($notify_texts['error'])</label>
<select name="pushover_prio_error" id="pushover_prio_error">
<option value="-2" <!--#if $pushover_prio_error == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_error == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_error == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_error == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_error == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_error == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_error == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_error == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>
<div class="field-pair">
<label class="config" for="pushover_prio_other">$T($notify_texts['other'])</label>
<select name="pushover_prio_other" id="pushover_prio_other">
<option value="-2" <!--#if $pushover_prio_other == -2 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-3" <!--#if $pushover_prio_other == -3 then 'selected="selected"' else ""#--> >$T('pushover-off')</option>
<option value="-2" <!--#if $pushover_prio_other == -2 then 'selected="selected"' else ""#--> >$T('prowl-very-low')</option>
<option value="-1" <!--#if $pushover_prio_other == -1 then 'selected="selected"' else ""#--> >$T('pushover-low')</option>
<option value="0" <!--#if $pushover_prio_other == 0 then 'selected="selected"' else ""#--> >$T('prowl-normal')</option>
<option value="1" <!--#if $pushover_prio_other == 1 then 'selected="selected"' else ""#--> >$T('pushover-high')</option>
<option value="2" <!--#if $pushover_prio_other == 2 then 'selected="selected"' else ""#--> >$T('pushover-confirm')</option>
<option value="2" <!--#if $pushover_prio_other == 2 then 'selected="selected"' else ""#--> >$T('prowl-emergency')</option>
</select>
</div>

View File

@@ -1,5 +1,5 @@
<!--#set global $pane="RSS"#-->
<!--#set global $help_uri="configure-rss-0-8"#-->
<!--#set global $help_uri="configure-rss-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<!--#if not $active_feed#-->
@@ -7,7 +7,7 @@
<div class="padTable">
<a class="main-helplink" href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
<p>$T('explain-RSS')</p>
<form action="add_rss_feed" method="post" novalidate>
<form action="add_rss_feed" method="post" autocomplete="off" novalidate>
<input type="hidden" name="session" value="$session" />
<table class="catTable">
<tr>
@@ -37,7 +37,7 @@
<!--#if $rss#-->
<div class="section">
<div class="padTable">
<form action="save_rss_feed" method="post" novalidate>
<form action="save_rss_feed" method="post" autocomplete="off" novalidate>
<input type="hidden" name="session" value="$session" />
<table id="subscriptions">
<tbody>
@@ -51,7 +51,7 @@
</td>
<td class="title">
<a href="?feed=$rss[$feed_item]['link']" class="subscription-title path feed <!--#if int($rss[$feed_item]['enable']) != 0 then 'feed_enabled' else 'feed_disabled'#-->">
<div class="favicon" style="background-image: url(http://www.google.com/s2/favicons?domain=$rss[$feed_item]['baselink']&amp;alt=feed);"></div> $feed_item
<div class="favicon" style="background-image: url(https://www.google.com/s2/favicons?domain=$rss[$feed_item]['baselink']&amp;alt=feed);"></div> $feed_item
</a>
</td>
<td class="controls">
@@ -73,7 +73,7 @@
</form>
<!--#if $feeds#-->
<br/>
<form action="rss_now" method="post" novalidate>
<form action="rss_now" method="post" autocomplete="off" novalidate>
<input type="hidden" name="session" value="$session" />
<button type="submit" class="btn btn-default readAll"><span class="glyphicon glyphicon-sort"></span> $T('button-rssNow')</button>
</form>
@@ -82,7 +82,7 @@
</div>
<!--#end if#-->
<div class="section">
<form action="save_rss_rate" method="post">
<form action="save_rss_rate" method="post" autocomplete="off">
<input type="hidden" name="session" value="$session" />
<div class="col1">
<fieldset>
@@ -279,7 +279,7 @@
<!--#set $fnum = 0#-->
<!--#for $filter in $rss[$feed].filters#-->
<!--#set $odd = not $odd#-->
<form action="upd_rss_filter" method="post">
<form action="upd_rss_filter" method="post" autocomplete="off">
<input type="hidden" name="session" value="$session" />
<input type="hidden" name="index" value="$fnum" />
<input type="hidden" name="feed" value="$feed" />

View File

@@ -1,5 +1,5 @@
<!--#set global $pane="Scheduling"#-->
<!--#set global $help_uri="configure-scheduling-0-8"#-->
<!--#set global $help_uri="configure-scheduling-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<%
@@ -17,7 +17,7 @@ else:
<div class="col2">
<h3>$T('addSchedule') <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
</div><!-- /col2 -->
<form action="addSchedule" method="post">
<form action="addSchedule" method="post" autocomplete="off">
<input type="hidden" id="session" name="session" value="$session" />
<div class="col1">
<fieldset>
@@ -48,12 +48,20 @@ else:
<div class="field-pair">
<label class="config" for="action">$T('sch-action')</label>
<select name="action" id="action">
<!--#for $action in $actions#-->
<option value="$action">$actions_lng[$action]</option>
<!--#end for#-->
<optgroup label="$T('sch-action')">
<!--#for $action in $actions#-->
<option value="$action" data-action="" data-noarg="<!--#if $action is 'speedlimit' then 0 else 1#-->">$actions_lng[$action]</option>
<!--#end for#-->
</optgroup>
<optgroup label="$T('cmenu-servers')">
<!--#for $server in $actions_servers.keys()#-->
<option value="$server" data-action="1"data-noarg="1">$T('sch-enable_server') "$actions_servers[$server]"</option>
<option value="$server" data-action="0"data-noarg="1">$T('sch-disable_server') "$actions_servers[$server]"</option>
<!--#end for#-->
</optgroup>
</select>
</div>
<div class="field-pair">
<div class="field-pair" id="hidden_arguments" style="display: none">
<label class="config" for="arguments">$T('sch-arguments')</label>
<input type="text" name="arguments" id="arguments" class="select_width" />
</div>
@@ -97,5 +105,16 @@ else:
</div><!-- /col1 -->
</div><!-- /section -->
</div><!-- /colmask -->
<script type="text/javascript">
\$('#action').on('change', function() {
// Set the action
\$('#arguments').val((\$(this).find('option:selected').data('action')))
// Arguments
if(\$(this).find('option:selected').data('noarg')) {
\$('#hidden_arguments').hide()
} else {
\$('#hidden_arguments').show()
}
})
</script>
<!--#include $webdir + "/_inc_footer_uc.tmpl"#-->

View File

@@ -1,5 +1,5 @@
<!--#set global $pane="Servers"#-->
<!--#set global $help_uri="configure-servers-0-8"#-->
<!--#set global $help_uri="configure-servers-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
@@ -62,6 +62,7 @@
<label class="config" for="ssl_type">$T('srv-ssl_type')</label>
<!--#if int($have_ssl) == 1#-->
<select name="ssl_type" id="ssl_type">
<option value="">$T('Default')</option>
<!--#if 't12' in $ssl_protocols#-->
<option value="t12">TLS v1.2</option>
<!--#end if#-->
@@ -71,9 +72,6 @@
<!--#if 't1' in $ssl_protocols#-->
<option value="t1">TLS v1</option>
<!--#end if#-->
<!--#if 'v23' in $ssl_protocols#-->
<option value="v23">SSL v23</option>
<!--#end if#-->
<!--#if 'v3' in $ssl_protocols#-->
<option value="v3">SSL v3</option>
<!--#end if#-->
@@ -98,7 +96,9 @@
<label class="config" for="categories">$T('srv-categories')</label>
<select name="categories" id="categories" multiple>
<!--#for $cat in $cats#-->
<option value="$cat" <!--#if $cat == "Default"#-->selected<!--#end if#-->>$cat</option>
<option value="$cat" <!--#if $cat == "Default"#-->selected<!--#end if#-->>
<!--#if $cat == "Default" then $T('Default') else $cat#-->
</option>
<!--#end for#-->
</select>
<span class="desc">$T('srv-explain-categories')</span>
@@ -118,24 +118,25 @@
</fieldset>
</div><!-- /col1 -->
</div><!-- /section -->
</form>
</form>
<!--#set $cur = 0#-->
<!--#for $server in $servers#-->
<!--#set $cur = $cur + 1#-->
<form action="saveServer" method="post" class="fullform" novalidate>
<form action="saveServer" method="post" class="fullform" autocomplete="off" novalidate>
<input type="hidden" name="session" value="$session" />
<input type="hidden" name="server" value="$server['name']" />
<div class="section">
<div class="col2">
<div class="section <!--#if int($server['enable']) == 0 then 'server-disabled' else ""#-->">
<div class="col2 <!--#if int($server['enable']) == 0 then 'server-disabled' else ""#-->">
<h3>$server['displayname'] <a href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
<span class="label label-primary" data-priority="$server['priority']">$server['priority']</span>
<span class="label label-primary" data-priority="$server['priority']">$T('srv-priority'):</span>
<!--#if int($server['enable']) != 0#-->
<span class="label label-primary" data-priority="$server['priority']#-->">$server['priority']</span>
<span class="label label-primary" data-priority="$server['priority']#-->">$T('srv-priority'):</span>
<!--#end if#-->
<table><tr>
<td><input type="checkbox" class="toggleServerCheckbox" id="enable_$cur" rel="$server['name']" name="q_enable" value="1" <!--#if int($server['enable']) != 0 then 'checked="checked"' else ""#--> /></td>
<td><input type="checkbox" class="toggleServerCheckbox" id="enable_$cur" name="$server['name']" value="1" <!--#if int($server['enable']) != 0 then 'checked="checked"' else ""#--> /></td>
<td><label for="enable_$cur">$T('enabled')</label></td>
</tr></table>
@@ -186,6 +187,7 @@
<label class="config" for="ssl_type$cur">$T('srv-ssl_type')</label>
<!--#if int($have_ssl) == 1#-->
<select name="ssl_type" id="ssl_type$cur">
<option value="" <!--#if $server['ssl_type'] == "" then 'selected="selected"' else ""#--> >$T('Default')</option>
<!--#if 't12' in $ssl_protocols#-->
<option value="t12" <!--#if $server['ssl_type'] == "t12" then 'selected="selected"' else ""#--> >TLS v1.2</option>
<!--#end if#-->
@@ -195,9 +197,6 @@
<!--#if 't1' in $ssl_protocols#-->
<option value="t1" <!--#if $server['ssl_type'] == "t1" then 'selected="selected"' else ""#--> >TLS v1</option>
<!--#end if#-->
<!--#if 'v23' in $ssl_protocols#-->
<option value="v23" <!--#if $server['ssl_type'] == "v23" then 'selected="selected"' else ""#--> >SSL v23</option>
<!--#end if#-->
<!--#if 'v3' in $ssl_protocols#-->
<option value="v3" <!--#if $server['ssl_type'] == "v3" then 'selected="selected"' else ""#--> >SSL v3</option>
<!--#end if#-->
@@ -222,7 +221,9 @@
<label class="config" for="categories$cur">$T('srv-categories')</label>
<select name="categories" id="categories$cur" multiple>
<!--#for $cat in $cats#-->
<option value="$cat" <!--#if $cat in $server['categories'] then 'selected' else ""#-->>$cat</option>
<option value="$cat" <!--#if $cat in $server['categories'] then 'selected' else ""#-->>
<!--#if $cat == "Default" then $T('Default') else $cat#-->
</option>
<!--#end for#-->
</select>
<span class="desc">$T('srv-explain-categories')</span>
@@ -285,15 +286,13 @@
\$(this).css('background-color', theColor)
})
/**
High-light disabled servers
**/
\$('.toggleServerCheckbox:not(:checked)').parents('.col2').addClass('server-disabled').find('.label').css('background-color', '#777')
/**
Click events
**/
\$('.showserver').click(function () {
if(\$(this).parent().hasClass('server-disabled')) {
\$(this).parent().parent().toggleClass('server-disabled')
}
\$(this).parent().next().toggle();
\$(this).parent().next().next().toggle();
if (\$(this).attr("value") == "$T('showDetails')") {
@@ -324,7 +323,7 @@
// Let us leave!
formWasSubmitted = true;
formHasChanged = false;
location.reload();
setTimeout(function() { location.reload(); }, 100)
}
return false;
});
@@ -334,12 +333,12 @@
// Let us leave!
formWasSubmitted = true;
formHasChanged = false;
location.reload();
setTimeout(function() { location.reload(); }, 100)
}
return false;
});
\$('.toggleServerCheckbox').click(function(){
var whichServer = \$(this).attr("rel");
var whichServer = \$(this).attr("name");
\$.ajax({
type: "POST",
url: "toggleServer",
@@ -348,7 +347,7 @@
// Let us leave!
formWasSubmitted = true;
formHasChanged = false;
location.reload();
setTimeout(function() { location.reload(); }, 100)
});
});
});

View File

@@ -1,9 +1,9 @@
<!--#set global $pane="Sorting"#-->
<!--#set global $help_uri="configure-sorting-0-7"#-->
<!--#set global $help_uri="configure-sorting-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveSorting" method="post" name="fullform" class="fullform">
<form action="saveSorting" method="post" name="fullform" class="fullform" autocomplete="off">
<input type="hidden" id="session" name="session" value="$session" />
<input id="complete_dir" type="hidden" value="$complete_dir" />
<div class="section">

View File

@@ -1,9 +1,9 @@
<!--#set global $pane="Special"#-->
<!--#set global $help_uri="configure-special-0-8"#-->
<!--#set global $help_uri="configure-special-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveSpecial" method="post" name="fullform" class="fullform">
<form action="saveSpecial" method="post" autocomplete="off">
<input type="hidden" id="session" name="session" value="$session" />
<div class="padTable">
<h4 class="darkred nomargin">$T('explain-special')</h4>

View File

@@ -1,9 +1,9 @@
<!--#set global $pane="Switches"#-->
<!--#set global $help_uri="configure-switches-0-8"#-->
<!--#set global $help_uri="configure-switches-1-0"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveSwitches" method="post" name="fullform" class="fullform">
<form action="saveSwitches" method="post" name="fullform" class="fullform" autocomplete="off">
<input type="hidden" id="session" name="session" value="$session" />
<div class="section">
<div class="col2">
@@ -11,6 +11,11 @@
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair">
<label class="config" for="auto_browser">$T('opt-auto_browser')</label>
<input type="checkbox" name="auto_browser" id="auto_browser" value="1" <!--#if int($auto_browser) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-auto_browser')</span>
</div>
<div class="field-pair">
<label class="config" for="check_new_rel">$T('opt-check_new_rel')</label>
<select name="check_new_rel" id="check_new_rel">
@@ -20,11 +25,6 @@
</select>
<span class="desc">$T('explain-check_new_rel')</span>
</div>
<div class="field-pair">
<label class="config" for="auto_browser">$T('opt-auto_browser')</label>
<input type="checkbox" name="auto_browser" id="auto_browser" value="1" <!--#if int($auto_browser) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-auto_browser')</span>
</div>
<div class="field-pair <!--#if not $have_ampm then "disabled" else "" #-->">
<label class="config" for="ampm">$T('opt-ampm')</label>
<input type="checkbox" name="ampm" id="ampm" value="1" <!--#if int($ampm) > 0 then 'checked="checked"' else ""#--> <!--#if not $have_ampm then 'readonly="readonly" disabled="disabled"' else "" #--> />
@@ -79,15 +79,33 @@
<div class="col1">
<fieldset>
<div class="field-pair">
<label class="config" for="fail_hopeless">$T('opt-fail_hopeless')</label>
<input type="checkbox" name="fail_hopeless" id="fail_hopeless" value="1" <!--#if int($fail_hopeless) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-fail_hopeless')</span>
<label class="config" for="pre_script">$T('opt-pre_script')</label>
<select name="pre_script" id="pre_script">
<!--#for $sc in $script_list#-->
<!--#if $sc.lower() == $pre_script.lower()#-->
<option value="$sc" selected="selected">$Tspec($sc)</option>
<!--#else#-->
<option value="$sc">$Tspec($sc)</option>
<!--#end if#-->
<!--#end for#-->
</select>
<span class="desc">$T('explain-pre_script')</span>
</div>
<div class="field-pair">
<label class="config" for="top_only">$T('opt-top_only')</label>
<input type="checkbox" name="top_only" id="top_only" value="1" <!--#if int($top_only) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-top_only')</span>
</div>
<div class="field-pair">
<label class="config" for="pre_check">$T('opt-pre_check')</label>
<input type="checkbox" name="pre_check" id="pre_check" value="1" <!--#if int($pre_check) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-pre_check')</span>
</div>
<div class="field-pair">
<label class="config" for="fail_hopeless">$T('opt-fail_hopeless')</label>
<input type="checkbox" name="fail_hopeless" id="fail_hopeless" value="1" <!--#if int($fail_hopeless) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-fail_hopeless')</span>
</div>
<div class="field-pair">
<label class="config" for="no_dupes">$T('opt-no_dupes')</label>
<select name="no_dupes" id="no_dupes">
@@ -106,11 +124,6 @@
</select>
<span class="desc">$T('explain-no_series_dupes')</span>
</div>
<div class="field-pair">
<label class="config" for="pause_on_post_processing">$T('opt-pause_on_post_processing')</label>
<input type="checkbox" name="pause_on_post_processing" id="pause_on_post_processing" value="1" <!--#if int($pause_on_post_processing) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-pause_on_post_processing')</span>
</div>
<div class="field-pair">
<label class="config" for="pause_on_pwrar">$T('opt-pause_on_pwrar')</label>
<select name="pause_on_pwrar" id="pause_on_pwrar">
@@ -134,29 +147,12 @@
<input type="text" name="unwanted_extensions" id="unwanted_extensions" value="$unwanted_extensions"/>
<span class="desc">$T('explain-unwanted_extensions')</span>
</div>
<div class="field-pair">
<label class="config" for="top_only">$T('opt-top_only')</label>
<input type="checkbox" name="top_only" id="top_only" value="1" <!--#if int($top_only) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-top_only')</span>
</div>
<div class="field-pair">
<label class="config" for="auto_sort">$T('opt-auto_sort')</label>
<input type="checkbox" name="auto_sort" id="auto_sort" value="1" <!--#if int($auto_sort) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-auto_sort')</span>
</div>
<div class="field-pair">
<label class="config" for="pre_script">$T('opt-pre_script')</label>
<select name="pre_script" id="pre_script">
<!--#for $sc in $script_list#-->
<!--#if $sc.lower() == $pre_script.lower()#-->
<option value="$sc" selected="selected">$Tspec($sc)</option>
<!--#else#-->
<option value="$sc">$Tspec($sc)</option>
<!--#end if#-->
<!--#end for#-->
</select>
<span class="desc">$T('explain-pre_script')</span>
</div>
<div class="field-pair">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
</div>
@@ -170,22 +166,39 @@
<div class="col1">
<fieldset>
<div class="field-pair">
<label class="config" for="ignore_samples">$T('opt-ignore_samples')</label>
<select name="ignore_samples" id="ignore_samples">
<option value="0" <!--#if int($ignore_samples) == 0 then 'selected="selected"' else ""#--> >$T('igsam-off')</option>
<option value="1" <!--#if int($ignore_samples) == 1 then 'selected="selected"' else ""#--> >$T('igsam-del')</option>
</select>
<span class="desc">$T('explain-ignore_samples')</span>
<label class="config" for="pause_on_post_processing">$T('opt-pause_on_post_processing')</label>
<input type="checkbox" name="pause_on_post_processing" id="pause_on_post_processing" value="1" <!--#if int($pause_on_post_processing) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-pause_on_post_processing')</span>
</div>
<div class="field-pair">
<label class="config" for="enable_all_par">$T('opt-enable_all_par')</label>
<input type="checkbox" name="enable_all_par" id="enable_all_par" value="1" <!--#if int($enable_all_par) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-enable_all_par')</span>
</div>
<div class="field-pair">
<label class="config" for="quick_check">$T('opt-quick_check')</label>
<input type="checkbox" name="quick_check" id="quick_check" value="1" <!--#if int($quick_check) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-quick_check')</span>
</div>
<div class="field-pair <!--#if not $have_multicore then "disabled" else "" #-->">
<label class="config" for="par2_multicore">$T('opt-par2_multicore')</label>
<input type="checkbox" name="par2_multicore" id="par2_multicore" value="1" <!--#if int($par2_multicore) > 0 then 'checked="checked"' else ""#--> <!--#if not $have_multicore then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-par2_multicore')</span>
</div>
<div class="field-pair">
<label class="config" for="enable_all_par">$T('opt-enable_all_par')</label>
<input type="checkbox" name="enable_all_par" id="enable_all_par" value="1" <!--#if int($enable_all_par) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-enable_all_par')</span>
<label class="config" for="par_option">$T('opt-par_option')</label>
<input type="text" name="par_option" id="par_option" value="$par_option" />
<span class="desc">$T('explain-par_option')</span>
</div>
<div class="field-pair">
<label class="config" for="sfv_check">$T('opt-sfv_check')</label>
<input type="checkbox" name="sfv_check" id="sfv_check" value="1" <!--#if int($sfv_check) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-sfv_check')</span>
</div>
<div class="field-pair">
<label class="config" for="safe_postproc">$T('opt-safe_postproc')</label>
<input type="checkbox" name="safe_postproc" id="safe_postproc" value="1" <!--#if int($safe_postproc) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-safe_postproc')</span>
</div>
<div class="field-pair <!--#if not $have_unrar then "disabled" else "" #-->">
<label class="config" for="enable_unrar">$T('opt-enable_unrar')</label>
@@ -227,21 +240,12 @@
<input type="checkbox" name="enable_tsjoin" id="enable_tsjoin" value="1" <!--#if int($enable_tsjoin) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-ts_join')</span>
</div>
<div class="field-pair">
<label class="config" for="safe_postproc">$T('opt-safe_postproc')</label>
<input type="checkbox" name="safe_postproc" id="safe_postproc" value="1" <!--#if int($safe_postproc) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-safe_postproc')</span>
</div>
<div class="field-pair">
<label class="config" for="sfv_check">$T('opt-sfv_check')</label>
<input type="checkbox" name="sfv_check" id="sfv_check" value="1" <!--#if int($sfv_check) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-sfv_check')</span>
</div>
<div class="field-pair">
<label class="config" for="unpack_check">$T('opt-unpack_check')</label>
<input type="checkbox" name="unpack_check" id="unpack_check" value="1" <!--#if int($unpack_check) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-unpack_check')</span>
</div>
<div class="field-pair">
<label class="config" for="script_can_fail">$T('opt-script_can_fail')</label>
<input type="checkbox" name="script_can_fail" id="script_can_fail" value="1" <!--#if int($script_can_fail) > 0 then 'checked="checked"' else ""#--> />
@@ -252,16 +256,7 @@
<input type="checkbox" name="new_nzb_on_failure" id="new_nzb_on_failure" value="1" <!--#if int($new_nzb_on_failure) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-new_nzb_on_failure')</span>
</div>
<div class="field-pair <!--#if not $have_multicore then "disabled" else "" #-->">
<label class="config" for="par2_multicore">$T('opt-par2_multicore')</label>
<input type="checkbox" name="par2_multicore" id="par2_multicore" value="1" <!--#if int($par2_multicore) > 0 then 'checked="checked"' else ""#--> <!--#if not $have_multicore then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-par2_multicore')</span>
</div>
<div class="field-pair">
<label class="config" for="par_option">$T('opt-par_option')</label>
<input type="text" name="par_option" id="par_option" value="$par_option" />
<span class="desc">$T('explain-par_option')</span>
</div>
<!--#if not $nt#-->
<div class="field-pair <!--#if not $have_nice then "disabled" else "" #-->">
<label class="config" for="nice">$T('opt-nice')</label>
<input type="text" name="nice" id="nice" value="$nice" <!--#if not $have_nice then 'readonly="readonly" disabled="disabled"' else "" #--> />
@@ -272,6 +267,12 @@
<input type="text" name="ionice" id="ionice" value="$ionice" <!--#if not $have_ionice then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-ionice')</span>
</div>
<!--#end if#-->
<div class="field-pair">
<label class="config" for="ignore_samples">$T('opt-ignore_samples')</label>
<input type="checkbox" name="ignore_samples" id="ignore_samples" value="1" <!--#if int($ignore_samples) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-ignore_samples') $T('igsam-del').</span>
</div>
<div class="field-pair">
<label class="config" for="cleanup_list">$T('opt-cleanup_list')</label>
<input type="text" name="cleanup_list" id="cleanup_list" value="$cleanup_list"/>

View File

@@ -262,6 +262,9 @@ textarea:hover, input[type="date"]:hover, input[type="datetime"]:hover, input[ty
.padTable h3 {
margin-top: 0;
}
tr.separator {
height: 30px;
}
.catTable th, .catTable td {
padding: 5px;
}
@@ -284,6 +287,28 @@ textarea:hover, input[type="date"]:hover, input[type="datetime"]:hover, input[ty
.RSS form[action="add_rss_feed"] tr:nth-child(even) {
border: 1px solid #E5E5E5;
}
.Config .table {
margin: 0;
border: 1px solid #ddd
}
.Config .colmask {
margin-bottom: 12px;
}
.Config .padding {
padding: 13px;
}
.Config th {
width: 20%;
min-width: 150px;
padding-left: 15px !important;
}
.Config .label {
font-size: 90%;
}
.Config td .glyphicon-question-sign {
color: black !important;
top: 3px;
}
.tab-pane thead tr {
background-color: transparent !important;
}
@@ -715,6 +740,7 @@ input[type="text"].smaller_input {
select {
min-width: 200px;
max-width: 300px;
}
input[disabled],
@@ -801,6 +827,10 @@ input[type="checkbox"] {
display: none;
}
#navbar .glyphicon-folder-open {
margin-right: 2px;
}
.rss-icon-svg {
display: inline-block;
margin-top: 1px;
@@ -824,6 +854,10 @@ input[type="checkbox"] {
line-height: 1.1em;
}
.Servers .col2.server-disabled .label {
color: ##777 !important;
}
.Servers .col2 .label:nth-child(2) {
opacity: 0.7;
}

View File

@@ -50,7 +50,7 @@
</a>
<div class="dropdown-menu max-speed-input">
<div data-bind="visible: !bandwithLimit()">
<a href="config/general/#bandwidth_max">
<a href="./config/general/#bandwidth_max">
<span class="glyphicon glyphicon-cog"></span> $T('Glitter-setMaxLinespeed')
</a>
</div>
@@ -70,7 +70,7 @@
</li>
<!--#if $have_rss_defined#-->
<li data-tooltip="true" data-placement="bottom" title="$T('cmenu-rss')">
<a href="config/rss">
<a href="./config/rss/">
<svg class="rss-icon-svg" viewBox="0 0 8 8">
<rect class="rss-button" width="8" height="8" />
<circle class="rss-symbol" cx="2" cy="6" r="1" />
@@ -81,7 +81,7 @@
</li>
<!--#end if#-->
<li data-tooltip="true" data-placement="bottom" title="SABnzbd $T('menu-config')">
<a href="config"><span class="glyphicon glyphicon-cog"></span></a>
<a href="./config/"><span class="glyphicon glyphicon-cog"></span></a>
</li>
<li class="dropdown main-menu-link" data-bind="css: { 'active-on-queue-finish-menu': onQueueFinish()}">
<a href="#" data-toggle="dropdown" onclick="keepOpen(this)">
@@ -97,7 +97,7 @@
<!--#if $have_watched_dir#--><li><a href="#" data-bind="click: doQueueAction" data-mode="watched_now">$T('sch-scan_folder')</a></li><!--#end if#-->
<!--#if $pp_pause_event#--><li><a href="#" data-bind="click: doQueueAction" data-mode="resume_pp">$T('sch-resume_post')</a></li><!--#end if#-->
<li class="divider"></li>
<li><a href="shutdown?session=$session" data-bind="click: shutdownSAB">$T('shutdownSab')</a></li>
<li><a href="./shutdown/?session=$session" data-bind="click: shutdownSAB">$T('shutdownSab')</a></li>
<li><a href="#" data-bind="click: restartSAB">$T('Glitter-restartSab')</a></li>
<li class="divider"></li>
<li class="dropdown-header"><span class="glyphicon glyphicon-off"></span> $T('Glitter-onFinish'):</li>

View File

@@ -65,12 +65,21 @@
<div class="col-sm-6">$T('dashboard-NameserverDNS')</div>
<div class="col-sm-6" data-bind="text: !statusInfo.dashboard.dnslookup() ? '$T('dashboard-connectionError')' : statusInfo.dashboard.dnslookup(), css: { 'options-bad-status' : (statusInfo.dashboard.dnslookup() != 'OK') }"></div>
</div>
<hr/>
<div class="row">
<div class="col-sm-6">$T('dashboard-systemPerformance')</div>
<div class="col-sm-6">
<span data-bind="text: statusInfo.dashboard.pystone"></span>
<a href="#" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<small data-bind="truncatedText: statusInfo.dashboard.cpumodel, length: 25"></small>
</div>
</div>
<div class="row">
<div class="col-sm-6">$T('dashboard-downloadDirSpeed')</div>
<div class="col-sm-6">
<span data-bind="text: (statusInfo.dashboard.downloaddirspeed() > 0 ? statusInfo.dashboard.downloaddirspeed() : '0'), css: { 'options-bad-status' : statusInfo.dashboard.downloaddirspeedbad() }"></span> MB/s
<a href="#" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<small>(<span data-bind="truncatedText: statusInfo.dashboard.downloaddir, length: 25"></span>)</small>
<small>(<span data-bind="truncatedText: statusInfo.dashboard.downloaddir, length: 24"></span>)</small>
</div>
</div>
<div class="row">
@@ -78,7 +87,7 @@
<div class="col-sm-6">
<span data-bind="text: (statusInfo.dashboard.completedirspeed() > 0 ? statusInfo.dashboard.completedirspeed() : '0'), css: { 'options-bad-status' : statusInfo.dashboard.completedirspeedbad() }"></span> MB/s
<a href="#" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<small>(<span data-bind="truncatedText: statusInfo.dashboard.completedir, length: 25"></span>)</small>
<small>(<span data-bind="truncatedText: statusInfo.dashboard.completedir, length: 24"></span>)</small>
</div>
</div>
<div class="row">
@@ -100,7 +109,7 @@
</div>
<div class="row options-function-box">
<div class="col-sm-6">
<a href="status/showlog?session=$session" target="_blank" class="btn btn-default"><span class="glyphicon glyphicon-file"></span> $T('link-showLog')</a>
<a href="./status/showlog?session=$session" target="_blank" class="btn btn-default"><span class="glyphicon glyphicon-file"></span> $T('link-showLog')</a>
</div>
<div class="col-sm-6">
<div class="input-group" data-tooltip="true" data-placement="top" title="$T('logging')">
@@ -128,12 +137,20 @@
</div>
<div data-bind="foreach: statusInfo.status.servers">
<div class="options-server-box">
<a href="#" data-bind="visible: serverblocked(), click: function() { \$parent.unblockServer(servername()) }" class="btn btn-default">$T('Glitter-unblockServer')</a>
<div class="row">
<div class="col-sm-6">$T('swtag-server')</div>
<div class="col-sm-6">
<span data-bind="text: servername"></span><br />
<span data-bind="visible: serverblocked(), text: serverblocked" class="label label-danger"></span>
<span data-bind="text: servername"></span>
</div>
</div>
<div class="row" data-bind="visible: serverblocked()">
<div class="col-sm-12">
<div class="alert alert-danger">
<a href="#" data-bind="visible: serverblocked(), click: function() { \$parent.unblockServer(servername()) }" class="btn btn-default"><span class="glyphicon glyphicon-share-alt"></span> $T('Glitter-unblockServer')</a>
<span data-bind="text: serverblocked()"></span>
</div>
</div>
</div>
<div class="row">
@@ -242,7 +259,7 @@
<option value="40">40 / $T('Glitter-page')</option>
<option value="50">50 / $T('Glitter-page')</option>
<option value="100">100 / $T('Glitter-page')</option>
<option value="9999999">$T('Glitter-everything')</option>
<option value="250">250 / $T('Glitter-page')</option>
</select>
</div>
</div>
@@ -257,7 +274,7 @@
<option value="40">40 / $T('Glitter-page')</option>
<option value="50">50 / $T('Glitter-page')</option>
<option value="100">100 / $T('Glitter-page')</option>
<option value="9999999">$T('Glitter-everything')</option>
<option value="250">250 / $T('Glitter-page')</option>
</select>
</div>
</div>
@@ -362,7 +379,7 @@
<div class="row form-horizontal">
<label class="col-sm-6 control-label">$T('Glitter-addnzbFilename')</label>
<div class="col-sm-6">
<input type="text" name="nzbname" id="nzbname" placeholder="$T('nzo-filename')" class="form-control" />
<input type="text" name="nzbname" id="nzbname" placeholder="$T('name')" class="form-control" />
</div>
</div>
<hr />
@@ -479,7 +496,7 @@
<span class="input-group-addon">
<span class="glyphicon glyphicon-lock"></span>
</span>
<input type="text" class="form-control" id="retry_job_password" placeholder="$T('srv-password')" />
<input type="text" class="form-control" id="retry_job_password" placeholder="$T('srv-password') ($T('srv-optional'))" />
</div>
</div>
</fieldset>

View File

@@ -2,9 +2,6 @@
<h2>$T('menu-queue')</h2>
<div class="info-container" data-bind="visible: diskSpaceLeft1()" style="display: none;">
<div class="info-container-box" id="localstorage-error">
<span class="queue-error-info"></span>
</div>
<!-- ko if: hasWarnings() -->
<div class="info-container-box">
<a href="#queue-messages" class="queue-error-info">
@@ -97,8 +94,8 @@
<input type="text" data-bind="value: nameForEdit, visible: editingName(), hasfocus: editingName" />
</form>
<div class="name-options" data-bind="visible: !editingName()">
<a href="#" data-bind="click: editName" class="hover-button"><span class="glyphicon glyphicon-pencil"></span></a>
<a href="#" data-bind="click: showFiles" class="hover-button" title="$T('nzoDetails') - $T('srv-password')"><span class="glyphicon glyphicon-folder-open"></span></a>
<a href="#" data-bind="click: editName, css: { disabled: isGrabbing() }" class="hover-button"><span class="glyphicon glyphicon-pencil"></span></a>
<a href="#" data-bind="click: showFiles, css: { disabled: isGrabbing() }" class="hover-button" title="$T('nzoDetails') - $T('srv-password')"><span class="glyphicon glyphicon-folder-open"></span></a>
<small data-bind="text: avg_age"></small>
</div>
</td>

View File

@@ -21,7 +21,9 @@
<meta name="application-name" content="SABnzbd">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="SABnzbd" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-status-bar-style" content="#000000" />
<meta name="msapplication-navbutton-color" content="#000000" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" sizes="76x76" href="./staticcfg/ico/apple-touch-icon-76x76-precomposed.png" />
<link rel="apple-touch-icon" sizes="120x120" href="./staticcfg/ico/apple-touch-icon-120x120-precomposed.png" />
@@ -59,7 +61,6 @@
glitterTranslate.repair = "$T('explain-Repair')".replace(/<br \/>/g, "\n");
glitterTranslate.removeDown = "$T('Glitter-confirmClearDownloads')";
glitterTranslate.removeDow1 = "$T('Glitter-confirmClear1Download')";
glitterTranslate.grabbing = "$T('Glitter-grabbing')";
glitterTranslate.encrypted = "$T('Glitter-encrypted')";
glitterTranslate.duplicate = "$T('Glitter-duplicate')";
glitterTranslate.tooLarge = "$T('Glitter-tooLarge')";
@@ -74,6 +75,7 @@
glitterTranslate.chooseFile = "$T('Glitter-chooseFile')";
glitterTranslate.orphanedJobsMsg = "$T('explain-orphans')";
glitterTranslate.useCache = "$T('explain-cache_limitstr')";
glitterTranslate.noLocalStorage = "$T('Glitter-noLocalStorage')";
glitterTranslate.updateAvailable = "$T('Glitter-updateAvailable')";
glitterTranslate.defaultText = "$T('default')";
glitterTranslate.noneText = "$T('None')";
@@ -98,6 +100,7 @@
glitterTranslate.status['Script'] = "$T('stage-script')";
glitterTranslate.status['Source'] = "$T('stage-source')";
glitterTranslate.status['Servers'] = "$T('stage-servers')";
glitterTranslate.status['INFO'] = "$T('log-info')".replace('+ ', '').toUpperCase();
glitterTranslate.status['WARNING'] = "$T('Glitter-warning')";
glitterTranslate.status['ERROR'] = "$T('Glitter-error')";

View File

@@ -11,8 +11,9 @@ var fadeOnDeleteDuration = 400; // ms after deleting a row
var isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
// To avoid problems when localStorage is disabled
function localStorageSetItem(varToSet, valueToSet) { try { return localStorage.setItem(varToSet, valueToSet); } catch(e) { $('#localstorage-error span').text('Cannot store settings locally'); } }
function localStorageGetItem(varToGet) { try { return localStorage.getItem(varToGet); } catch(e) { $('#localstorage-error span').text('Cannot store settings locally'); } }
var hasLocalStorage = true;
function localStorageSetItem(varToSet, valueToSet) { try { return localStorage.setItem(varToSet, valueToSet); } catch(e) { hasLocalStorage = false; } }
function localStorageGetItem(varToGet) { try { return localStorage.getItem(varToGet); } catch(e) { hasLocalStorage = false; } }
/**
GLITTER CODE
@@ -166,15 +167,15 @@ $(function() {
var bandwithLimitText = self.bandwithLimit().replace(/[^a-zA-Z]+/g, '');
// Only the number
var speedLimitNumber = (parseInt(self.bandwithLimit()) * (self.speedLimit() / 100));
var speedLimitNumberFull = (parseFloat(self.bandwithLimit()) * (self.speedLimit() / 100));
// Trick to only get decimal-point when needed
speedLimitNumber = Math.round(speedLimitNumber*10)/10;
var speedLimitNumber = Math.round(speedLimitNumberFull*10)/10;
// Fix it for lower than 1MB/s
if(bandwithLimitText == 'M' && speedLimitNumber < 1) {
bandwithLimitText = 'K';
speedLimitNumber = Math.round(speedLimitNumber * 1024);
speedLimitNumber = Math.round(speedLimitNumberFull * 1024);
}
// Show text
@@ -506,6 +507,12 @@ $(function() {
// Update on changes
self.pauseCustom.subscribe(function(newValue) {
// Is it plain numbers?
if(newValue.match(/^\s*\d+\s*$/)) {
// Treat it as a number of minutes
newValue += " minutes";
}
// At least 3 charaters
if(newValue.length < 3) {
$('#customPauseOutput').text('').data('time', 0)
@@ -593,11 +600,10 @@ $(function() {
});
})
// Clear warnings through this weird URL..
// Clear warnings through this special URL..
self.clearWarnings = function() {
if(!self.confirmDeleteQueue() || confirm(glitterTranslate.clearWarn))
// Activate
callSpecialAPI("./status/clearwarnings").done(self.refresh)
// Activate
callSpecialAPI("./status/clearwarnings/").done(self.refresh)
}
// Clear messages
@@ -637,6 +643,9 @@ $(function() {
// Shutdown options
self.onQueueFinish.subscribe(function(newValue) {
// Ignore updates before the page is done
if(!self.hasStatusInfo()) return;
// Something changes
callAPI({
mode: 'queue',
@@ -680,6 +689,14 @@ $(function() {
// From the upload
self.addNZBFromFileForm = function(form) {
// Anything?
if(!$(form.nzbFile)[0].files[0]) {
$('.btn-file').css('border-color', 'red')
setTimeout(function() { $('.btn-file').css('border-color', '') }, 2000)
return false;
}
// Upload
self.addNZBFromFile($(form.nzbFile)[0].files[0]);
// After that, hide and reset
@@ -690,6 +707,13 @@ $(function() {
}
// From URL
self.addNZBFromURL = function(form) {
// Anything?
if(!$(form.nzbURL).val()) {
$(form.nzbURL).css('border-color', 'red')
setTimeout(function() { $(form.nzbURL).css('border-color', '') }, 2000)
return false;
}
// Add
callAPI({
mode: "addurl",
@@ -737,6 +761,9 @@ $(function() {
// Load status info
self.loadStatusInfo = function(item, event) {
// Hide tooltips (otherwise they stay forever..)
$('#options-status [data-tooltip="true"]').tooltip('hide')
// Reset
self.hasStatusInfo(false)
@@ -758,7 +785,7 @@ $(function() {
// Only now we can subscribe to the log-level-changes!
self.statusInfo.status.loglevel.subscribe(function(newValue) {
// Update log-level
callSpecialAPI('./status/change_loglevel', {
callSpecialAPI('./status/change_loglevel/', {
loglevel: newValue
});
})
@@ -778,14 +805,14 @@ $(function() {
// Hide before running the test
self.hasStatusInfo(false)
// Run it and then display it
callSpecialAPI('./status/dashrefresh').then(function() {
callSpecialAPI('./status/dashrefresh/').then(function() {
self.loadStatusInfo(true, true)
})
}
// Unblock server
self.unblockServer = function(servername) {
callSpecialAPI("./status/unblock_server", {
callSpecialAPI("./status/unblock_server/", {
server: servername
}).then(function() {
$("#modal-options").modal("hide");
@@ -812,7 +839,7 @@ $(function() {
self.removeAllOrphaned = function() {
if(!self.confirmDeleteHistory() || confirm(glitterTranslate.clearWarn)) {
// Delete them all
callSpecialAPI("./status/delete_all").then(self.loadStatusInfo)
callSpecialAPI("./status/delete_all/").then(self.loadStatusInfo)
}
}
@@ -827,7 +854,7 @@ $(function() {
self.restartSAB = function() {
if(!confirm(glitterTranslate.restart)) return;
// Call restart function
callSpecialAPI("./config/restart")
callSpecialAPI("./config/restart/")
// Set counter, we need at least 15 seconds
self.isRestarting(Math.max(1, Math.floor(15 / self.refreshRate())));
@@ -844,13 +871,13 @@ $(function() {
// Repair queue
self.repairQueue = function() {
if(!confirm(glitterTranslate.repair)) return;
callSpecialAPI("./config/repair").then(function() {
callSpecialAPI("./config/repair/").then(function() {
$("#modal-options").modal("hide");
})
}
// Force disconnect
self.forceDisconnect = function() {
callSpecialAPI("./status/disconnect").then(function() {
callSpecialAPI("./status/disconnect/").then(function() {
$("#modal-options").modal("hide");
})
}
@@ -886,7 +913,7 @@ $(function() {
if(newRelease) {
self.allMessages.push({
index: 'UpdateMsg',
type: 'INFO',
type: glitterTranslate.status['INFO'],
text: ('<a class="queue-update-sab" href="'+newReleaseUrl+'" target="_blank">'+glitterTranslate.updateAvailable+' '+newRelease+' <span class="glyphicon glyphicon-save"></span></a>'),
css: 'info'
});
@@ -896,7 +923,7 @@ $(function() {
if(!response.config.misc.cache_limit && localStorageGetItem('CacheMsg')*1+(1000*3600*24*5) < Date.now()) {
self.allMessages.push({
index: 'CacheMsg',
type: 'INFO',
type: glitterTranslate.status['INFO'],
text: ('<a href="./config/general/#cache_limit">'+glitterTranslate.useCache.replace(/<br \/>/g, " ")+' <span class="glyphicon glyphicon-cog"></span></a>'),
css: 'info',
clear: function() { self.clearMessages('CacheMsg')}
@@ -908,7 +935,7 @@ $(function() {
var orphanMsg = localStorageGetItem('OrphanedMsg')*1+(1000*3600*24*5) < Date.now();
// Delay the check
if(orphanMsg) {
setTimeout(self.loadStatusInfo, 2000);
setTimeout(self.loadStatusInfo, 200);
}
// On any status load we check Orphaned folders
@@ -922,8 +949,8 @@ $(function() {
if(!ko.utils.arrayFirst(self.allMessages(), function(item) { return item.index == 'OrphanedMsg' })) {
self.allMessages.push({
index: 'OrphanedMsg',
type: 'INFO',
text: glitterTranslate.orphanedJobsMsg + ' <a href="#" onclick="$(\'a[href=#modal-options]\').click().parent().click(); $(\'a[href=#options-orphans]\').click()"><span class="glyphicon glyphicon-wrench"></span></a>',
type: glitterTranslate.status['INFO'],
text: glitterTranslate.orphanedJobsMsg + ' <a href="#" onclick="showOrphans()"><span class="glyphicon glyphicon-wrench"></span></a>',
css: 'info',
clear: function() { self.clearMessages('OrphanedMsg')}
});
@@ -936,6 +963,17 @@ $(function() {
}
})
// Message about localStorage not being enabled every 20 days
if(!hasLocalStorage && localStorageGetItem('LocalStorageMsg')*1+(1000*3600*24*20) < Date.now()) {
self.allMessages.push({
index: 'LocalStorageMsg',
type: glitterTranslate.status['WARNING'].replace(':', ''),
text: glitterTranslate.noLocalStorage,
css: 'warning',
clear: function() { self.clearMessages('LocalStorageMsg')}
});
}
/***
Date-stuff
***/
@@ -1562,6 +1600,9 @@ $(function() {
// Edit name
self.editName = function(data, event) {
// Not when still grabbing
if(self.isGrabbing()) return false;
// is there a password in there?
var extractOutput = extractTitleAndPassword(self.name())
@@ -1606,6 +1647,8 @@ $(function() {
// See items
self.showFiles = function() {
// Not when still grabbing
if(self.isGrabbing()) return false;
// Trigger update
parent.parent.filelist.loadFiles(self)
}
@@ -2277,7 +2320,7 @@ $(function() {
dataToSend['action_size'] = Math.abs(nrMoves);
// Activate with this weird URL "API"
callSpecialAPI("./nzb/" + self.currentItem.id + "/bulk_operation", dataToSend)
callSpecialAPI("./nzb/" + self.currentItem.id + "/bulk_operation/", dataToSend)
};
// Remove selected files
@@ -2294,7 +2337,7 @@ $(function() {
})
// Activate with this weird URL "API"
callSpecialAPI("./nzb/" + self.currentItem.id + "/bulk_operation", dataToSend).then(function() {
callSpecialAPI("./nzb/" + self.currentItem.id + "/bulk_operation/", dataToSend).then(function() {
// Fade it out
$('.item-files-table input:checked:not(:disabled)').parents('tr').fadeOut(fadeOnDeleteDuration, function() {
// Set state of the check-all
@@ -2306,7 +2349,7 @@ $(function() {
// For changing the passwords
self.setNzbPassword = function() {
// Activate with this weird URL "API"
callSpecialAPI("./nzb/" + self.currentItem.id + "/save", {
callSpecialAPI("./nzb/" + self.currentItem.id + "/save/", {
name: self.modalTitle(),
password: $('#nzb_password').val()
}).then(function() {
@@ -2629,12 +2672,18 @@ function keepOpen(thisItem) {
// Show history details
function showDetails(thisItem) {
// Open the details of this
// Needs timeout, otherwise it thinks its the 'close' click
setTimeout(function() {
// Unfortunatly the .dropdown('toggle') doesn't work in this setup, so work-a-round
// Open the details of this, or close it?
if($(thisItem).parent().find('.delete>.dropdown').hasClass('open')) {
// One click = close
$(thisItem).parent().find('.delete>.dropdown>a').click()
},1)
} else {
// Needs timeout, otherwise it thinks its the 'close' click for some reason
setTimeout(function() {
$(thisItem).parent().find('.delete>.dropdown>a').click()
},1)
}
}
// Check all functionality
@@ -2701,3 +2750,9 @@ function hideCompletedFiles() {
localStorageSetItem('showCompletedFiles', 'Yes')
}
}
// Show status modal and switch to orphaned jobs tab
function showOrphans() {
$('a[href="#modal-options"]').click().parent().click();
$('a[href="#options-orphans"]').click()
}

View File

@@ -810,7 +810,7 @@ tr.queue-item>td:first-child>a {
}
.table-messages .queue-message-text {
word-break: break-all;
word-wrap: break-word;
}
.table-messages .queue-update-sab {
@@ -915,7 +915,7 @@ tr.queue-item>td:first-child>a {
}
.history-status-table .col-sm-10 {
word-break: break-word;
word-wrap: break-word;
}
.history-status-table a {
@@ -1235,9 +1235,11 @@ tr.queue-item>td:first-child>a {
}
#modal-options .options-server-box .btn {
position: absolute;
right: 10px;
z-index:2000;
float: right;
}
#modal-options .options-server-box .alert {
margin-bottom: 5px;
}
#modal-options .options-server-box:last-child {
@@ -1403,6 +1405,11 @@ tr.queue-item>td:first-child>a {
max-width: 100px;
}
.btn-file,
input[name="nzbURL"] {
transition : border 500ms ease-out;
}
/* HELP MODAL */
#modal-help {

View File

@@ -49,6 +49,8 @@
"localipv4": "$localipv4",
"publicipv4": "$publicipv4",
"ipv6": "$ipv6",
"pystone": "$pystone",
"cpumodel": "$cpumodel",
"dnslookup": "$dnslookup",
<!--#set $downloaddir = $downloaddir.replace('\\','\\\\')#-->
"downloaddir": "$downloaddir",

View File

@@ -134,7 +134,7 @@
<tr class="<!--#if $odd then "odd" else "even"#-->">
<td>$T('dashboard-localIP4')</td>
<td>
<!--#if $publicipv4#-->
<!--#if $localipv4#-->
$localipv4
<!--#else#-->
<strong style="color: red;">$T('dashboard-connectionError')</strong>

View File

@@ -12,11 +12,16 @@
[Unit]
Description=SABnzbd binary newsreader
Wants=network-online.target
After=network-online.target
[Service]
ExecStart=/opt/sabnzbd/SABnzbd.py --logging 1 --browser 0
User=%I
Group=%I
Type = simple
Restart = on-failure
[Install]
WantedBy=multi-user.target

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

@@ -108,3 +108,6 @@ msgstr "How long or until when do you want to pause? (in English!)"
msgid "Timeleft"
msgstr "Time left"
#: sabnzbd/skintext.py:791 # sabnzbd/skintext.py:871
msgid "Optionally specify a filename"
msgstr "Optionally specify a name"

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

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

1
portable.cmd Normal file
View File

@@ -0,0 +1 @@
@%~dp0SABnzbd.exe -f %~dp0 %1 %2 %3 %4 %5 %6 %7 %8 %9

View File

@@ -197,9 +197,12 @@ def sig_handler(signum=None, frame=None):
INIT_LOCK = Lock()
def connect_db(thread_index):
def connect_db(thread_index=0):
# Create a connection and store it in the current thread
cherrypy.thread_data.history_db = sabnzbd.database.get_history_handle()
if not (hasattr(cherrypy.thread_data, 'history_db') and cherrypy.thread_data.history_db):
cherrypy.thread_data.history_db = sabnzbd.database.get_history_handle()
return cherrypy.thread_data.history_db
@synchronized(INIT_LOCK)
@@ -271,8 +274,9 @@ def initialize(pause_downloader=False, clean_up=False, evalSched=False, repair=0
sabnzbd.encoding.change_fsys(cfg.fsys_type())
# Set cache limit
if (sabnzbd.WIN32 or sabnzbd.DARWIN) and not cfg.cache_limit():
cfg.cache_limit.set('200M')
if sabnzbd.WIN32 or sabnzbd.DARWIN:
if cfg.cache_limit() == '' or cfg.cache_limit() == '200M':
cfg.cache_limit.set('450M')
ArticleCache.do.new_limit(cfg.cache_limit.get_int())
check_incomplete_vs_complete()
@@ -285,9 +289,7 @@ def initialize(pause_downloader=False, clean_up=False, evalSched=False, repair=0
lang.set_language(cfg.language())
sabnzbd.api.clear_trans_cache()
# Check for old queue (when a new queue is not present)
if not os.path.exists(os.path.join(cfg.admin_dir.get_path(), QUEUE_FILE_NAME)):
OLD_QUEUE = bool(misc.globber(cfg.admin_dir.get_path(), QUEUE_FILE_TMPL % '?'))
OLD_QUEUE = check_old_queue()
sabnzbd.change_queue_complete_action(cfg.queue_complete(), new=False)
@@ -486,18 +488,24 @@ def guard_fsys_type():
""" Callback for change of file system naming type """
sabnzbd.encoding.change_fsys(cfg.fsys_type())
def guard_https_ver():
""" Callback for change of https verification """
def set_https_verification(value):
prev = False
try:
import ssl
if hasattr(ssl, '_create_default_https_context'):
if cfg.enable_https_verification():
prev = ssl._create_default_https_context == ssl.create_default_context
if value:
ssl._create_default_https_context = ssl.create_default_context
else:
ssl._create_default_https_context = ssl._create_unverified_context
except ImportError:
pass
return prev
def guard_https_ver():
""" Callback for change of https verification """
set_https_verification(cfg.enable_https_verification())
def add_url(url, pp=None, script=None, cat=None, priority=None, nzbname=None):
@@ -923,8 +931,7 @@ def remove_data(_id, path):
os.remove(path)
logging.info("%s removed", path)
except:
logging.info("Failed to remove %s", path)
logging.info("Traceback: ", exc_info=True)
logging.debug("Failed to remove %s", path)
@synchronized(IO_LOCK)
@@ -952,7 +959,7 @@ def save_admin(data, _id, do_pickle=True):
@synchronized(IO_LOCK)
def load_admin(_id, remove=False, do_pickle=True):
def load_admin(_id, remove=False, do_pickle=True, silent=False):
""" Read data in admin folder in specified format """
path = os.path.join(cfg.admin_dir.get_path(), _id)
logging.info("Loading data for %s from %s", _id, path)
@@ -972,9 +979,10 @@ def load_admin(_id, remove=False, do_pickle=True):
if remove:
os.remove(path)
except:
excepterror = str(sys.exc_info()[0])
logging.error(T('Loading %s failed with error %s'), path, excepterror)
logging.info("Traceback: ", exc_info=True)
if not silent:
excepterror = str(sys.exc_info()[0])
logging.error(T('Loading %s failed with error %s'), path, excepterror)
logging.info("Traceback: ", exc_info=True)
return None
return data
@@ -1121,6 +1129,24 @@ def wait_for_download_folder():
logging.debug('Waiting for "incomplete" folder')
time.sleep(2.0)
def check_old_queue():
""" Check for old queue (when a new queue is not present) """
old = False
if not os.path.exists(os.path.join(cfg.admin_dir.get_path(), QUEUE_FILE_NAME)):
for ver in (QUEUE_VERSION -1 , QUEUE_VERSION - 2, QUEUE_VERSION - 3):
data = load_admin(QUEUE_FILE_TMPL % str(ver))
if data:
break
try:
old = bool(data and isinstance(data, tuple) and len(data[1]))
except (TypeError, IndexError):
pass
if old and sabnzbd.WIN32 and ver < 10 and sabnzbd.DIR_LCLDATA != sabnzbd.DIR_HOME \
and misc.is_relative_path(cfg.download_dir()):
# For Windows and when version < 10: adjust old default location
cfg.download_dir.set('Documents/' + cfg.download_dir())
return old
# Required wrapper because nzbstuff.py cannot import downloader.py
def highest_server(me):
@@ -1133,11 +1159,11 @@ def proxy_pre_queue(name, pp, cat, script, priority, size, groups):
def test_ipv6():
""" Check if external IPv6 addresses are reachable """
if not cfg.ipv6_test_host():
if not cfg.selftest_host():
# User disabled the test, assume active IPv6
return True
try:
info = socket.getaddrinfo(cfg.ipv6_test_host(), 80, socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_IP, socket.AI_CANONNAME)
info = socket.getaddrinfo(cfg.selftest_host(), 443, socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_IP, socket.AI_CANONNAME)
except:
logging.debug("Test IPv6: Disabling IPv6, because it looks like it's not available. Reason: %s", sys.exc_info()[0] )
return False

View File

@@ -482,7 +482,7 @@ def _api_history(name, output, kwargs):
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
history_db = sabnzbd.connect_db()
if special in ('all', 'failed'):
if del_files:
del_job_files(history_db.get_failed_paths(search))
@@ -1238,13 +1238,15 @@ def build_queue(web_dir=None, root=None, verbose=False, prim=True, webdir='', ve
slot['mbdone_fmt'] = locale.format('%d', int(mb - mbleft), True)
slot['size'] = format_bytes(bytes)
slot['sizeleft'] = format_bytes(bytesleft)
if not Downloader.do.paused and status not in (Status.PAUSED, Status.FETCHING) and not found_active:
if not Downloader.do.paused and status not in (Status.PAUSED, Status.FETCHING, Status.GRABBING) and not found_active:
if status == Status.CHECKING:
slot['status'] = Status.CHECKING
else:
slot['status'] = Status.DOWNLOADING
found_active = True
else:
# ensure compatibility of API status
if status in (Status.DELETED, ): status = Status.DOWNLOADING
slot['status'] = "%s" % (status)
if priority == TOP_PRIORITY:
slot['priority'] = 'Force'
@@ -1574,7 +1576,7 @@ def options_list(output):
def retry_job(job, new_nzb, password):
""" Re enter failed job in the download queue """
if job:
history_db = cherrypy.thread_data.history_db
history_db = sabnzbd.connect_db()
futuretype, url, pp, script, cat = history_db.get_other(job)
if futuretype:
sabnzbd.add_url(url, pp, script, cat)
@@ -1590,7 +1592,7 @@ def retry_job(job, new_nzb, password):
def retry_all_jobs():
""" Re enter all failed jobs in the download queue """
history_db = cherrypy.thread_data.history_db
history_db = sabnzbd.connect_db()
return NzbQueue.do.retry_all_jobs(history_db)
@@ -1608,7 +1610,7 @@ def del_hist_job(job, del_files):
if path:
PostProcessor.do.delete(job, del_files=del_files)
else:
history_db = cherrypy.thread_data.history_db
history_db = sabnzbd.connect_db()
path = history_db.get_path(job)
PostProcessor.do.delete(job, del_files=del_files)
history_db.remove_history(job)
@@ -1815,7 +1817,7 @@ def build_history(start=None, limit=None, verbose=False, verbose_list=None, sear
# Aquire the db instance
try:
history_db = cherrypy.thread_data.history_db
history_db = sabnzbd.connect_db()
close_db = False
except:
# Required for repairs at startup because Cherrypy isn't active yet

View File

@@ -24,7 +24,7 @@ import threading
import sabnzbd
from sabnzbd.decorators import synchronized
from sabnzbd.constants import GIGI
from sabnzbd.constants import GIGI, Status
ARTICLE_LOCK = threading.Lock()
@@ -60,12 +60,12 @@ class ArticleCache(object):
nzf = article.nzf
nzo = nzf.nzo
if nzf.deleted or nzo.deleted:
if nzo.status in (Status.COMPLETED, Status.DELETED):
# Do not discard this article because the
# file might still be processed at this moment!!
if sabnzbd.LOG_ALL:
logging.debug("%s would be discarded", article)
# return
logging.debug("%s is discarded", article)
return
saved_articles = article.nzf.nzo.saved_articles
@@ -142,12 +142,12 @@ class ArticleCache(object):
nzf = article.nzf
nzo = nzf.nzo
if nzf.deleted or nzo.deleted:
if nzo.status in (Status.COMPLETED, Status.DELETED):
# Do not discard this article because the
# file might still be processed at this moment!!
if sabnzbd.LOG_ALL:
logging.debug("%s would be discarded", article)
# return
logging.debug("%s is discarded", article)
return
art_id = article.get_art_id()
if art_id:

View File

@@ -199,7 +199,7 @@ class BPSMeter(object):
self.defaults()
# Force update of counters and validate data
try:
for server in self.grand_total:
for server in self.grand_total.keys():
self.update(server)
except TypeError:
self.defaults()
@@ -446,7 +446,7 @@ class BPSMeter(object):
def midnight(self):
""" Midnight action: dummy update for all servers """
for server in self.day_total:
for server in self.day_total.keys():
self.update(server)

View File

@@ -82,8 +82,8 @@ replace_illegal = OptionBool('misc', 'replace_illegal', True)
pre_script = OptionStr('misc', 'pre_script', 'None')
script_can_fail = OptionBool('misc', 'script_can_fail', False)
start_paused = OptionBool('misc', 'start_paused', False)
enable_https_verification = OptionBool('misc', 'enable_https_verification', True)
ipv6_test_host = OptionStr('misc', 'ipv6_test_host', 'test-ipv6.sabnzbd.org')
enable_https_verification = OptionBool('misc', 'enable_https_verification', False)
selftest_host = OptionStr('misc', 'selftest_host', 'self-test.sabnzbd.org')
enable_unrar = OptionBool('misc', 'enable_unrar', True)
enable_unzip = OptionBool('misc', 'enable_unzip', True)
@@ -142,7 +142,7 @@ no_dupes = OptionNumber('misc', 'no_dupes', 0)
no_series_dupes = OptionNumber('misc', 'no_series_dupes', 0)
backup_for_duplicates = OptionBool('misc', 'backup_for_duplicates', True)
ignore_samples = OptionNumber('misc', 'ignore_samples', 0, 0, 2)
ignore_samples = OptionBool('misc', 'ignore_samples', False)
create_group_folders = OptionBool('misc', 'create_group_folders', False)
auto_sort = OptionBool('misc', 'auto_sort', False)
folder_rename = OptionBool('misc', 'folder_rename', True)
@@ -257,7 +257,7 @@ inet_exposure = OptionNumber('misc', 'inet_exposure', 0, protect=True) # 0=loca
max_art_tries = OptionNumber('misc', 'max_art_tries', 3, 2)
max_art_opt = OptionBool('misc', 'max_art_opt', False)
use_pickle = OptionBool('misc', 'use_pickle', False)
no_ipv6 = OptionBool('misc', 'no_ipv6', False)
ipv6_hosting = OptionBool('misc', 'ipv6_hosting', False)
# [ncenter]
ncenter_enable = OptionBool('ncenter', 'ncenter_enable', sabnzbd.DARWIN_VERSION > 7)
@@ -332,16 +332,16 @@ pushover_token = OptionStr('pushover', 'pushover_token')
pushover_userkey = OptionStr('pushover', 'pushover_userkey')
pushover_device = OptionStr('pushover', 'pushover_device')
pushover_enable = OptionBool('pushover', 'pushover_enable')
pushover_prio_startup = OptionNumber('pushover', 'pushover_prio_startup', -2)
pushover_prio_startup = OptionNumber('pushover', 'pushover_prio_startup', -3)
pushover_prio_download = OptionNumber('pushover', 'pushover_prio_download', -2)
pushover_prio_pp = OptionNumber('pushover', 'pushover_prio_pp', -2)
pushover_prio_complete = OptionNumber('pushover', 'pushover_prio_complete', 1)
pushover_prio_failed = OptionNumber('pushover', 'pushover_prio_failed', 1)
pushover_prio_pp = OptionNumber('pushover', 'pushover_prio_pp', -3)
pushover_prio_complete = OptionNumber('pushover', 'pushover_prio_complete', -1)
pushover_prio_failed = OptionNumber('pushover', 'pushover_prio_failed', -1)
pushover_prio_disk_full = OptionNumber('pushover', 'pushover_prio_disk_full', 1)
pushover_prio_warning = OptionNumber('pushover', 'pushover_prio_warning', -2)
pushover_prio_error = OptionNumber('pushover', 'pushover_prio_error', -2)
pushover_prio_warning = OptionNumber('pushover', 'pushover_prio_warning', 1)
pushover_prio_error = OptionNumber('pushover', 'pushover_prio_error', 1)
pushover_prio_queue_done = OptionNumber('pushover', 'pushover_prio_queue_done', -1)
pushover_prio_other = OptionNumber('pushover', 'pushover_prio_other', -2)
pushover_prio_other = OptionNumber('pushover', 'pushover_prio_other', -3)
# [pushbullet]
pushbullet_enable = OptionBool('pushbullet', 'pushbullet_enable')

View File

@@ -300,7 +300,7 @@ class OptionStr(Option):
def set(self, value):
""" Set stripped value """
error = None
if type(value) == type('') and self.__strip:
if isinstance(value, basestring) and self.__strip:
value = value.strip()
if self.__validation:
error, val = self.__validation(value)

View File

@@ -109,7 +109,7 @@ DEF_QRATE = 0
MIN_DECODE_QUEUE = 5
MAX_DECODE_QUEUE = 10
MAX_WARNINGS = 20
MAX_WIN_DFOLDER = 40
MAX_WIN_DFOLDER = 60
REPAIR_PRIORITY = 3
TOP_PRIORITY = 2
@@ -150,19 +150,20 @@ sample_match = r'((^|[\W_])sample\d*[\W_])' # something-sample.avi
class Status():
COMPLETED = 'Completed'
CHECKING = 'Checking'
DOWNLOADING = 'Downloading'
EXTRACTING = 'Extracting'
FAILED = 'Failed'
FETCHING = 'Fetching'
GRABBING = 'Grabbing'
MOVING = 'Moving'
PAUSED = 'Paused'
QUEUED = 'Queued'
QUICK_CHECK = 'QuickCheck'
REPAIRING = 'Repairing'
RUNNING = 'Running'
VERIFYING = 'Verifying'
COMPLETED = 'Completed' # PP: Job is finished
CHECKING = 'Checking' # Q: Pre-check is running
DOWNLOADING = 'Downloading' # Q: Normal downloading
EXTRACTING = 'Extracting' # PP: Archives are being extraced
FAILED = 'Failed' # PP: Job has failed, now in History
FETCHING = 'Fetching' # Q: Job is downloading extra par2 files
GRABBING = 'Grabbing' # Q: Getting an NZB from an external site
MOVING = 'Moving' # PP: Files are being moved
PAUSED = 'Paused' # Q: Job is paused
QUEUED = 'Queued' # Q: Job is waiting for its turn to download
QUICK_CHECK = 'QuickCheck' # PP: QuickCheck verification is running
REPAIRING = 'Repairing' # PP: Job is being repaired (by par2)
RUNNING = 'Running' # PP: User's post processing script is running
VERIFYING = 'Verifying' # PP: Job is being verified (by par2)
DELETED = 'Deleted' # Q: Job has been deleted (and is almost gone)
NOTIFY_KEYS = ('startup', 'download', 'pp', 'complete', 'failed', 'queue_done', 'disk_full', 'warning', 'error', 'other')

View File

@@ -237,9 +237,9 @@ class HistoryDB(object):
post = ''
if categories:
categories = ['*' if c == 'Default' else c for c in categories]
post = ' AND (CATEGORY = "'
post += '" OR CATEGORY = "'.join(categories)
post += '" )'
post = " AND (CATEGORY = '"
post += "' OR CATEGORY = '".join(categories)
post += "' )"
if failed_only:
post += ' AND STATUS = "Failed"'
@@ -280,7 +280,7 @@ class HistoryDB(object):
series = series.lower().replace('.', ' ').replace('_', ' ').replace(' ', ' ')
if series and season and episode:
pattern = '%s/%s/%s' % (series, season, episode)
res = self.execute('select count(*) from History WHERE series = ? AND STATUS != "Failed"', (pattern,))
res = self.execute("select count(*) from History WHERE series = ? AND STATUS != 'Failed'", (pattern,))
if res:
try:
total = self.c.fetchone().get('count(*)')
@@ -291,7 +291,7 @@ class HistoryDB(object):
def have_md5sum(self, md5sum):
""" Check whether this md5sum already in History """
total = 0
res = self.execute('select count(*) from History WHERE md5sum = ? AND STATUS != "Failed"', (md5sum,))
res = self.execute("select count(*) from History WHERE md5sum = ? AND STATUS != 'Failed'", (md5sum,))
if res:
try:
total = self.c.fetchone().get('count(*)')
@@ -495,7 +495,7 @@ def unpack_history_info(item):
item['stage_log'] = [x for x in lst if x is not None]
if item['script_log']:
item['script_log'] = zlib.decompress(item['script_log'][:])
item['script_log'] = ''
# The action line is only available for items in the postproc queue
if not item.has_key('action_line'):
item['action_line'] = ''

View File

@@ -37,7 +37,7 @@ from sabnzbd.constants import MAX_DECODE_QUEUE, MIN_DECODE_QUEUE
from sabnzbd.articlecache import ArticleCache
import sabnzbd.downloader
import sabnzbd.cfg as cfg
from sabnzbd.encoding import name_fixer
from sabnzbd.encoding import yenc_name_fixer
from sabnzbd.misc import match_str
@@ -245,7 +245,7 @@ def decode(article, data):
try:
for i in xrange(min(40, len(data))):
if data[i].startswith('begin '):
nzf.filename = name_fixer(data[i].split(None, 2)[2])
nzf.filename = yenc_name_fixer(data[i].split(None, 2)[2])
nzf.type = 'uu'
found = True
break
@@ -267,7 +267,7 @@ def decode(article, data):
# Deal with yenc encoded posts
elif (ybegin and yend):
if 'name' in ybegin:
nzf.filename = name_fixer(ybegin['name'])
nzf.filename = yenc_name_fixer(ybegin['name'])
else:
logging.debug("Possible corrupt header detected => ybegin: %s", ybegin)
nzf.type = 'yenc'

View File

@@ -62,11 +62,6 @@ class Server(object):
def __init__(self, id, displayname, host, port, timeout, threads, priority, ssl, ssl_type, send_group, username=None,
password=None, optional=False, retention=0, categories=None):
# If no ssl is protocol set, used highest available one
protocols = ssl_protocols()
if ssl and protocols and ssl_type not in protocols:
ssl_type = protocols[0]
self.id = id
self.newid = None
self.restart = False
@@ -77,7 +72,7 @@ class Server(object):
self.threads = threads
self.priority = priority
self.ssl = ssl
self.ssl_type = ssl_type
self.ssl_type = None
self.optional = optional
self.retention = retention
self.send_group = send_group
@@ -98,6 +93,11 @@ class Server(object):
self.have_body = 'free.xsusenet.com' not in host
self.have_stat = True # Assume server has "STAT", until proven otherwise
if ssl:
# When the user has set a supported protocol, use it
if ssl_type and ssl_type in ssl_protocols():
self.ssl_type = ssl_type
for i in range(threads):
self.idle_threads.append(NewsWrapper(self, i + 1))
@@ -239,8 +239,9 @@ class Downloader(Thread):
@synchronized_CV
def resume(self):
logging.info("Resuming")
if self.paused:
growler.send_notification("SABnzbd", T('Resuming'), 'download')
self.paused = False
growler.send_notification("SABnzbd", T('Resuming'), 'download')
@synchronized_CV
def pause(self, save=True):
@@ -570,7 +571,7 @@ class Downloader(Thread):
ecode = msg[:3]
display_msg = ' [%s]' % msg
logging.debug('Server login problem: %s, %s', ecode, msg)
if ecode in ('502', '481', '400') and clues_too_many(msg):
if ecode in ('502', '400', '481', '482') and clues_too_many(msg):
# Too many connections: remove this thread and reduce thread-setting for server
# Plan to go back to the full number after a penalty timeout
if server.active:
@@ -579,7 +580,7 @@ class Downloader(Thread):
self.__reset_nw(nw, None, warn=False, destroy=True, quit=True)
self.plan_server(server.id, _PENALTY_TOOMANY)
server.threads -= 1
elif ecode in ('502', '481') and clues_too_many_ip(msg):
elif ecode in ('502', '481', '482') and clues_too_many_ip(msg):
# Account sharing?
if server.active:
server.errormsg = T('Probable account sharing') + display_msg

View File

@@ -71,17 +71,27 @@ def platform_encode(p):
def name_fixer(p):
""" Return Unicode name of 8bit ASCII string, first try UTF-8, then cp1252 """
""" Return Unicode name of 8bit ASCII string, first try UTF-8, then codepage, then cp1252 """
if isinstance(p, unicode):
return p
elif isinstance(p, str):
try:
return p.decode('utf-8')
except:
return p.decode(codepage)
try:
return p.decode(codepage)
except:
return p.decode('cp1252', 'ignore')
else:
return p
def yenc_name_fixer(p):
""" Return Unicode name of 8bit ASCII string, first try utf-8, then cp1252 """
try:
return p.decode('utf-8')
except:
return p.decode('cp1252')
def is_utf8(p):
""" Return True when p is UTF-8 or plain ASCII """
@@ -251,7 +261,7 @@ def TRANS(p):
if sabnzbd.WIN32:
return p.translate(gTABLE_850_LATIN).decode('cp1252', 'replace')
else:
return p
return unicoder(p)
def UNTRANS(p):

83
sabnzbd/getipaddress.py Normal file
View File

@@ -0,0 +1,83 @@
#!/usr/bin/python -OO
# Copyright 2008-2016 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.getipaddress
"""
import socket
import sabnzbd
import sabnzbd.cfg
def localipv4():
try:
s_ipv4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s_ipv4.connect(('1.2.3.4', 80)) # Option: use 100.64.1.1 (IANA-Reserved IPv4 Prefix for Shared Address Space)
ipv4 = s_ipv4.getsockname()[0]
s_ipv4.close()
except:
ipv4 = None
pass
return ipv4
def publicipv4():
# Because of dual IPv4/IPv6 clients, finding the public ipv4 needs special attention,
# meaning forcing IPv4 connections, and not allowing IPv6 connections
try:
import urllib2
ipv4_found = False
# we only want IPv4 resolving, so socket.AF_INET:
result = socket.getaddrinfo(sabnzbd.cfg.selftest_host(), 80, socket.AF_INET, 0, socket.IPPROTO_TCP)
except:
# something very bad: no urllib2, no resolving of selftest_host, no network at all
public_ipv4 = None
return public_ipv4
# we got one or more IPv4 address(es), so let's connect to them
for item in result:
selftest_ipv4 = item[4][0] # get next IPv4 address of sabnzbd.cfg.selftest_host()
try:
# put the selftest_host's IPv4 address into the URL
req = urllib2.Request("http://" + selftest_ipv4 + "/")
# specify the User-Agent, because certain sites refuse connections with "python urllib2" as User-Agent:
req.add_header('User-Agent', 'SABnzbd+/%s' % sabnzbd.version.__version__ )
# specify the Host, because we only provide the IPv4 address in the URL:
req.add_header('Host', sabnzbd.cfg.selftest_host())
# get the response
public_ipv4 = urllib2.urlopen(req, timeout=2).read() # timeout 2 seconds, in case website is not accessible
# ... check the response is indeed an IPv4 address:
socket.inet_aton(public_ipv4) # if we got anything else than a plain IPv4 address, this will raise an exception
# if we get here without exception, we're done:
ipv4_found = True
break
except:
# the connect OR the inet_aton raised an exception, so:
# continue the for loop to try next server IPv4 address
pass
if not ipv4_found :
public_ipv4 = None
return public_ipv4
def ipv6():
try:
s_ipv6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s_ipv6.connect(('2001:db8::8080', 80)) # IPv6 prefix for documentation purpose
ipv6 = s_ipv6.getsockname()[0]
s_ipv6.close()
except:
ipv6 = None
return ipv6

View File

@@ -334,8 +334,7 @@ def send_notification_center(title, msg, gtype):
tool = ncenter_path()
if tool:
try:
command = [tool, '-title', title, '-message', msg, '-group', Tx(NOTIFICATION.get(gtype, 'other')),
'-sender', 'org.sabnzbd.team']
command = [tool, '-title', title, '-message', msg, '-group', Tx(NOTIFICATION.get(gtype, 'other'))]
proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
output = proc.stdout.read()
proc.wait()
@@ -390,7 +389,7 @@ def send_prowl(title, msg, gtype, force=False, test=None):
prio = sabnzbd.cfg.prowl_prio_complete()
if gtype == 'failed':
prio = sabnzbd.cfg.prowl_prio_failed()
if gtype == 'disk-full':
if gtype == 'disk_full':
prio = sabnzbd.cfg.prowl_prio_disk_full()
if gtype == 'warning':
prio = sabnzbd.cfg.prowl_prio_warning()
@@ -431,7 +430,7 @@ def send_pushover(title, msg, gtype, force=False, test=None):
return T('Cannot send, missing required data')
title = Tx(NOTIFICATION.get(gtype, 'other'))
prio = -2
prio = -3
if gtype == 'startup':
prio = sabnzbd.cfg.pushover_prio_startup()
@@ -443,7 +442,7 @@ def send_pushover(title, msg, gtype, force=False, test=None):
prio = sabnzbd.cfg.pushover_prio_complete()
if gtype == 'failed':
prio = sabnzbd.cfg.pushover_prio_failed()
if gtype == 'disk-full':
if gtype == 'disk_full':
prio = sabnzbd.cfg.pushover_prio_disk_full()
if gtype == 'warning':
prio = sabnzbd.cfg.pushover_prio_warning()
@@ -456,7 +455,7 @@ def send_pushover(title, msg, gtype, force=False, test=None):
if force:
prio = 1
if prio > -2:
if prio > -3:
try:
conn = httplib.HTTPSConnection("api.pushover.net:443")
conn.request("POST", "/1/messages.json", urllib.urlencode({
@@ -541,5 +540,10 @@ def send_pushbullet(title, msg, gtype, force=False, test=None):
def send_windows(title, msg, gtype):
if sabnzbd.WINTRAY:
sabnzbd.WINTRAY.sendnotification(title, msg)
try:
sabnzbd.WINTRAY.sendnotification(title, msg)
except:
logging.info(T('Failed to send Windows notification'))
logging.debug("Traceback: ", exc_info=True)
return T('Failed to send Windows notification')
return None

View File

@@ -26,6 +26,7 @@ import logging
import urllib
import json
import re
import socket
from xml.sax.saxutils import escape
from sabnzbd.utils.rsslib import RSS, Item
@@ -51,6 +52,7 @@ from sabnzbd.nzbqueue import NzbQueue
import sabnzbd.wizard
from sabnzbd.utils.servertests import test_nntp_server_dict
from sabnzbd.utils.sslinfo import ssl_protocols
from sabnzbd.getipaddress import localipv4, publicipv4, ipv6
from sabnzbd.constants import \
REC_RAR_VERSION, NORMAL_PRIORITY, PNFO_NZO_ID_FIELD, PNFO_REPAIR_FIELD, \
@@ -322,7 +324,7 @@ class MainPage(object):
# For Glitter we pre-load the JSON output
if 'Glitter' in self.__web_dir:
# Queue
queue = build_queue(limit=cfg.queue_limit())[0]
queue = build_queue(limit=cfg.queue_limit(), output='json')[0]
queue['categories'] = info.pop('cat_list')
queue['scripts'] = info.pop('script_list')
@@ -331,15 +333,16 @@ class MainPage(object):
grand, month, week, day = BPSMeter.do.get_sums()
history['total_size'], history['month_size'], history['week_size'], history['day_size'] = \
to_units(grand), to_units(month), to_units(week), to_units(day)
history['slots'], fetched_items, history['noofslots'] = build_history(limit=cfg.history_limit())
history['slots'], fetched_items, history['noofslots'] = build_history(limit=cfg.history_limit(), output='json')
# Make sure the JSON works, otherwise leave empty
try:
info['preload_queue'] = json.dumps({'queue': remove_callable(queue)});
info['preload_history'] = json.dumps({'history': history});
except UnicodeDecodeError:
info['preload_queue'] = ''
info['preload_history'] = ''
# We use the javascript recognized 'false'
info['preload_queue'] = 'false'
info['preload_history'] = 'false'
template = Template(file=os.path.join(self.__web_dir, 'main.tmpl'),
filter=FILTER, searchList=[info], compilerSettings=DIRECTIVES)
@@ -453,7 +456,15 @@ class MainPage(object):
if cfg.api_logging():
logging.debug('API-call from %s [%s] %s', cherrypy.request.remote.ip,
cherrypy.request.headers.get('User-Agent', '??'), kwargs)
if kwargs.get('mode', '') not in ('version', 'auth'):
mode = kwargs.get('mode', '')
if isinstance(mode, list):
mode = mode[0]
kwargs['mode'] = mode
name = kwargs.get('name', '')
if isinstance(name, list):
name = name[0]
kwargs['name'] = name
if mode not in ('version', 'auth'):
msg = check_apikey(kwargs)
if msg:
return msg
@@ -468,7 +479,7 @@ class MainPage(object):
name = kwargs.get('name')
if name:
history_db = cherrypy.thread_data.history_db
history_db = sabnzbd.connect_db()
return ShowString(history_db.get_name(name), history_db.get_script_log(name))
else:
raise dcRaiser(self.__root, kwargs)
@@ -1009,7 +1020,7 @@ class HistoryPage(object):
msg = check_session(kwargs)
if msg:
return msg
history_db = cherrypy.thread_data.history_db
history_db = sabnzbd.connect_db()
history_db.remove_history()
raise queueRaiser(self.__root, kwargs)
@@ -1048,7 +1059,7 @@ class HistoryPage(object):
if msg:
return msg
del_files = bool(int_conv(kwargs.get('del_files')))
history_db = cherrypy.thread_data.history_db
history_db = sabnzbd.connect_db()
if del_files:
del_job_files(history_db.get_failed_paths())
history_db.remove_failed()
@@ -1099,7 +1110,7 @@ class HistoryPage(object):
return Protected()
name = kwargs.get('name')
if name:
history_db = cherrypy.thread_data.history_db
history_db = sabnzbd.connect_db()
return ShowString(history_db.get_name(name), history_db.get_script_log(name))
else:
raise dcRaiser(self.__root, kwargs)
@@ -1391,7 +1402,7 @@ SPECIAL_BOOL_LIST = \
'queue_complete_pers', 'api_warnings', 'allow_64bit_tools',
'never_repair', 'allow_streaming', 'ignore_unrar_dates', 'rss_filenames',
'osx_menu', 'osx_speed', 'win_menu', 'use_pickle', 'allow_incomplete_nzb',
'no_ipv6', 'keep_awake', 'empty_postproc',
'ipv6_hosting', 'keep_awake', 'empty_postproc',
'web_watchdog', 'wait_for_dfolder', 'warn_empty_nzb', 'enable_bonjour',
'warn_dupl_jobs', 'backup_for_duplicates', 'enable_par_cleanup',
'enable_https_verification', 'api_logging'
@@ -1399,7 +1410,7 @@ SPECIAL_BOOL_LIST = \
SPECIAL_VALUE_LIST = \
('size_limit', 'folder_max_length', 'fsys_type', 'movie_rename_limit', 'nomedia_marker',
'req_completion_rate', 'wait_ext_drive', 'history_limit', 'show_sysload', 'ipv6_servers',
'rating_host', 'ipv6_test_host'
'rating_host', 'selftest_host'
)
SPECIAL_LIST_LIST = \
('rss_odd_titles', 'prio_sort_list'
@@ -1804,9 +1815,6 @@ def handle_server(kwargs, root=None, new_svr=False):
for kw in ('ssl', 'send_group', 'enable', 'optional'):
if kw not in kwargs.keys():
kwargs[kw] = None
if 'ssl_type' in kwargs and kwargs['ssl_type'] == ssl_protocols()[0]:
# When user selects highest protocol, make empty (default)
kwargs['ssl_type'] = ''
if svr and not new_svr:
svr.set_dict(kwargs)
else:
@@ -2222,11 +2230,13 @@ class ConfigScheduling(object):
actions_lng = {}
for action in actions:
actions_lng[action] = Ttemplate("sch-" + action)
actions_servers = {}
servers = config.get_servers()
for srv in servers:
name = servers[srv].displayname()
actions.append(name)
actions_lng[name] = name
actions_servers[srv] = servers[srv].displayname()
conf['actions_servers'] = actions_servers
conf['actions'] = actions
conf['actions_lng'] = actions_lng
@@ -2240,13 +2250,7 @@ class ConfigScheduling(object):
if msg:
return msg
# Create server dictionary based on displayname
server_names = {}
servers = config.get_servers()
for srv in servers:
srv = servers[srv]
server_names[srv.displayname()] = srv.ident()[1]
minute = kwargs.get('minute')
hour = kwargs.get('hour')
days_of_week = ''.join([str(x) for x in kwargs.get('daysofweek', '')])
@@ -2267,8 +2271,7 @@ class ConfigScheduling(object):
arguments = 0
elif action in _SCHED_ACTIONS:
arguments = ''
elif action in server_names:
action = server_names[action]
elif action in servers:
if arguments == '1':
arguments = action
action = 'enable_server'
@@ -2462,14 +2465,12 @@ class Status(object):
# Dashboard: Begin
if not kwargs.get('skip_dashboard'):
from sabnzbd.utils.getipaddress import localipv4, publicipv4, ipv6
header['localipv4'] = localipv4()
header['publicipv4'] = publicipv4()
header['ipv6'] = ipv6()
# Dashboard: DNS-check
try:
import socket
socket.gethostbyname('www.google.com')
socket.gethostbyname(cfg.selftest_host())
header['dnslookup'] = "OK"
except:
header['dnslookup'] = None
@@ -2659,17 +2660,12 @@ class Status(object):
msg = check_session(kwargs)
if msg:
return msg
try:
logging.debug('Dashboard: Refresh button pressed')
from sabnzbd.utils.diskspeed import diskspeedmeasure
sabnzbd.downloaddirspeed = round(diskspeedmeasure(sabnzbd.cfg.download_dir.get_path()), 1)
sabnzbd.completedirspeed = round(diskspeedmeasure(sabnzbd.cfg.complete_dir.get_path()), 1)
from sabnzbd.utils.diskspeed import diskspeedmeasure
sabnzbd.downloaddirspeed = round(diskspeedmeasure(sabnzbd.cfg.download_dir.get_path()), 1)
time.sleep(1.0)
sabnzbd.completedirspeed = round(diskspeedmeasure(sabnzbd.cfg.complete_dir.get_path()), 1)
logging.debug('Dashboard: Refresh finished succesfully')
except:
logging.debug('Dashboard: Refresh had a problem')
raise dcRaiser(self.__root, kwargs) # Refresh screen
@@ -2951,7 +2947,6 @@ def rss_history(url, limit=50, search=None):
return rss.write()
def rss_warnings():
""" Return an RSS feed with last warnings/errors """
rss = RSS()
@@ -2968,3 +2963,4 @@ def rss_warnings():
rss.channel.lastBuildDate = std_time(time.time())
rss.channel.pubDate = rss.channel.lastBuildDate
return rss.write()

View File

@@ -446,6 +446,17 @@ def create_real_path(name, loc, path, umask=False, writable=True):
return (False, "")
def is_relative_path(p):
""" Return True if path is relative """
p = p.replace('\\', '/')
if p and p[0] == '/':
return False
if sabnzbd.WIN32 and p and len(p) > 2:
if p[0].isalpha() and p[1] == ':' and p[2] == '/':
return False
return True
def windows_variant():
""" Determine Windows variant
Return vista_plus, x64
@@ -1296,6 +1307,9 @@ def get_base_url(url):
url_host = urlparse(url).hostname
if url_host:
url_split = url_host.split(".")
# Exception for localhost and IPv6 addresses
if len(url_split) < 3:
return url_host
return ".".join(len(url_split[-2]) < 4 and url_split[-3:] or url_split[-2:])
else:
return ''

View File

@@ -476,7 +476,8 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, one_folder, rars):
try:
os.remove(rar)
except OSError:
logging.warning(T('Deleting %s failed!'), rar)
if os.path.exists(rar):
logging.warning(T('Deleting %s failed!'), rar)
brokenrar = '%s.1' % rar
@@ -485,7 +486,8 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, one_folder, rars):
try:
os.remove(brokenrar)
except OSError:
logging.warning(T('Deleting %s failed!'), brokenrar)
if os.path.exists(brokenrar):
logging.warning(T('Deleting %s failed!'), brokenrar)
return fail, extracted_files
@@ -504,6 +506,9 @@ def rar_extract(rarfile, numrars, one_folder, nzo, setname, extraction_path):
passwords = [nzo.password.strip()]
else:
passwords = []
pw = nzo.nzo_info.get('password')
if pw:
passwords.append(pw)
# Append meta passwords, to prevent changing the original list
passwords.extend(nzo.meta.get('password', []))
if passwords:
@@ -614,6 +619,7 @@ def rar_extract_core(rarfile, numrars, one_folder, nzo, setname, extraction_path
rarfiles = []
fail = 0
inrecovery = False
lines = []
while 1:
line = proc.readline()
@@ -621,6 +627,7 @@ def rar_extract_core(rarfile, numrars, one_folder, nzo, setname, extraction_path
break
line = line.strip()
lines.append(line)
if line.startswith('Extracting from'):
filename = TRANS((re.search(EXTRACTFROM_RE, line).group(1)))
@@ -711,6 +718,19 @@ def rar_extract_core(rarfile, numrars, one_folder, nzo, setname, extraction_path
nzo.set_unpack_info('Unpack', unicoder(msg), set=setname)
fail = 3
elif 'checksum error' in line:
# Corrupt archive
# packed data checksum error in volume FILE
m = re.search(r'error in volume (.+)', line)
if m:
filename = TRANS(m.group(1)).strip()
else:
filename = '???'
nzo.fail_msg = T('Corrupt RAR file')
msg = ('[%s][%s] ' + T('Corrupt RAR file')) % (setname, filename)
nzo.set_unpack_info('Unpack', unicoder(msg), set=setname)
fail = 3
else:
m = re.search(r'^(Extracting|Creating|...)\s+(.*?)\s+OK\s*$', line)
if m:
@@ -757,6 +777,7 @@ def rar_extract_core(rarfile, numrars, one_folder, nzo, setname, extraction_path
else:
logging.info('Skipping unrar file check due to unreliable file names or old unrar')
logging.debug('UNRAR output %s', '\n'.join(lines))
nzo.fail_msg = ''
msg = T('Unpacked %s files/folders in %s') % (str(len(extracted)), format_time_string(time() - start))
nzo.set_unpack_info('Unpack', '[%s] %s' % (unicoder(setname), msg), set=setname)
@@ -1032,9 +1053,9 @@ def par2_repair(parfile_nzf, nzo, workdir, setname, single):
# Download all par2 files that haven't been downloaded yet
readd = False
for extrapar in parfile_nzf.extrapars[:]:
if extrapar in nzo.files:
parfile_nzf.extrapars.remove(extrapar)
if extrapar not in nzo.finished_files and extrapar not in nzo.files:
nzo.add_parfile(extrapar)
parfile_nzf.extrapars.remove(extrapar)
readd = True
if readd:
return readd, result
@@ -1213,6 +1234,7 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False, sin
pars = []
datafiles = []
renames = {}
reconstructed = []
linebuf = ''
finished = 0
@@ -1405,18 +1427,25 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False, sin
finished = 1
elif line.startswith('File:') and line.find('data blocks from') > 0:
# Find out if a joinable file has been used for joining
uline = unicoder(line)
for jn in joinables:
if uline.find(os.path.split(jn)[1]) > 0:
used_joinables.append(jn)
break
# Special case of joined RAR files, the "of" and "from" must both be RAR files
# This prevents the joined rars files from being seen as an extra rar-set
m = _RE_BLOCK_FOUND.search(line)
if m and '.rar' in m.group(1).lower() and '.rar' in m.group(2).lower():
if m:
workdir = os.path.split(parfile)[0]
used_joinables.append(os.path.join(workdir, TRANS(m.group(1))))
old_name = TRANS(m.group(1))
new_name = TRANS(m.group(2))
if joinables:
# Find out if a joinable file has been used for joining
uline = unicoder(line)
for jn in joinables:
if uline.find(os.path.split(jn)[1]) > 0:
used_joinables.append(jn)
break
# Special case of joined RAR files, the "of" and "from" must both be RAR files
# This prevents the joined rars files from being seen as an extra rar-set
if '.rar' in old_name.lower() and '.rar' in new_name.lower():
used_joinables.append(os.path.join(workdir, old_name))
else:
logging.debug('PAR2 will reconstruct "%s" from "%s"', new_name, old_name)
reconstructed.append(os.path.join(workdir, old_name))
elif 'Could not write' in line and 'at offset 0:' in line and not classic:
# Hit a bug in par2-tbb, retry with par2-classic
@@ -1496,6 +1525,11 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False, sin
renames[name] = previous[name]
save_data(renames, RENAMES_FILE, nzo.workpath)
# If successful and files were reconstructed, remove incomplete original files
if finished and reconstructed:
# Use 'used_joinables' as a vehicle to get rid of the files
used_joinables.extend(reconstructed)
if retry_classic:
logging.debug('Retry PAR2-joining with par2-classic')
return PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=True, single=single)
@@ -1640,9 +1674,6 @@ def QuickCheck(set, nzo):
nzf_list = nzo.finished_files
for file in md5pack:
if sabnzbd.misc.on_cleanup_list(file, False):
result = True
continue
found = False
for nzf in nzf_list:
if file == nzf.filename:
@@ -1802,8 +1833,11 @@ def pre_queue(name, pp, cat, script, priority, size, groups):
if n < len(values) and line:
values[n] = TRANS(line)
n += 1
if int_conv(values[0]) < 1:
accept = int_conv(values[0])
if accept < 1:
logging.info('Pre-Q refuses %s', name)
elif accept == 2:
logging.info('Pre-Q accepts&fails %s', name)
else:
logging.info('Pre-Q accepts %s', name)

View File

@@ -308,7 +308,7 @@ class NewsWrapper(object):
self.pass_sent = True
self.pass_ok = True
if code in ('501', '502') and self.user_sent:
if code in ('501',) and self.user_sent:
# Change to a sensible text
code = '481'
self.lines[0] = T('Authentication failed, check username/password.')

View File

@@ -251,12 +251,13 @@ class NzbQueue(TryList):
nzo_ids = []
# Aggregate nzo_ids and save each nzo
for nzo in self.__nzo_list:
nzo_ids.append(os.path.join(nzo.work_name, nzo.nzo_id))
if save_nzo is None or nzo is save_nzo:
sabnzbd.save_data(nzo, nzo.nzo_id, nzo.workpath)
if not nzo.futuretype:
nzo.save_to_disk()
for nzo in self.__nzo_list[:]:
if not nzo.deleted:
nzo_ids.append(os.path.join(nzo.work_name, nzo.nzo_id))
if save_nzo is None or nzo is save_nzo:
sabnzbd.save_data(nzo, nzo.nzo_id, nzo.workpath)
if not nzo.futuretype:
nzo.save_to_disk()
sabnzbd.save_admin((QUEUE_VERSION, nzo_ids, []), QUEUE_FILE_NAME)
@@ -436,10 +437,10 @@ class NzbQueue(TryList):
if nzo_id in self.__nzo_table:
nzo = self.__nzo_table.pop(nzo_id)
nzo.deleted = True
if cleanup and nzo.status not in (Status.COMPLETED, Status.FAILED):
nzo.status = Status.DELETED
self.__nzo_list.remove(nzo)
sabnzbd.remove_data(nzo_id, nzo.workpath)
if add_to_history:
# Create the history DB instance
history_db = database.get_history_handle()
@@ -451,6 +452,8 @@ class NzbQueue(TryList):
elif cleanup:
self.cleanup_nzo(nzo, keep_basic, del_files)
sabnzbd.remove_data(nzo_id, nzo.workpath)
if save:
self.save(nzo)
else:
@@ -775,18 +778,22 @@ class NzbQueue(TryList):
if self.__top_only:
if self.__nzo_list:
for nzo in self.__nzo_list:
if nzo.status not in (Status.PAUSED, Status.GRABBING) and nzo.server_allowed(server):
article = nzo.get_article(server, servers)
if article:
return article
# Not when queue paused and not a forced item
if (nzo.status not in (Status.PAUSED, Status.GRABBING) and not sabnzbd.downloader.Downloader.do.paused) or nzo.priority == TOP_PRIORITY:
if nzo.server_allowed(server):
article = nzo.get_article(server, servers)
if article:
return article
else:
for nzo in self.__nzo_list:
# Don't try to get an article if server is in try_list of nzo
if not nzo.server_in_try_list(server) and nzo.status not in (Status.PAUSED, Status.GRABBING) and nzo.server_allowed(server):
article = nzo.get_article(server, servers)
if article:
return article
# Not when queue paused and not a forced item
if (nzo.status not in (Status.PAUSED, Status.GRABBING) and not sabnzbd.downloader.Downloader.do.paused) or nzo.priority == TOP_PRIORITY:
# Don't try to get an article if server is in try_list of nzo
if not nzo.server_in_try_list(server) and nzo.server_allowed(server):
article = nzo.get_article(server, servers)
if article:
return article
# No articles for this server, block server (until reset issued)
self.add_to_try_list(server)
@@ -807,27 +814,30 @@ class NzbQueue(TryList):
if reset:
self.reset_try_list()
if file_done:
if nzo.next_save is None or time.time() > nzo.next_save:
sabnzbd.save_data(nzo, nzo.nzo_id, nzo.workpath)
BPSMeter.do.save()
if nzo.save_timeout is None:
nzo.next_save = None
else:
nzo.next_save = time.time() + nzo.save_timeout
if nzo.status in (Status.COMPLETED, Status.DELETED):
logging.debug('Discarding file completion %s for deleted job', filename)
else:
if file_done:
if nzo.next_save is None or time.time() > nzo.next_save:
sabnzbd.save_data(nzo, nzo.nzo_id, nzo.workpath)
BPSMeter.do.save()
if nzo.save_timeout is None:
nzo.next_save = None
else:
nzo.next_save = time.time() + nzo.save_timeout
if not nzo.precheck:
_type = nzf.type
if not nzo.precheck:
_type = nzf.type
# Only start decoding if we have a filename and type
if filename and _type:
Assembler.do.process((nzo, nzf))
# Only start decoding if we have a filename and type
if filename and _type:
Assembler.do.process((nzo, nzf))
else:
if file_has_articles(nzf):
logging.warning(T('%s -> Unknown encoding'), filename)
if post_done:
self.end_job(nzo)
else:
if file_has_articles(nzf):
logging.warning(T('%s -> Unknown encoding'), filename)
if post_done:
self.end_job(nzo)
def end_job(self, nzo):
""" Send NZO to the post-processing queue """

View File

@@ -82,7 +82,6 @@ class Article(TryList):
TryList.__init__(self)
self.fetcher = None
self.fetcher_priority = 0
self.allow_fill_server = False
self.article = article
@@ -703,7 +702,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, cfg.ignore_samples() == 2 and not reuse)
handler = NzbParser(self, False)
parser = xml.sax.make_parser()
parser.setFeature(xml.sax.handler.feature_external_ges, 0)
parser.setContentHandler(handler)
@@ -869,6 +868,12 @@ class NzbObject(TryList):
# Set nzo save-delay to 6 sec per GB with a max of 5 min
self.save_timeout = min(6.0 * float(self.bytes) / GIGI, 300.0)
# If accept&fail, fail the job
if accept == 2:
self.deleted = True
sabnzbd.Assembler.do.process((self, None))
def check_for_dupe(self, nzf):
filename = nzf.filename
@@ -892,9 +897,10 @@ class NzbObject(TryList):
def remove_nzf(self, nzf):
if nzf in self.files:
self.files.remove(nzf)
if nzf not in self.finished_files:
self.finished_files.append(nzf)
nzf.import_finished = True
nzf.deleted = True
nzf.import_finished = True
nzf.deleted = True
return not bool(self.files)
def reset_all_try_lists(self):
@@ -1012,7 +1018,8 @@ class NzbObject(TryList):
if renames:
for name in renames:
if name in files or renames[name] in files:
files.remove(name)
if name in files:
files.remove(name)
files.append(renames[name])
# Looking for the longest name first, minimizes the chance on a mismatch
@@ -1110,7 +1117,7 @@ class NzbObject(TryList):
def pause(self):
self.status = Status.PAUSED
# Prevent loss of paused state when terminated
if self.nzo_id:
if self.nzo_id and self.status not in (Status.COMPLETED, Status.DELETED):
sabnzbd.save_data(self, self.nzo_id, self.workpath)
def resume(self):
@@ -1130,7 +1137,7 @@ class NzbObject(TryList):
self.unwanted_ext = 2
def add_parfile(self, parfile):
if parfile not in self.files:
if not parfile.completed and parfile not in self.files:
self.files.append(parfile)
if parfile.extrapars and parfile in parfile.extrapars:
parfile.extrapars.remove(parfile)
@@ -1508,7 +1515,7 @@ class NzbObject(TryList):
def save_to_disk(self):
""" Save job's admin to disk """
self.save_attribs()
if self.nzo_id:
if self.nzo_id and self.status not in (Status.COMPLETED, Status.DELETED):
sabnzbd.save_data(self, self.nzo_id, self.workpath)
def save_attribs(self):

View File

@@ -265,6 +265,8 @@ def launch_a_browser(url, force=False):
# Must use https, because http is not available
url = url.replace('http:', 'https:')
if 'localhost' in url and not cfg.ipv6_hosting():
url = url.replace('localhost', '127.0.0.1')
logging.info("Launching browser with %s", url)
try:
if url and not url.startswith('http'):

View File

@@ -120,7 +120,8 @@ class PostProcessor(Thread):
def remove(self, nzo):
""" Remove given nzo from the queue """
try:
self.history_queue.remove(nzo)
if nzo in self.history_queue:
self.history_queue.remove(nzo)
except:
nzo_id = getattr(nzo, 'nzo_id', 'unknown id')
logging.error(T('Failed to remove nzo from postproc queue (id)') + ' ' + nzo_id)
@@ -423,7 +424,7 @@ def process_job(nzo):
else:
job_result = int(par_error) + int(bool(unpack_error)) * 2
if cfg.ignore_samples() > 0:
if cfg.ignore_samples():
remove_samples(workdir_complete)
# TV/Movie/Date Renaming code part 2 - rename and move files to parent folder
@@ -593,7 +594,7 @@ def parring(nzo, workdir):
if repair_sets:
for setname in repair_sets:
if cfg.ignore_samples() > 0 and 'sample' in setname.lower():
if cfg.ignore_samples() and 'sample' in setname.lower():
continue
if not verified.get(setname, False):
logging.info("Running repair on set %s", setname)

View File

@@ -112,7 +112,8 @@ class Rating(Thread):
self.shutdown = False
self.queue = OrderedSetQueue()
try:
(self.version, self.ratings, self.nzo_indexer_map) = sabnzbd.load_admin("Rating.sab")
self.version, self.ratings, self.nzo_indexer_map = sabnzbd.load_admin("Rating.sab",
silent=not cfg.rating_enable())
if self.version == 1:
ratings = {}
for k, v in self.ratings.iteritems():

View File

@@ -118,6 +118,7 @@ SKIN_TEXT = {
'off' : TT('off'),
'parameters' : TT('Parameters'), #: Config: startup parameters of SABnzbd
'pythonVersion' : TT('Python Version'),
'notAvailable' : TT('Not available'),
'homePage' : TT('Home page'), #: Home page of the SABnzbd project
'source' : TT('Source'), #: Where to find the SABnzbd sourcecode
'or' : TT('or'), #: Used in "IRC or IRC-Webaccess"
@@ -149,6 +150,7 @@ SKIN_TEXT = {
'menu-wiki' : TT('Wiki'), #: Main menu item
'menu-forums' : TT('Forum'), #: Main menu item
'menu-irc' : TT('IRC'), #: Main menu item
'menu-issues' : TT('Issues'), #: Main menu item
'cmenu-general' : TT('General'), #: Main menu item
'cmenu-folders' : TT('Folders'), #: Main menu item
'cmenu-switches' : TT('Switches'), #: Main menu item
@@ -271,7 +273,7 @@ SKIN_TEXT = {
'warning' : TT('Warning'), #: Status page, table column header, actual message
'warnings' : TT('Warnings'), #: Footer: indicator of warnings
'enabled' : TT('Enabled'), #: Status page, indicator that server is enabled
# Dashboard
'dashboard-title' : TT('Dashboard'),
'dashboard-connectionError' : TT('Connection failed!'),
@@ -337,7 +339,7 @@ SKIN_TEXT = {
'opt-bandwidth_perc' : TT('Percentage of line speed'),
'explain-bandwidth_perc' : TT('Which percentage of the linespeed should SABnzbd use, e.g. 50'),
'opt-cache_limitstr' : TT('Article Cache Limit'),
'explain-cache_limitstr' : TT('Cache articles in memory to reduce disk access.<br /><i>In bytes, optionally follow with K,M,G. For example: "64M" or "128M"</i>'),
'explain-cache_limitstr' : TT('Cache articles in memory to reduce disk access.<br /><i>In bytes, optionally follow with K,M,G. For example: "64M" or "128M"</i>').replace("64M", "256M").replace("128M", "512M"),
'opt-cleanup_list' : TT('Cleanup List'),
'explain-cleanup_list' : TT('List of file extensions that should be deleted after download.<br />For example: <b>nfo</b> or <b>nfo, sfv</b>'),
'button-saveChanges' : TT('Save Changes'),
@@ -805,12 +807,12 @@ SKIN_TEXT = {
'Glitter-confirmClearWarnings' : TT('Are you sure?'),
'Glitter-confirmClearDownloads' : TT('Are you sure?'),
'Glitter-confirmClear1Download' : TT('Are you sure?'),
'Glitter-grabbing' : TT('Grabbing NZB...'),
'Glitter-updateAvailable' : TT('Update Available!'),
'Glitter-noLocalStorage' : TT('LocalStorage (cookies) are disabled in your browser, interface settings will be lost after you close the browser!'), #: Don't translate LocalStorage
'Glitter-custom' : TT('Custom'),
'Glitter-confirmDeleteQueue' : TT('Confirm Queue Deletions'),
'Glitter-confirmDeleteHistory' : TT('Confirm History Deletions'),
'Glitter-pausePrompt': TT('How long or untill when do you want to pause? (in English!)'),
'Glitter-pausePrompt': TT('How long or untill when do you want to pause? (in English!)'),
'Glitter-pausePromptFail': TT('Sorry, we could not interpret that. Try again.'),
'Glitter-pauseFor' : TT('Pause for...'),
'Glitter-sortAgeAsc' : TT('Sort by Age <small>Oldest&rarr;Newest</small>'),

View File

@@ -40,6 +40,7 @@ class TryList:
def __init__(self):
self.__try_list = []
self.fetcher_priority = 0
@synchronized(TRYLIST_LOCK)
def server_in_try_list(self, server):
@@ -67,3 +68,4 @@ class TryList:
""" Clean the list """
if self.__try_list:
self.__try_list = []
self.fetcher_priority = 0

View File

@@ -124,6 +124,9 @@ class URLGrabber(Thread):
elif '401' in error1 or 'unauthorized' in error1:
msg = T('Unauthorized access')
retry = False
elif '404' in error1:
msg = T('File not on server')
retry = False
new_url = dereferring(url, fn)
if new_url:
@@ -157,6 +160,8 @@ class URLGrabber(Thread):
nzo_info['failure'] = value
elif item == 'x-dnzb-details':
nzo_info['details'] = value
elif item == 'x-dnzb-password':
nzo_info['password'] = value
elif item == 'retry-after':
# For NZBFinder
wait = misc.int_conv(value)
@@ -201,6 +206,9 @@ class URLGrabber(Thread):
data = fn.read()
fn.close()
# Sanatize filename first
filename = misc.sanitize_filename(filename)
# Write data to temp file
path = os.path.join(cfg.admin_dir.get_path(), FUTURE_Q_FOLDER)
path = os.path.join(path, filename)

View File

@@ -3,40 +3,59 @@
import time
import os
import sys
import logging
_DUMP_DATA = '*' * 10000
def writetofile(filename, mysizeMB):
# writes string to specified file repeat delay, until mysizeMB is reached. Then deletes file
mystring = "The quick brown fox jumps over the lazy dog"
writeloops = int(1000000 * mysizeMB / len(mystring))
# writes string to specified file repeat delay, until mysizeMB is reached.
writeloops = int(1024 * 1024 * mysizeMB / len(_DUMP_DATA))
try:
f = open(filename, 'w')
except:
# no better idea than:
raise
for x in range(0, writeloops):
f.write(mystring)
logging.debug('Cannot create file %s', filename)
logging.debug("Traceback: ", exc_info=True)
return False
try:
for x in xrange(writeloops):
f.write(_DUMP_DATA)
except:
logging.debug('Cannot write to file %s', filename)
logging.debug("Traceback: ", exc_info=True)
return False
f.close()
os.remove(filename)
return True
def diskspeedmeasure(dirname):
# returns writing speed to dirname in MB/s
# method: keep writing a file, until 0.5 seconds is passed. Then divide bytes written by time passed
filesize = 1 # MB
filesize = 10 # MB
maxtime = 0.5 # sec
filename = os.path.join(dirname, 'outputTESTING.txt')
if os.name == 'nt':
# On Windows, this crazy action is needed to
# avoid a "permission denied" error
try:
os.system('echo Hi >%s' % filename)
except:
pass
start = time.time()
loopcounter = 0
while True:
try:
writetofile(filename, filesize)
except:
return None
if not writetofile(filename, filesize):
return 0
loopcounter += 1
diff = time.time() - start
if diff > maxtime:
break
try:
os.remove(filename)
except:
pass
return (loopcounter * filesize) / diff

View File

@@ -1,43 +0,0 @@
#!/usr/bin/python -OO
import socket
def localipv4():
try:
s_ipv4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s_ipv4.connect(('1.2.3.4', 80)) # Option: use 100.64.1.1 (IANA-Reserved IPv4 Prefix for Shared Address Space)
ipv4 = s_ipv4.getsockname()[0]
s_ipv4.close()
except:
ipv4 = None
pass
return ipv4
def publicipv4():
try:
import urllib2
f = urllib2.urlopen("http://api.ipify.org", timeout=2) # timeout 2 seconds, in case website is not accessible
public_ipv4 = f.read()
socket.inet_aton(public_ipv4) # if we got anything else than a plain IPv4 address, this will raise an exception
except:
public_ipv4 = None
pass
return public_ipv4
def ipv6():
try:
s_ipv6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s_ipv6.connect(('2001:db8::8080', 80)) # IPv6 prefix for documentation purpose
ipv6 = s_ipv6.getsockname()[0]
s_ipv6.close()
except:
ipv6 = None
return ipv6
if __name__ == '__main__':
print localipv4()
print publicipv4()
print ipv6()

View File

@@ -1,7 +1,5 @@
_ALL_PROTOCOLS = ('t12', 't11', 't1', 'v23', 'v3', 'v2')
_SSL_PROTOCOLS = {}
def ssl_potential():
''' Return a list of potentially supported SSL protocols'''
try:
@@ -47,17 +45,24 @@ try:
except ImportError:
SSL = None
def ssl_method(method):
''' Translate SSL acronym to a method value '''
if method in _SSL_PROTOCOLS:
return _SSL_PROTOCOLS[method]
else:
return _SSL_PROTOCOLS[0]
# The default is "negotiate a protocol"
try:
return SSL.SSLv23_METHOD
except AttributeError:
return _SSL_PROTOCOLS[0]
def ssl_protocols():
''' Return acronyms for SSL protocols, highest quality first '''
return [p for p in _ALL_PROTOCOLS if p in _SSL_PROTOCOLS]
def ssl_version():
if SSL:
try:
@@ -72,8 +77,19 @@ def ssl_version():
return None
def pyopenssl_version():
if SSL:
try:
import OpenSSL
return OpenSSL.__version__
except ImportError:
return 'No pyOpenSSL installed'
else:
return None
if __name__ == '__main__':
print 'SSL version: %s' % ssl_version()
print 'pyOpenSSL version: %s' % pyopenssl_version()
print 'Potentials: %s' % ssl_potential()
print 'Actuals: %s' % ssl_protocols()

View File

@@ -23,6 +23,7 @@ import urllib2
import urllib
import logging
import os
from sabnzbd.encoding import unicoder
import sabnzbd.cfg as cfg
from sabnzbd.misc import get_ext, get_filename
import sabnzbd.newsunpack
@@ -34,6 +35,7 @@ from sabnzbd.dirscanner import ProcessArchiveFile, ProcessSingleFile
def upload_file(url, fp):
""" Function for uploading nzbs to a running sabnzbd instance """
try:
fp = unicoder(fp).encode('utf-8')
fp = urllib.quote_plus(fp)
url = '%s&mode=addlocalfile&name=%s' % (url, fp)
# Add local apikey if it wasn't already in the registered URL

View File

@@ -4,5 +4,5 @@
# You MUST use double quotes (so " and not ')
__version__ = "0.8.x"
__version__ = "1.0.x"
__baseline__ = "unknown"