Compare commits

...

89 Commits

Author SHA1 Message Date
Travis
e3e2fb7057 Automatic translation update 2017-06-27 09:23:17 +00:00
Safihre
ece04909e7 Add latest changes to changelog 2017-06-27 00:13:24 +02:00
Safihre
963920eb88 Semi-correct missing MB counter for Pre-check
It's still off (for Precheck only), but not sure why
2017-06-26 22:03:50 +02:00
Safihre
cf5fa542b6 Don't show import errors when NZO is gone 2017-06-26 21:36:49 +02:00
Safihre
1be7e99754 Remove last hashlib workaround 2017-06-26 21:00:17 +02:00
Safihre
14e3334682 Correctly handle disk-space calculations
No more glitches in the interface during downloading.
2017-06-26 16:25:03 +02:00
Safihre
b1e033dd55 Update text files for 2.2.0Alpa2 2017-06-26 14:28:22 +02:00
Safihre
111feb1b57 Show missing articles as MB instead of number of articles 2017-06-26 13:46:54 +02:00
Safihre
886b23d034 Update translatable texts 2017-06-26 10:40:02 +02:00
Safihre
f2590792b3 Download all par2 always when enable_par_cleanup is disabled
https://forums.sabnzbd.org/viewtopic.php?f=2&t=22744
2017-06-26 09:19:05 +02:00
Safihre
02a497ed74 Only set Post-processing Completed/Failed at the very end
To prevent race-issues
2017-06-25 20:32:45 +02:00
Safihre
48df0eed84 Add logging for user-actions
We were missing way too many things
2017-06-24 23:18:14 +02:00
Travis
0f58cbb671 Automatic translation update 2017-06-24 18:51:32 +00:00
Safihre
9d71670f59 Full hearted 2017-06-24 20:33:16 +02:00
Safihre
7f838ebb38 Move Donate-link in Glitter 2017-06-24 13:51:19 +02:00
Safihre
ef1cb05bc8 Store result of MultiPar verification
Just in case prospective par2 didn't catch them all
2017-06-24 10:47:33 +02:00
Safihre
c14b3ed82a Prospective Par2 correct TryList reset
I think
2017-06-24 00:34:57 +02:00
Safihre
792e337936 Rename increase_last_history_update to history_updated 2017-06-23 22:58:29 +02:00
Safihre
6cd2e66052 Use actual counter for LAST_HISTORY_UPDATE
Would otherwise miss some updates
2017-06-23 12:49:40 +02:00
Safihre
728022b86d Show Verifying Repair stage for MultiPar 2017-06-23 11:10:47 +02:00
Safihre
7718446313 Convert HTML to text in warning messages
Related: #952
2017-06-23 08:30:54 +02:00
Travis
66dea54053 Automatic translation update 2017-06-22 20:34:50 +00:00
Safihre
f19b60bd41 Also don't list line numbers for NSIS pot file 2017-06-22 21:46:55 +02:00
Safihre
09f1c92856 Move enable_multipar to Specials
Moving forward to make MultiPar the only used par2-solution on Windows.
2017-06-22 11:03:53 +02:00
Safihre
589715901d Correct counting during Checking/Verification in MultiPar 2017-06-22 10:50:00 +02:00
Safihre
3f1a5ff5e0 Fix typo in extract_pot.py 2017-06-22 09:32:59 +02:00
Safihre
49cd956d4c Do not list line-number for POT files
To avoid commit-overhead when updating texts
2017-06-21 22:17:49 +02:00
Safihre
f9acde862f Correct counting in MultiPar Checking 2017-06-21 21:40:24 +02:00
Safihre
503e1dd899 Re-work NZO_LOCK to actually lock when saving 2017-06-21 20:54:00 +02:00
Safihre
c8e12b948d Mixed up application of use_pickle 2017-06-21 17:18:16 +02:00
Safihre
18949d68c0 Fix wrong addition to en.po
Thx @thezoggy!
2017-06-21 17:12:19 +02:00
Safihre
0c51b6c016 Add Donate links to main Config page and Glitter help modal 2017-06-21 09:57:56 +02:00
Safihre
63a5c22c1f Don't continue when fetching failed
Possibly: #914
2017-06-21 09:19:25 +02:00
Safihre
f76e2a7b56 All links to sabnzbd.org should be HTTPS 2017-06-20 23:15:15 +02:00
Safihre
bab151d6f5 Properly fix redirect after enabeling/disabeling HTTPS 2017-06-20 22:46:48 +02:00
Safihre
d43fec088b Fix typo in Correct redirect when enabeling HTTPS 2017-06-20 19:48:18 +02:00
Safihre
a8ca1cbcd7 Correct redirect when enabeling HTTPS 2017-06-20 19:47:45 +02:00
Safihre
ada3494483 Fix typo in Config JavaScript 2017-06-20 19:04:38 +02:00
Safihre
43c238b7f1 Update translations 2017-06-17 11:23:50 +02:00
Safihre
128d10c51e Restart-text was always shown in English 2017-06-17 11:19:59 +02:00
Safihre
1a1e01f9f6 Correct upgrade-notice 2017-06-17 11:13:53 +02:00
Safihre
8483e4ab8a Add last minor change to changelog 2017-06-17 09:01:53 +02:00
Safihre
f6c163b505 CherryPy 8.1.2 - Catch OSX "Protocol wrong type for socket" 2017-06-17 08:40:14 +02:00
Safihre
8f30173db0 Update text files for 2.2.0Alpha1 2017-06-16 15:38:17 +02:00
Brendan Ball
0372ff95bb Added support for systemd power controls
added systemd support to powersup.linux_shutdown, linux_hibernate, linux_standby
2017-06-16 15:19:32 +02:00
Safihre
6fa29c7877 Update translatable texts 2017-06-15 20:58:48 +02:00
Safihre
d4c9121593 Remove NZB_LOCK
Not required
2017-06-15 20:54:13 +02:00
Safihre
76a8df0282 Make it more clear that Hostname verification is a server problem 2017-06-15 20:51:27 +02:00
Safihre
0b6d8309a0 Format the SSL certificate messages more for humans 2017-06-15 20:51:21 +02:00
Safihre
10a9bc0817 Don't show Advanded on Config>General if HTTPS disabled 2017-06-15 16:09:01 +02:00
Safihre
2a14af4ffa Firefox doesn't suck at animations anymore 2017-06-15 14:47:04 +02:00
Safihre
d1a4a292e3 Prevent log-flooding when job is too old for server 2017-06-13 21:40:45 +02:00
Safihre
14c0efa151 Fix error in MultiPar repair when first .par2-file was broken 2017-06-13 21:40:45 +02:00
Safihre
4fc03f2581 Discard all articles at once when too old for server 2017-06-13 21:40:45 +02:00
Safihre
3205b9fda9 Don't fill anything for bandwith limit if nothing is set
Now it would just fill "M" when nothing was set.
2017-06-13 21:40:45 +02:00
Safihre
953e0d6c22 Remove DIR_LOCK
The operations it was locking were always performed from 1 thread anyway.
2017-06-13 21:40:45 +02:00
Safihre
b50ce54ca9 Reformat IO_LOCK to really only protect against NZO-saving collisions
The main intent was not to read/write to same file, but this can (as far as I can see) never happen anyway. 
Before this change 2 threads could not be writing data at the same time, even if they were writing to completly different directories.
2017-06-13 21:40:45 +02:00
Safihre
5e7558ce4a Remove locks from ArticleCache
All operations on the list are atomic or modify objects in place that can't be read at the same time.
2017-06-13 21:40:45 +02:00
Safihre
8aa6362432 Remove NZBQueue wrapper functions
Direct-access!
2017-06-13 21:40:45 +02:00
Safihre
02ebb97a8b Remove NZBQUEUE_LOCK and only use synced wrappers when needed
Less locks = Less waiting
2017-06-13 21:40:45 +02:00
Safihre
b36063403d Remove legacy asserts and work-a-rounds 2017-06-13 21:40:45 +02:00
Safihre
526ffa2afb Add new translation to Changelog 2017-06-13 17:26:37 +02:00
Safihre
5b3fd812d8 Don't break MO-creation on missing Email templates 2017-06-13 14:40:47 +02:00
Safihre
af6dac9cdc Refresh Config > General when submitting language change 2017-06-13 14:14:26 +02:00
Safihre
bc25d936bb Show Hebrew in language menu
Correction of previous commit: I intended to write that it's an experiment because Hebrew is RTL. It seems to work!
2017-06-13 14:14:01 +02:00
Safihre
b497fe1444 Add Hebrew as language
This is an experiment, since Hebrew is LTR language. But a translator translated almost all the texts, so we want to use his efforts!
2017-06-13 11:43:18 +02:00
Safihre
3f456cce05 Move max_art_opt to Specials
Only for special cases (don't know which ones, but I can imagine it could be usefull..)
Deprecate later!
2017-06-13 00:40:02 +02:00
Safihre
4dd2f089ec Move replace_illegal to Specials
Who doesn't want that
2017-06-13 00:37:20 +02:00
Safihre
b1b1bc248d Reformat startswith() to use tuples when testing multiple options 2017-06-11 22:01:45 +02:00
Safihre
d9e675469c Don't throw errors when silent-saving fails 2017-06-11 22:01:45 +02:00
Safihre
ede0ca1772 Catch new way of par2 reporting bad parameters
See: https://forums.sabnzbd.org/viewtopic.php?f=2&t=22713&p=112209#p112209
2017-06-11 22:01:45 +02:00
Safihre
2d098a1477 Defend against possible NTFS crash
Closes #930
2017-06-11 22:01:45 +02:00
Safihre
e5f014b68e Replace spaces/dots in the order written in the Config 2017-06-11 22:01:45 +02:00
Safihre
b3a9dc9eeb Fix old code throughout 2017-06-11 22:01:45 +02:00
Safihre
2a06cec27c Seperate compatibility-check logic in NZBQueue 2017-06-11 22:01:45 +02:00
Safihre
19230c889d Remove unused functions and constants (vulture) 2017-06-11 22:01:45 +02:00
Safihre
c969ce552c Remove unused constants (vulture) 2017-06-11 22:01:45 +02:00
Safihre
2def600d21 Remove unused imports and functions (pyflakes) 2017-06-11 22:01:45 +02:00
Safihre
02aa8f18c8 Trylist doesn't need locks, all atomic operations 2017-06-11 22:01:45 +02:00
Safihre
fcd9522dae Remove unused import and define NzbQueue as proper class 2017-06-11 22:01:45 +02:00
Safihre
72d3ce885e Remove un-used version definitions from __init__ 2017-06-11 22:01:45 +02:00
Safihre
b428996eb7 Convert pickles and keep queue order
Also restore future jobs


dewd
2017-06-11 22:01:45 +02:00
Safihre
2b4eb58fad Correctly show message about old Queue-version
Now it's also upgrade-proof, and not just works for 1 version.
2017-06-11 22:01:45 +02:00
Safihre
240e8dff60 Bump Queue-Version to force Queue-Repair 2017-06-11 22:01:45 +02:00
Safihre
1c286afde6 Implement __slots__ to conserve memory
Objects such as Article() get created a lot. By using the __slots__ property, python will only reserve space for the give keywords instead of a whole diectonary. 

Testing showed that (on WinX64) 1 job now takes between 2-3MB of memory when loaded, compared to 4MB before.
2017-06-11 22:01:45 +02:00
Safihre
2eeb908540 Revert "Remove enable_par_cleanup"
This reverts commit f5ab4a2253.
2017-06-11 16:10:25 +02:00
Safihre
562e6ecce9 Fix Untill typos in texts and comments
Closes #943
2017-06-11 11:51:50 +02:00
Safihre
4bd0d32508 Bump version to 2.2.0-develop 2017-06-11 11:46:36 +02:00
Safihre
6f2ccbef80 Always show Par2-Multicore status on first Config page on Linux 2017-06-09 16:04:30 +02:00
110 changed files with 24850 additions and 20770 deletions

View File

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

View File

@@ -1,4 +1,4 @@
SABnzbd 2.1.0
SABnzbd 2.2.0
-------------------------------------------------------------------------------
0) LICENSE

View File

@@ -1,8 +1,8 @@
Metadata-Version: 1.0
Name: SABnzbd
Version: 2.1.0
Summary: SABnzbd-2.1.0
Home-page: http://sabnzbd.org
Version: 2.2.0Alpha2
Summary: SABnzbd-2.2.0Alpha2
Home-page: https://sabnzbd.org
Author: The SABnzbd Team
Author-email: team@sabnzbd.org
License: GNU General Public License 2 (GPL2 or later)

View File

@@ -5,7 +5,7 @@ SABnzbd is an Open Source Binary Newsreader written in Python.
It's totally free, incredibly easy to use, and works practically everywhere.
SABnzbd makes Usenet as simple and streamlined as possible by automating everything we can. All you have to do is add an `.nzb`. SABnzbd takes over from there, where it will be automatically downloaded, verified, repaired, extracted and filed away with zero human interaction.
If you want to know more you can head over to our website: http://sabnzbd.org.
If you want to know more you can head over to our website: https://sabnzbd.org.
## Resolving Dependencies

View File

@@ -1,22 +1,49 @@
Release Notes - SABnzbd 2.1.0
Release Notes - SABnzbd 2.2.0 Alpha 2
=========================================================
## Changes since 2.0.1
- Windows-only: Will now use MultiPar for verification and repair. MultiPar uses
the latest optimizations, multiple cores and can utilize the GPU, resulting in
repairs often being twice as fast. Created by Yutaka Sawada (Windows only)
"Extra Par2 Parameters" are also passed to MultiPar
For example: Set "/lc32" to enable GPU for repair (can also be slower!)
- Minimal macOS version set to 10.9 (Mavericks)
- Human readable history date/time default setting in Glitter (x hours ago, etc)
- Post-processing script execution can be aborted
- Removed Specials settings: never_repair, nr_decoders, prio_sort_list,
create_group_folder, enable_par_cleanup, enable_quickcheck, allow_64bit_tools
NOTE: Due to changes in this release, the queue will be converted when 2.2.0
is started for the first time. Job order, settings and data will be
preserved, but all jobs will be unpaused and URL's that did not finish
fetching before the upgrade will be lost!
# Bugfixes
- File join would fail incorrectly
- Catch and show 'Disk full' messages from PAR2/MultiPar
- MemoryError occurred when opening the interface after long period of inactivity
We now also accept donations via Bitcoin, Ethereum and Litecoin:
https://sabnzbd.org/donate/
## Changes since Alpha 1
- Show missing articles in MB instead of number of articles
- 'Download all par2' will download all par2 if par_cleanup is disabled
- Windows: Move enable_multipar to Specials (so MultiPar is always used)
- Windows: Better indication of verification process before and after repair
- Windows: MultiPar verification of a job is skipped after blocks are fetched
## Bugfixes since Alpha 1
- Fixed some "Saving failed" errors
- Fixed crashing URLGrabber
- Disk-space readings could be updated incorrectly
- Correct redirect after enabling HTTPS in the Config
- Fix race-condition in Post-processing
- History would not always show latest changes
- Convert HTML in error messages
- Not all texts were shown in the selected Language
## Changes in 2.2.0
- Reduced memory usage, especially with larger queues
- Slight improvement in download performance by removing internal locks
- Smoother animations in Firefox (disabled previously due to FF high-CPU usage)
- If enabled, replace dots in filenames also when there are spaces already
- Jobs outside server retention are processed faster
- max_art_opt and replace_illegal moved from Switches to Specials
## Bugfixes in 2.2.0
- Shutdown/suspend did not work on some Linux systems
- Deleting a job could result in write errors
- Display warning if custom par2 parameters are wrong
- macOS: Catch 'Protocol wrong type for socket' errors
- Windows: Fix error in MultiPar-code when first par2-file was damaged
## Translations
- Added Hebrew translation by ION IL, many other languages updated.
## Upgrading from 0.7.x and older
- Finish queue

View File

@@ -56,8 +56,6 @@ if [int(n) for n in cherrypy.__version__.split('.')] < [8, 1, 2]:
print 'Sorry, requires Python module Cherrypy 8.1.2+ (use the included version)'
sys.exit(1)
from cherrypy import _cpserver
SQLITE_DLL = True
try:
from sqlite3 import version as sqlite3_version
@@ -90,7 +88,7 @@ from sabnzbd.misc import real_path, \
check_latest_version, exit_sab, \
split_host, get_ext, create_https_certificates, \
windows_variant, ip_extract, set_serv_parms, get_serv_parms, globber_full
from sabnzbd.panic import panic_tmpl, panic_port, panic_host, panic_fwall, \
from sabnzbd.panic import panic_tmpl, panic_port, panic_host, \
panic_sqlite, panic, launch_a_browser
import sabnzbd.scheduler as scheduler
import sabnzbd.config as config
@@ -727,24 +725,6 @@ def evaluate_inipath(path):
return path
def cherrypy_logging(log_path, log_handler):
""" Setup CherryPy logging """
log = cherrypy.log
log.access_file = ''
log.error_file = ''
# Max size of 512KB
maxBytes = getattr(log, "rot_maxBytes", 524288)
# cherrypy.log cherrypy.log.1 cherrypy.log.2
backupCount = getattr(log, "rot_backupCount", 3)
# Make a new RotatingFileHandler for the error log.
fname = getattr(log, "rot_error_file", log_path)
h = log_handler(fname, 'a', maxBytes, backupCount)
h.setLevel(logging.DEBUG)
h.setFormatter(cherrypy._cplogging.logfmt)
log.error_log.addHandler(h)
def commandline_handler(frozen=True):
""" Split win32-service commands are true parameters
Returns:
@@ -1353,7 +1333,6 @@ def main():
'error_page.404': sabnzbd.panic.error_page_404
})
# Do we want CherryPy Logging? Cannot be done via the config
if cherrypylogging:
sabnzbd.WEBLOGFILE = os.path.join(logdir, DEF_LOG_CHERRY)

View File

@@ -196,12 +196,13 @@ socket_errors_to_ignore = plat_specific_errors(
)
socket_errors_to_ignore.append('timed out')
socket_errors_to_ignore.append('The read operation timed out')
if sys.platform == 'darwin':
socket_errors_to_ignore.append(plat_specific_errors('EPROTOTYPE'))
socket_errors_nonblocking = plat_specific_errors(
'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK')
if sys.platform == 'darwin':
socket_errors_to_ignore.append(plat_specific_errors('EPROTOTYPE'))
socket_errors_nonblocking.append(plat_specific_errors('EPROTOTYPE'))
comma_separated_headers = [
ntob(h) for h in
['Accept', 'Accept-Charset', 'Accept-Encoding',

View File

@@ -41,12 +41,16 @@
</td>
</tr>
<!--#end if#-->
<!--#if not $have_mt_par2#-->
<!--#if not $nt and not $darwin#-->
<tr>
<th scope="row">Multicore Par2</th>
<th scope="row">$T('opt-multicore-par2')</th>
<td>
<!--#if $have_mt_par2#-->
<span class="glyphicon glyphicon-ok"></span>
<!--#else#-->
<span class="label label-warning">$T('notAvailable')</span> $T('explain-getpar2mt')
<a href="${helpuri}installation/multicore-par2" target="_blank">${helpuri}installation/multicore-par2</a>
<!--#end if#-->
</td>
</tr>
<!--#end if#-->
@@ -105,7 +109,7 @@
<tbody>
<tr>
<th scope="row">$T('homePage') </th>
<td><a href="http://sabnzbd.org/" target="_blank">http://sabnzbd.org/</a></td>
<td><a href="https://sabnzbd.org/" target="_blank">https://sabnzbd.org/</a></td>
</tr>
<tr>
<th scope="row">$T('menu-wiki') </th>
@@ -113,7 +117,7 @@
</tr>
<tr>
<th scope="row">$T('menu-forums') </th>
<td><a href="http://forums.sabnzbd.org/" target="_blank">http://forums.sabnzbd.org/</a></td>
<td><a href="https://forums.sabnzbd.org/" target="_blank">https://forums.sabnzbd.org/</a></td>
</tr>
<tr>
<th scope="row">$T('source') </th>
@@ -127,6 +131,10 @@
<th scope="row">$T('menu-issues') </th>
<td><a href="https://sabnzbd.org/wiki/introduction/known-issues" target="_blank">https://sabnzbd.org/wiki/introduction/known-issues</a></td>
</tr>
<tr>
<th scope="row">$T('menu-donate') </th>
<td><a href="https://sabnzbd.org/donate" target="_blank">https://sabnzbd.org/donate</a></td>
</tr>
</tbody>
</table>
</div>

View File

@@ -25,7 +25,7 @@
</div>
<div class="field-pair">
<label class="config" for="enable_https">$T('opt-enable_https')</label>
<input type="checkbox" name="enable_https" id="enable_https" value="1" <!--#if int($enable_https) > 0 then 'checked="checked"' else ""#-->/>
<input type="checkbox" name="enable_https" id="enable_https" value="1" <!--#if int($enable_https) > 0 then 'checked="checked" data-original="1"' else ""#-->/>
<span class="desc">$T('explain-enable_https')</span>
</div>
<div class="field-pair">
@@ -240,7 +240,17 @@
\$('.alert-translate').show()
}
}
\$('#language').on('change', hideOrShowTranslate)
\$('#language').on('change', function() {
// Show message
hideOrShowTranslate()
// Re-load page on submit
\$('.fullform').submit(function() {
// Skip the fancy stuff, just submit
this.submit()
})
// No JSON reponse
\$('#ajax').val('')
})
hideOrShowTranslate()
\$('#apikey, #nzbkey').click(function () { \$(this).select() });
@@ -314,14 +324,20 @@
if(bandwidthLimit) {
var bandwithLimitNumber = parseFloat(bandwidthLimit)
var bandwithLimitText = bandwidthLimit.replace(/[^a-zA-Z]+/g, '');
\$('#bandwidth_max_value').val(bandwithLimitNumber)
\$('#bandwidth_max_dropdown').val(bandwithLimitText)
if(bandwithLimitNumber) {
\$('#bandwidth_max_value').val(bandwithLimitNumber)
\$('#bandwidth_max_dropdown').val(bandwithLimitText)
}
}
// Update the value
\$('#bandwidth_max_value, #bandwidth_max_dropdown').on('change', function() {
\$('#bandwidth_max').val(\$('#bandwidth_max_value').val() + \$('#bandwidth_max_dropdown').val())
if(\$('#bandwidth_max_value').val()) {
\$('#bandwidth_max').val(\$('#bandwidth_max_value').val() + \$('#bandwidth_max_dropdown').val())
} else {
\$('#bandwidth_max').val('')
}
})
});

View File

@@ -338,6 +338,7 @@
}).then(function(data) {
// Let's replace the link
msg = data.value.message.replace('https://sabnzbd.org/certificate-errors', '<a href="https://sabnzbd.org/certificate-errors" class="alert-link" target="_blank">https://sabnzbd.org/certificate-errors</a>')
msg = msg.replace('-', '<br>')
// Fill the box and enable the button
resultBox.removeClass('alert-success alert-danger').show()
resultBox.html(msg)

View File

@@ -31,12 +31,6 @@
<input type="number" name="max_art_tries" id="max_art_tries" value="$max_art_tries" min="2" max="2000" />
<span class="desc">$T('explain-max_art_tries')</span>
</div>
<div class="field-pair">
<label class="config" for="max_art_opt">$T('opt-max_art_opt')</label>
<input type="checkbox" name="max_art_opt" id="max_art_opt" value="1" <!--#if int($max_art_opt) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-max_art_opt')</span>
</div>
<div class="field-pair">
<label class="config" for="auto_disconnect">$T('opt-auto_disconnect')</label>
<input type="checkbox" name="auto_disconnect" id="auto_disconnect" value="1" <!--#if int($auto_disconnect) > 0 then 'checked="checked"' else ""#--> />
@@ -159,13 +153,6 @@
<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').replace('. ', '.<br/>')</span>
</div>
<!--#if $nt#-->
<div class="field-pair">
<label class="config" for="multipar">$T('opt-par2_multipar')</label>
<input type="checkbox" name="multipar" id="multipar" value="1" <!--#if int($multipar) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-par2_multipar')</span>
</div>
<!--#end if#-->
<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" />
@@ -251,11 +238,6 @@
<input type="checkbox" name="replace_dots" id="replace_dots" value="1" <!--#if int($replace_dots) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-replace_dots')</span>
</div>
<div class="field-pair">
<label class="config" for="replace_illegal">$T('opt-replace_illegal')</label>
<input type="checkbox" name="replace_illegal" id="replace_illegal" value="1" <!--#if int($replace_illegal) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-replace_illegal')</span>
</div>
<!--#if not $nt#-->
<div class="field-pair">
<label class="config" for="sanitize_safe">$T('opt-sanitize_safe')</label>

View File

@@ -228,16 +228,13 @@ function do_restart() {
// What template
var arrPath = window.location.pathname.split('/');
var urlPath = (arrPath[1] == "m" || arrPath[2] == "m") ? '/sabnzbd/m/' : '/sabnzbd/';
var switchedHTTPS = !$('#enable_https').is(':checked') && window.location.protocol == 'https:'
var switchedHTTPS = ($('#enable_https').is(':checked') == ($('#enable_https').data('original') === undefined))
var portsUnchanged = ($('#port').val() == $('#port').data('original')) && ($('#https_port').val() == $('#https_port').data('original'))
// Are we on settings page?
if(!$('body').hasClass('General')) {
// Same as before, with fall-back in case location.origin is not supported (<IE9)
var urlTotal = window.location.origin ? (window.location.origin + urlPath) : window.location;
} else if (!switchedHTTPS && ($('#port').val() == $('#port').data('original')) && ($('#https_port').val() == $('#https_port').data('original'))) {
// If the http/https port config didn't change, don't try and guess the URL/port to redirect to
// This solves some incorrect behavior if running behind a reverse proxy
var urlTotal = window.location.origin ? (window.location.origin + urlPath) : window.location;
// Are we on settings page or did nothing change?
if(!$('body').hasClass('General') || (!switchedHTTPS && !portsUnchanged)) {
// Same as before
var urlTotal = window.location.origin + urlPath
} else {
// Protocol and port depend on http(s) setting
if($('#enable_https').is(':checked') && (window.location.protocol == 'https:' || !$('#https_port').val())) {
@@ -263,7 +260,7 @@ function do_restart() {
// Keep counter of failures
var failureCounter = 0;
// Now we try untill we can connect
// Now we try until we can connect
var refreshInterval = setInterval(function() {
// We skip the first one
if(failureCounter == 0) {
@@ -409,6 +406,9 @@ $(document).ready(function () {
$('#enable_https').on('change', function() {
$('.enable_https_options').toggle()
})
if(!$('#enable_https').is(':checked')) {
$('.enable_https_options').hide()
}
$('.advancedButton').click(function(event){
$('.advanced-settings').toggle()

View File

@@ -89,6 +89,7 @@
</a>
<ul class="dropdown-menu menu-options">
<li><a href="#modal-help" data-toggle="modal"><span class="glyphicon glyphicon-question-sign"></span> $T('menu-help')</a></li>
<li><a href="https://sabnzbd.org/donate" target="_blank"><span class="glyphicon glyphicon-heart"></span> $T('menu-donate')</a></li>
<!--#if $have_logout or $have_quota or $have_rss_defined or $have_watched_dir or $pp_pause_event#--><li class="divider"></li><!--#end if#-->
<!--#if $have_logout#--><li><a href="./login/?logout=1"><span class="glyphicon glyphicon-log-out"></span> $T('logout')</a></li><!--#end if#-->
<!--#if $have_quota#--><li><a href="#" data-bind="click: doQueueAction" data-mode="reset_quota">$T('link-resetQuota')</a></li><!--#end if#-->

View File

@@ -60,13 +60,13 @@
<p><strong>If anything is not working as expected, or could be improved, let us know!</strong></p>
<p><strong>If you encounter an error, please include the log file (click on <span class="glyphicon glyphicon-wrench"></span> ) when contacting us.</strong></p>
<h4>General</h4>
<span class="glyphicon glyphicon-home"></span> <a href="http://forums.sabnzbd.org/" target="_blank">SABnzbd Forum</a><br />
<span class="glyphicon glyphicon-home"></span> <a href="https://forums.sabnzbd.org/" target="_blank">SABnzbd Forum</a><br />
<span class="glyphicon glyphicon-plane"></span> <a href="https://github.com/sabnzbd/sabnzbd/" target="_blank">SABnzbd on Github</a><br />
<span class="glyphicon glyphicon-globe"></span> <a href="https://translations.launchpad.net/sabnzbd" target="_blank">Translations of SABnzbd</a><br />
<span class="glyphicon glyphicon-envelope"></span> <a href="mailto:bugs@sabnzbd.org?body=Version:%20$version%20Skin:%20Glitter">Email bugs@sabnzbd.org</a>
<h4>Interface (Glitter)</h4>
<span class="glyphicon glyphicon-home"></span> <a href="http://forums.sabnzbd.org/viewtopic.php?f=5&amp;t=18880" target="_blank">Glitter at SABnzbd Forum</a><br />
<span class="glyphicon glyphicon-home"></span> <a href="https://forums.sabnzbd.org/viewtopic.php?f=5&amp;t=18880" target="_blank">Glitter at SABnzbd Forum</a><br />
<span class="glyphicon glyphicon-envelope"></span> <a href="mailto:safihre@sabnzbd.org?body=Version:%20$version">Email safihre@sabnzbd.org</a>
</div>
</div>
@@ -621,7 +621,7 @@
</tr>
<tr>
<td><strong>$T('menu-forums'):</strong></td>
<td><a href="http://forums.sabnzbd.org/" target="_blank">http://forums.sabnzbd.org/</a></td>
<td><a href="https://forums.sabnzbd.org/" target="_blank">https://forums.sabnzbd.org/</a></td>
</tr>
<tr>
<td><strong>GitHub:</strong></td>
@@ -629,7 +629,7 @@
</tr>
<tr>
<td><strong>$T('menu-irc'):</strong></td>
<td><a href="http://www.sabnzbd.org/live-chat/" target="_blank">http://www.sabnzbd.org/live-chat/</a></td>
<td><a href="https://sabnzbd.org/live-chat" target="_blank">https://sabnzbd.org/live-chat</a></td>
</tr>
</tbody>
</table>

View File

@@ -58,7 +58,7 @@
glitterTranslate.pauseFor = "$T('pauseFor')"
glitterTranslate.minutes = "$T('mins')"
glitterTranslate.shutdown = "$T('shutdownOK?')";
glitterTranslate.restart = "$T('explain-Restart')".replace(/<br \/>/g, "\n");
glitterTranslate.restart = "$T('explain-Restart') $T('explain-needNewLogin')".replace(/\<br(\s*\/|)\>/g, '\n');
glitterTranslate.repair = "$T('explain-Repair')".replace(/<br \/>/g, "\n").replace(/&quot;/g,'"');
glitterTranslate.removeDown = "$T('Glitter-confirmClearDownloads')";
glitterTranslate.removeDow1 = "$T('Glitter-confirmClear1Download')";

View File

@@ -538,7 +538,7 @@ function ViewModel() {
// Go over all warnings and add
$.each(response.warnings, function(index, warning) {
// Split warning into parts
var warningSplit = warning.split(/\n/);
var warningSplit = convertHTMLtoText(warning).split(/\n/);
// Reformat CSS label and date
var warningData = {

View File

@@ -464,7 +464,7 @@ function QueueModel(parent, data) {
self.totalMB = ko.observable(parseFloat(data.mb));
self.remainingMB = ko.observable(parseFloat(data.mbleft));
self.avg_age = ko.observable(data.avg_age)
self.missing = ko.observable(data.missing)
self.missing = ko.observable(parseFloat(data.mbmissing))
self.category = ko.observable(data.cat);
self.priority = ko.observable(parent.priorityName[data.priority]);
self.script = ko.observable(data.script);
@@ -485,8 +485,8 @@ function QueueModel(parent, data) {
if(self.status() == 'Checking') {
return '#58A9FA'
}
// Check for missing data, the value is arbitrary!
if(self.missing() > 50) {
// Check for missing data, the value is arbitrary! (3%)
if(self.missing()/self.totalMB() > 0.03) {
return '#F8A34E'
}
// Set to grey, only when not Force download
@@ -510,9 +510,9 @@ function QueueModel(parent, data) {
// Texts
self.missingText= ko.pureComputed(function() {
// Check for missing data, the value is arbitrary!
if(self.missing() > 50) {
return self.missing() + ' ' + glitterTranslate.misingArt
// Check for missing data, the value is arbitrary! (3%)
if(self.missing()/self.totalMB() > 0.03) {
return self.missing().toFixed(0) + ' MB ' + glitterTranslate.misingArt
}
return;
})
@@ -565,7 +565,7 @@ function QueueModel(parent, data) {
self.totalMB(parseFloat(data.mb));
self.remainingMB(parseFloat(data.mbleft));
self.avg_age(data.avg_age)
self.missing(data.missing)
self.missing(parseFloat(data.mbmissing))
self.category(data.cat);
self.priority(parent.priorityName[data.priority]);
self.script(data.script);

View File

@@ -52,8 +52,8 @@ h2 {
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.1);
background-color: #ffffff;
border: 1px solid #cccccc;
margin-left: -150px;
margin-top: 4px;
margin-left: -220px;
margin-top: 5px;
}
.navbar-collapse.in .dropdown-menu a,
@@ -1921,49 +1921,6 @@ input[name="nzbURL"] {
}
}
/***
SPECIAL FOR FIREFOX
It uses very high CPU for anything animated (Sep 2015)
Disable animations on progress-bar and make the History-'processing' a block animation
Can be removed if it's performance gets better in the future..
***/
@supports (-moz-transform: translate(0, 0)) {
.progress-bar {
transform: none !important;
animation: none !important;
transition: none !important;
}
@keyframes stretchdelay {
0%, 60% {
transform: scaleY(0.4);
}
61%, 100% {
transform: scaleY(1.0);
}
}
.processing-download > div {
animation: stretchdelay 2s infinite linear;
}
.processing-download .loader-bar-two {
animation-delay: 0.2s;
}
.processing-download .loader-bar-three {
animation-delay: 0.4s;
}
.processing-download .loader-bar-four {
animation-delay: 0.6s;
}
.queue-table td.name input {
margin-left: -2px;
}
}
/***
Bootstrap overwrites

View File

@@ -1,7 +1,7 @@
Plush for SABnzbd 0.6.x | Feb. 21 2010
assembled by pairofdimes - see LICENSE-CC.txt
http://forums.sabnzbd.org contributions welcome
https://forums.sabnzbd.org contributions welcome
======================
THANKS TO CONTRIBUTORS

View File

@@ -23,8 +23,8 @@
<div id="help_modal">
<table>
<tr><td><strong>$T('menu-wiki'):</strong></td><td><a href="$helpuri$help_uri" target="_blank">$helpuri$help_uri</a></td></tr>
<tr><td><strong>$T('menu-forums'):</strong></td><td><a href="http://forums.sabnzbd.org/" target="_blank">http://forums.sabnzbd.org/</a></td></tr>
<tr><td><strong>$T('menu-irc'):</strong></td><td><a href="http://www.sabnzbd.org/live-chat/" target="_blank">http://www.sabnzbd.org/live-chat/</a></td></tr>
<tr><td><strong>$T('menu-forums'):</strong></td><td><a href="https://forums.sabnzbd.org/" target="_blank">https://forums.sabnzbd.org/</a></td></tr>
<tr><td><strong>$T('menu-irc'):</strong></td><td><a href="https://sabnzbd.org/live-chat.html" target="_blank">https://sabnzbd.org/live-chat.html</a></td></tr>
</table>
<div class="sabnzbd_logo main_sprite_container sprite_sabnzbdplus_logo"></div>
<p><strong>SABnzbd $T('version'):</strong> $version</p>

View File

@@ -1134,7 +1134,7 @@ function loadingJSON(){
<li><a style="text-decoration:underline;cursor:pointer;" onclick="if(confirm('$T('shutdownOK?')')){shutdown()}">$T('link-shutdown')</a></li>
<br/>
<li><a href="$helpuri" target="_blank">$T('menu-wiki')</a></li>
<li><a href="http://forums.sabnzbd.org" target="_blank">$T('menu-forums')</a></li>
<li><a href="https://forums.sabnzbd.org" target="_blank">$T('menu-forums')</a></li>
<li><a href="http://sabnzbd.org/live-chat/" target="_blank">$T('menu-irc')</a></li>
</ul>
<!--<input type="checkbox" name="enable_speedlimit" />-->

View File

@@ -1,11 +1,11 @@
#
# SABnzbd Translation Template file EMAIL
# Copyright (C) 2011-2015 by the SABnzbd Team
# Copyright 2011-2017 The SABnzbd-Team
# team@sabnzbd.org
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-0.8.x\n"
"Project-Id-Version: SABnzbd-2.2.0-develop\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: shypike@sabnzbd.org\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: shypike <Unknown>\n"
"Language-Team: Danish <da@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Thomas Lucke (Lucky) <Unknown>\n"
"Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: shypike <Unknown>\n"
"Language-Team: Spanish <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Matti Ylönen <Unknown>\n"
"Language-Team: Finnish <fi@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Fox Ace <Unknown>\n"
"Language-Team: French <fr@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

121
po/email/he.po Normal file
View File

@@ -0,0 +1,121 @@
# Hebrew translation for sabnzbd
# Copyright (c) 2017 Rosetta Contributors and Canonical Ltd 2017
# This file is distributed under the same license as the sabnzbd package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2017.
#
msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-06-13 09:56+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""
"##\n"
"## Default Email template for SABnzbd\n"
"## This a Cheetah template\n"
"## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"## Newlines and whitespace are significant!\n"
"##\n"
"## These are the email headers\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd has <!--#if $status then \"completed\" else \"failed\" #--> "
"job $name\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## After this comes the body, the empty line is required!\n"
"\n"
"Hi,\n"
"<!--#if $status #-->\n"
"SABnzbd has downloaded \"$name\" <!--#if $msgid==\"\" then \"\" else "
"\"(newzbin #\" + $msgid + \")\"#-->\n"
"<!--#else#-->\n"
"SABnzbd has failed to download \"$name\" <!--#if $msgid==\"\" then \"\" else "
"\"(newzbin #\" + $msgid + \")\"#-->\n"
"<!--#end if#-->\n"
"Finished at $end_time\n"
"Downloaded $size\n"
"\n"
"Results of the job:\n"
"<!--#for $stage in $stages #-->\n"
"Stage $stage <!--#slurp#-->\n"
"<!--#for $result in $stages[$stage]#-->\n"
" $result <!--#slurp#-->\n"
"<!--#end for#-->\n"
"<!--#end for#-->\n"
"<!--#if $script!=\"\" #-->\n"
"Output from user script \"$script\" (Exit code = $script_ret):\n"
"$script_output\n"
"<!--#end if#-->\n"
"<!--#if $status #-->\n"
"Enjoy!\n"
"<!--#else#-->\n"
"Sorry!\n"
"<!--#end if#-->\n"
msgstr ""
#: email/rss.tmpl:1
msgid ""
"##\n"
"## RSS Email template for SABnzbd\n"
"## This a Cheetah template\n"
"## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"## Newlines and whitespace are significant!\n"
"##\n"
"## These are the email headers\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd has added $amount jobs to the queue\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## After this comes the body, the empty line is required!\n"
"\n"
"Hi,\n"
"\n"
"SABnzbd has added $amount job(s) to the queue.\n"
"They are from RSS feed \"$feed\".\n"
"<!--#for $job in $jobs#-->\n"
" $job <!--#slurp#-->\n"
"<!--#end for#-->\n"
"\n"
"Bye\n"
msgstr ""
#: email/badfetch.tmpl:1
msgid ""
"##\n"
"## Bad URL Fetch Email template for SABnzbd\n"
"## This a Cheetah template\n"
"## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"## Newlines and whitespace are significant!\n"
"##\n"
"## These are the email headers\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd failed to fetch an NZB\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## After this comes the body, the empty line is required!\n"
"\n"
"Hi,\n"
"\n"
"SABnzbd has failed to retrieve the NZB from $url.\n"
"The error message was: $msg\n"
"\n"
"Bye\n"
msgstr ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: shypike <Unknown>\n"
"Language-Team: Dutch <nl@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Tomasz 'Zen' Napierala <tomasz@napierala.org>\n"
"Language-Team: Polish <pl@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: lrrosa <Unknown>\n"
"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: nicusor <Unknown>\n"
"Language-Team: Romanian <ro@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Pavel Maryanov <Unknown>\n"
"Language-Team: Russian <gnu@mx.ru>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Ozzii <Unknown>\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-06-24 19:51+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
"Language-Team: Launchpad Serbian Translators\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-27 06:00+0000\n"
"X-Generator: Launchpad (build 18416)\n"
"Language: sr\n"
#: email/email.tmpl:1
@@ -66,20 +66,20 @@ msgid ""
"<!--#end if#-->\n"
msgstr ""
"##\n"
"## Шаблон основне е-поште за САБнзбд\n"
"## Основни шаблон ел. поште за САБнзбд\n"
"## Ово је Гепард шаблон\n"
"## Документација: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"## Нови редови и размаци су важни!\n"
"##\n"
"## Ово су заглавља е-поруке\n"
"Прима: $to\n"
"Шаље: $from\n"
"Датум: $date\n"
"Тема: САБнзбд је <!--#if $status then \"завршио\" else \"није обавио\" #--> "
"посао $name\n"
"Х-приоритет: 5\n"
"Х-МС-приоритет: 5\n"
"## Ово су заглавља ел. поште\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: САБнзбд је <!--#if $status then \"completed\" else \"failed\" #--> "
"посао $name\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## После тога долази разрада, празни редови су потребни!\n"
"\n"
"Здраво,\n"
@@ -101,7 +101,7 @@ msgstr ""
"<!--#end for#-->\n"
"<!--#end for#-->\n"
"<!--#if $script!=\"\" #-->\n"
"Излаз корисничке скрипте „$script“ (Код излаза = $script_ret):\n"
"Излаз корисничке скрипте „$script“ (Шифра излаза = $script_ret):\n"
"$script_output\n"
"<!--#end if#-->\n"
"<!--#if $status #-->\n"
@@ -139,19 +139,19 @@ msgid ""
"Bye\n"
msgstr ""
"##\n"
"## Шаблон РСС е-поруке за САБнзбд\n"
"## РСС шаблон ел. поште за САБнзбд\n"
"## Ово је Гепард шаблон\n"
"## Документација: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"## Нови редови и размаци су важни!\n"
"##\n"
"## Ово су заглавља е-поруке\n"
"Прима: $to\n"
"Шаље: $from\n"
"Датум: $date\n"
"Тема: САБнзбд је додао $amount посла у ред\n"
"Х-приоритет: 5\n"
"Х-МС-приоритет: 5\n"
"## Ово су заглавља ел. поште\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject САБнзбд је додао $amount посла у ред\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## После тога долази разрада, празни редови су потребни!\n"
"\n"
"Здраво,\n"
@@ -190,24 +190,24 @@ msgid ""
"Bye\n"
msgstr ""
"##\n"
"## Bad URL Fetch Email template for SABnzbd\n"
"## This a Cheetah template\n"
"## Documentation: http://sabnzbd.wikidot.com/email-templates\n"
"## Шаблон ел. поште лошег набављања адресе за САБнзбд\n"
"## Ово је Гепард шаблон\n"
"## Документација: http://sabnzbd.wikidot.com/email-templates\n"
"##\n"
"## Newlines and whitespace are significant!\n"
"## Нови редови и размаци су важни!\n"
"##\n"
"## These are the email headers\n"
"За: $to\n"
"Од: $from\n"
"Датум: $date\n"
"Сујјекат: SABnzbd није успео да преузме НЗБ\n"
"## Ово су заглавља ел. поште\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: САБнзбд није успео да преузме НЗБ\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## After this comes the body, the empty line is required!\n"
"## После тога долази разрада, празни редови су потребни!\n"
"\n"
"Здраво,\n"
"\n"
"SABnzbd није успео да преузме НЗБ од $url.\n"
"САБнзбд није успео да преузме НЗБ са$url.\n"
"Порука грешке је: $msg\n"
"\n"
"Поздрав\n"

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Andreas Lindberg <andypandyswe@gmail.com>\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-06-24 19:50+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
"Language-Team: Swedish <sv@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-04-26 05:45+0000\n"
"X-Generator: Launchpad (build 17430)\n"
"X-Launchpad-Export-Date: 2017-06-27 06:00+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""
@@ -72,10 +72,10 @@ msgstr ""
"## Newlines and whitespace are significant!\n"
"##\n"
"## These are the email headers\n"
"Till: $to\n"
"Från: $from\n"
"Datum: $date\n"
"Ämne: SABnzbd has <!--#if $status then \"completed\" else \"failed\" #--> "
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd has <!--#if $status then \"completed\" else \"failed\" #--> "
"job $name\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
@@ -145,10 +145,10 @@ msgstr ""
"## Newlines and whitespace are significant!\n"
"##\n"
"## These are the email headers\n"
"Till: $to\n"
"Från: $from\n"
"Datum: $date\n"
"Ämne: SABnzbd har lagt till $amount jobb i kön\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd har lagt till $amount jobb i kön\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## After this comes the body, the empty line is required!\n"
@@ -196,10 +196,10 @@ msgstr ""
"## Newlines and whitespace are significant!\n"
"##\n"
"## These are the email headers\n"
"Till: $to\n"
"Från: $from\n"
"Datum: $date\n"
"Ämne: SABnzbd misslyckades med att hämta en NZB -fil\n"
"To: $to\n"
"From: $from\n"
"Date: $date\n"
"Subject: SABnzbd misslyckades med att hämta en NZB -fil\n"
"X-priority: 5\n"
"X-MS-priority: 5\n"
"## After this comes the body, the empty line is required!\n"

View File

@@ -7,15 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-04-25 09:21+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2015-10-24 11:05+0000\n"
"Last-Translator: shypike <Unknown>\n"
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-10-25 05:43+0000\n"
"X-Generator: Launchpad (build 17812)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:55+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: email/email.tmpl:1
msgid ""

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

@@ -15,27 +15,21 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: sabnzbd/skintext.py:67 [Config->Scheduler]
msgid "Pause low prioirty jobs"
msgstr "Pause low priority jobs"
#: sabnzbd/skintext.py:68 [Config->Scheduler]
msgid "Pause normal prioirty jobs"
msgstr "Pause normal priority jobs"
#: sabnzbd/skintext.py:69 [Config->Scheduler]
msgid "Pause high prioirty jobs"
msgstr "Pause high priority jobs"
#: sabnzbd/skintext.py:70 [Config->Scheduler]
msgid "Resume low prioirty jobs"
msgstr "Resume low priority jobs"
#: sabnzbd/skintext.py:71 [Config->Scheduler]
msgid "Resume normal prioirty jobs"
msgstr "Resume normal priority jobs"
#: sabnzbd/skintext.py:72 [Config->Scheduler]
msgid "Resume high prioirty jobs"
msgstr "Resume high priority jobs"
@@ -48,80 +42,66 @@ msgstr ""
"click the button below.<br /><br /><strong><a "
"href=\"..\">Refresh</a></strong><br />"
#: sabnzbd/skintext.py:251 [Retry all failed jobs in History]
msgid "Retry all failed"
msgstr "Retry All Failed"
#: sabnzbd/skintext.py:54 [#: Config->Scheduler]
msgid "disable server"
msgstr "Disable server:"
#: sabnzbd/skintext.py:55 [#: Config->Scheduler]
msgid "enable server"
msgstr "Enable server:"
#: sabnzbd/emailer.py:117
msgid "The server didn't reply properly to the helo greeting"
msgstr "The server didn't reply properly to the hello greeting"
#: sabnzbd/interface.py:226
msgid "API Key missing, please enter the api key from Config->General into your 3rd party program:"
msgstr "API key missing, please enter the API key from Config->General into your 3rd party program:"
#: sabnzbd/interface.py:233
msgid "API Key incorrect, Use the api key from Config->General in your 3rd party program:"
msgstr "API key incorrect, Use the API key from Config->General in your 3rd party program:"
#: sabnzbd/skintext.py:330
msgid "HTTPS Chain Certifcates"
msgstr "HTTPS Chain Certificates"
#: sabnzbd/skintext.py:465
msgid "Replace Spaces in Foldername"
msgstr "Replace spaces in folder name"
#: sabnzbd/skintext.py:467
msgid "Replace dots in Foldername"
msgstr "Replace dots in folder name"
#: sabnzbd/skintext.py:693
msgid "Original Foldername"
msgstr "Original folder name"
#: sabnzbd/skintext.py:808
msgid "How long or untill when do you want to pause? (in English!)"
msgstr "How long or until when do you want to pause? (in English!)"
#: sabnzbd/skintext.py:917
msgid "Timeleft"
msgstr "Time left"
#: sabnzbd/skintext.py:791 # sabnzbd/skintext.py:871
msgid "Optionally specify a filename"
msgstr "Optionally specify a name"
#: sabnzbd/skintext.py:819 # sabnzbd/skintext.py:880
msgid "Confirm Queue Deletions"
msgstr "Confirm queue deletions"
#: sabnzbd/skintext.py:820 # sabnzbd/skintext.py:881
msgid "Confirm History Deletions"
msgstr "Confirm history deletions"
#: sabnzbd/skintext.py:288 [Do not translate Pystone]
msgid "System Performance (Pystone)"
msgstr "System performance (Pystone)"
#: sabnzbd/skintext.py:317 # sabnzbd/skintext.py:779
msgid "Web Interface"
msgstr "Web interface"
#: sabnzbd/notifier.py
msgid "Script returned exit code %s and output \"%s\""
msgstr "Notification script returned exit code %s and output \"%s\""
#: sabnzbd/skintext.py:333
msgid "If empty, the standard port will only listen to HTTPS."
msgstr "If empty, the SABnzbd Port set above will listen to HTTPS."
msgid "Posts will be paused untill they are at least this age. Setting job priority to Force will skip the delay."
msgstr "Posts will be paused until they are at least this age. Setting job priority to Force will skip the delay."
msgid "Support the project, Donate!"
msgstr "Support the project, donate!"

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

4812
po/main/he.po Normal file
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

@@ -5,7 +5,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-develop\n"
"Project-Id-Version: SABnzbd-2.2.0-develop\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: shypike@sabnzbd.org\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -13,71 +13,71 @@ msgstr ""
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 7bit\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr ""
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr ""
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr ""
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid "The installation directory has changed (now in \"Program Files\"). \\nIf you run SABnzbd as a service, you need to update the service settings."
msgstr ""
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr ""
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr ""
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr ""
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr ""
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr ""
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr ""
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid "This system requires the Microsoft runtime library VC90 to be installed first. Do you want to do that now?"
msgstr ""
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr ""
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr ""
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr ""
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid "You cannot overwrite an existing installation. \\n\\nClick `OK` to remove the previous version or `Cancel` to cancel this upgrade."
msgstr ""
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr ""

View File

@@ -7,33 +7,33 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-04-10 11:28+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
"Language-Team: Danish <da@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-04-14 05:48+0000\n"
"X-Generator: Launchpad (build 18352)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Vis udgivelsesbemærkninger"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Støt projektet, donér!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Luk venligst \"SABnzbd.exe\" først"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
@@ -41,31 +41,31 @@ msgstr ""
"Installationsmappen er ændret (nu i \"Program Files \"). \\nHvis du kører "
"SABnzbd som en tjeneste, skal du opdatere tjenesteindstillingerne."
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Dette vil afinstallere SABnzbd fra dit system"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Kør ved opstart"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Skrivebordsikon"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "NZB filtilknytning"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Slet program"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Slet indstillinger"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -73,19 +73,19 @@ msgstr ""
"Dette system kræver, at Microsoft runtime biblioteket VC90 skal installeres "
"først. Ønsker du at gøre det nu?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Downloader Microsoft runtime installationsfil..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Download fejl, prøv igen?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Kan ikke installere uden runtime bibliotek, prøv igen?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -94,7 +94,7 @@ msgstr ""
"fjerne den tidligere version eller `Annuller` for at annullere denne "
"opgradering."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Dine indstillinger og data vil blive bevaret."

View File

@@ -7,33 +7,33 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-05-22 08:00+0000\n"
"Last-Translator: larshuth <Unknown>\n"
"Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-05-23 06:10+0000\n"
"X-Generator: Launchpad (build 18387)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Versionshinweise anzeigen"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr "Starte SABnzbd"
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Bitte unterstützen Sie das Projekt durch eine Spende!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Schliessen Sie bitte zuerst \"SABnzbd.exe\"."
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
@@ -42,31 +42,31 @@ msgstr ""
"nWenn du SABnzbd als Service ausführst, musst du die Serviceeinstellungen "
"anpassen."
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Dies entfernt SABnzbd von Ihrem System"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Beim Systemstart ausführen"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Desktop-Symbol"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "Mit NZB-Dateien verknüpfen"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Programm löschen"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Einstellungen löschen"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -74,22 +74,22 @@ msgstr ""
"Dieses System erfordert die Installation der Laufzeitbibliothek VC90 von "
"Microsoft. Möchten Sie die Installation jetzt durchführen?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr ""
"Installationsprogramm für Microsoft-Laufzeitbibliothek wird "
"heruntergeladen..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Download-Fehler. Erneut versuchen?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr ""
"Installation ohne Laufzeitbibliothek nicht möglich. Erneut versuchen?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -98,7 +98,7 @@ msgstr ""
"Sie 'OK', um die vorherige Version zu entfernen oder 'Abbrechen' um die "
"Aktualisierung abzubrechen."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Ihre Einstellungen und Daten bleiben erhalten."

View File

@@ -7,63 +7,63 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Victor Herrero <victorhera@gmail.com>\n"
"Language-Team: Spanish <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-19 06:37+0000\n"
"X-Generator: Launchpad (build 18332)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Mostrar notas de la versión"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "¡Apoye el proyecto, haga una donación!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Por favor cierre primero \"SABnzbd.exe\""
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr ""
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Esto desinstalará SABnzbd de su sistema"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Ejecutar al inicio"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Icono del escritorio"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "Asociación de archivos NZB"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Eliminar programa"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Eliminar Ajustes"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -71,20 +71,20 @@ msgstr ""
"Este sistema requiere la ejecución de la biblioteca Microsoft runtime VC90 "
"que debe ser instalada. ¿Quieres hacerlo ahora?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Descargando el instalador de Microsoft runtime..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Error en la descarga, ¿probamos de nuevo?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr ""
"No se puede instalar sin la biblioteca runtime, ¿Lo volvemos a intentar?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -92,7 +92,7 @@ msgstr ""
"No es posible sobrescribir una instalación existente. \\n\\nPresione `OK' "
"para quitar la versión anterior o 'Cancelar' para cancelar la actualización."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Tus ajustes y datos se mantendrán intactos."

View File

@@ -7,33 +7,33 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-04-02 07:38+0000\n"
"Last-Translator: Paavo Rissanen <paavo.rissanen@outlook.com>\n"
"Language-Team: Finnish <fi@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-04-05 07:19+0000\n"
"X-Generator: Launchpad (build 18335)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Näytä julkaisutiedot"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr "Käynnistä SABnzbd"
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Tue projektia, lahjoita!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Ole hyvä ja sulje \"SABnzbd.exe\" ensin"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
@@ -41,31 +41,31 @@ msgstr ""
"Asennuskansio on muuttunut (nykyisin \"Program Files\"). \\nJos suoritat "
"SABnzbd:ta palveluna, sinun täytyy päivittää palvelun asetukset."
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Tämä poistaa SABnzbd:n tietokoneestasi"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Suorita käynnistyksen yhteydessä"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Työpöydän kuvake"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "NZB tiedostosidos"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Poista sovellus"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Poista asetukset"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -73,19 +73,19 @@ msgstr ""
"Tämä järjestelmä vaatii, että Microsoft runtime kirjasto VC90 täytyy asentaa "
"ensin. Haluatko asentaa sen nyt?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Ladataan Microsoft runtime asennusta..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Latausvirhe, yritä uudelleen?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Ei voida asentaa ilman runtime kirjastoa, yritä uudelleen?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -93,7 +93,7 @@ msgstr ""
"Et voi asentaa tätä vanhan asennuksen päälle. \\n\\nPaina `OK` poistaaksesi "
"edellisen version tai paina `Peruuta` peruuttaaksesi tämän päivityksen."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Asetuksiasi ja tietojasi ei poisteta."

View File

@@ -7,33 +7,33 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-03-21 08:58+0000\n"
"Last-Translator: Fred <88com88@gmail.com>\n"
"Language-Team: French <fr@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-22 06:58+0000\n"
"X-Generator: Launchpad (build 18334)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Afficher les notes de version"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr "Démarrer SABnzbd"
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Soutenez le projet, faites un don !"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Merci de fermer \"SABnzbd.exe\" avant l'installation"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
@@ -42,31 +42,31 @@ msgstr ""
"nSi vous exécutez SABnzbd en tant que service, vous devez mettre à jour les "
"paramètres du service."
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Ceci désinstallera SABnzbd de votre système"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Lancer au démarrage"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Icône sur le Bureau"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "Association des fichiers NZB"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Supprimer le programme"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Supprimer les paramètres"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -74,19 +74,19 @@ msgstr ""
"Ce système nécessite que la bibliothèque d'exécution Microsoft vc90 soit "
"installée en premier. Voulez-vous le faire maintenant?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Téléchargement de Microsoft runtime installer..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Erreur de téléchargement, réessayer ?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Impossible d'installer sans moteur d'exécution, réessayer?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -95,7 +95,7 @@ msgstr ""
"pour supprimer la version précédente ou `Annuler` pour annuler cette mise à "
"niveau."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Vos paramètres et données seront conservés."

98
po/nsis/he.po Normal file
View File

@@ -0,0 +1,98 @@
# Hebrew translation for sabnzbd
# Copyright (c) 2017 Rosetta Contributors and Canonical Ltd 2017
# This file is distributed under the same license as the sabnzbd package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2017.
#
msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-05-06 09:07+0000\n"
"Last-Translator: ION IL <Unknown>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "הראה הערות שחרור"
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr "התחל את SABnzbd"
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "תמוך במיזם, תרום!"
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "אנא סגור את \"SABnzbd.exe\" תחילה"
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr ""
"ספרית ההתקנה השתנתה (עכשיו ב-\"Program Files\"). \\nאם תריץ את SABnzbd בתור "
"שירות, אתה צריך לעדכן את הגדרות השירות."
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "זה יסיר את SABnzbd ממערכתך"
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "הפעל באתחול"
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "צלמית שולחן עבודה"
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "שיוך קבצי NZB"
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "מחק תכנית"
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "מחק הגדרות"
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
msgstr ""
"מערכת זו דורשת את ספרית זמן-אמת VC90 של Microsoft שתהיה מותקנת תחילה. האם "
"ברצונך להתקין אותה כעת?"
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "מוריד מתקין זמן-אמת של Microsoft..."
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "שגיאת הורדה, לנסות שוב?"
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "לא ניתן להתקין ללא ספרית זמן-אמת, לנסות שוב?"
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
msgstr ""
"אינך יכול לדרוס התקנה קיימת.\\n\\nלחץ על `אישור` כדי להסיר את הגרסה הקודמת "
"או על `ביטול` כדי לבטל שדרוג זה."
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "ההגדרות והנתונים שלך יישמרו."

View File

@@ -7,63 +7,63 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-19 06:37+0000\n"
"X-Generator: Launchpad (build 18332)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Vis versjonsmerknader"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Støtt prosjektet, donèr!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Vennligst lukk \"SABnzbd.exe\" først"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr ""
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Dette vil avinstallere SABnzbd fra ditt system"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Kjør ved oppstart"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Skrivebordsikon"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "NZB-filassosiering"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Fjern program"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Slett innstillinger"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -71,19 +71,19 @@ msgstr ""
"Dette sytemet krever at Microsoft runtime library VC90 er installert først. "
"Ønsker du å gjøre dette nå?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Laster ned Microsoft runtime installer..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Nedlasting feilet, prøve på nytt?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Kan ikke installere uten runtime library, prøve på nytt?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -92,7 +92,7 @@ msgstr ""
"fjerne tidligere installasjon, eller 'Avbryt' for å avbryte denne "
"oppgraderingen."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Dine innstillinger og data vil bli tatt vare på."

View File

@@ -7,33 +7,33 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-03-19 09:47+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
"Language-Team: Dutch <nl@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-20 06:21+0000\n"
"X-Generator: Launchpad (build 18332)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Toon opmerkingen bij deze uitgave"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr "Start SABnzbd"
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Steun het project, doneer!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Sluit \"SABnzbd.exe\" eerst af"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
@@ -42,31 +42,31 @@ msgstr ""
"SABnzbd als een service draait, zul je de service instellingen moeten "
"aanpassen."
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Dit verwijdert SABnzbd van je systeem"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Starten met Windows"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Bureaubladpictogram"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "NZB-bestanden openen met SABnzbd"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Programma verwijderen"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Verwijder alle instellingen"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -74,19 +74,19 @@ msgstr ""
"Op dit systeem moeten eerst de Microsoft runtime bibliotheek VC90 "
"geïnstalleerd worden. Wilt u dat nu doen?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Downloaden van de Microsoft bibliotheek"
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Download mislukt, opnieuw proberen?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Installeren heeft geen zin zonder de bibliotheek, opnieuw proberen?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -94,7 +94,7 @@ msgstr ""
"U kunt geen bestaande installatie overschrijven.\\n\\nKlik op `OK` om de "
"vorige versie te verwijderen of op `Annuleren` om te stoppen."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Je instellingen en bestanden blijven behouden."

View File

@@ -7,63 +7,63 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Tomasz 'Zen' Napierala <tomasz@napierala.org>\n"
"Language-Team: Polish <pl@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-19 06:37+0000\n"
"X-Generator: Launchpad (build 18332)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Pokaż informacje o wydaniu"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Wspomóż projekt!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Najpierw zamknij SABnzbd.exe"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr ""
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "To odinstaluje SABnzbd z systemu"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Uruchom wraz z systemem"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Ikona pulpitu"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "powiązanie pliku NZB"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Usuń program"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Skasuj obecne ustawienia"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -71,19 +71,19 @@ msgstr ""
"Ten system wymaga najpierw zainstalowania bibliotek Microsoft VC90. Czy "
"chcesz wykonać teraz instalację?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Pobieranie instalatora bibliotek Microsoft..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Problem z pobieraniem, spróbować ponownie?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Nie można wykonać instalacji bez bibliotek, spróbować ponownie?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -91,7 +91,7 @@ msgstr ""
"Nie można nadpisać istniejącej instalacji. \\n\\n Naciśnij `OK`, aby usunąć "
"poprzednia wersję lub `Anuluj` aby anulować aktualizację."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Twoje ustawienia i dane zostaną zachowane."

View File

@@ -7,63 +7,63 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: lrrosa <Unknown>\n"
"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-19 06:37+0000\n"
"X-Generator: Launchpad (build 18332)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Mostrar Notas de Lançamento"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Apoie o projeto. Faça uma doação!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Por favor, feche \"SABnzbd.exe\" primeiro"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr ""
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Isso irá desinstalar SABnzbd de seu sistema"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Executar na inicialização"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Ícone na Área de Trabalho"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "Associação com Arquivos NZB"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Excluir o Programa"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Apagar Configurações"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -71,19 +71,19 @@ msgstr ""
"Este sistema precisa que a biblioteca runtime Microsoft VC90 seja instalada "
"antes. Você quer fazer isso agora?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Baixando o instalador runtime da Microsoft ..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Houve um erro de download. Quer tentar novamente?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Não é possível instalar sem a biblioteca runtime. Quer repetir?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -91,7 +91,7 @@ msgstr ""
"Você não pode substituir uma instalação existente. \\n\\nClique `OK` para "
"remover a versão anterior ou `Cancelar` para cancelar esta atualização."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Suas configurações e os dados serão preservados."

View File

@@ -7,63 +7,63 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: nicusor <Unknown>\n"
"Language-Team: Romanian <ro@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-19 06:37+0000\n"
"X-Generator: Launchpad (build 18332)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Arată Notele de Publicare"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Susţine proiectul, Donează!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Închideţi mai întâi \"SABnzbd.exe\""
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr ""
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Acest lucru va dezinstala SABnzbd din sistem"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Executare la pornire"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Icoană Desktop"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "Asociere cu Fişierele NZB"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Şterge Program"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Ştergeţi Setări"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -71,19 +71,19 @@ msgstr ""
"Acest sistem necesită librăria Microsoft VC90 instalată. Dortiți să faceți "
"asta acum ?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Descărcare rutină instalare Microsoft..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Eroare descărcare, încerc din nou?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Nu pot instala fără rutină librărie, încerc din nou?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -91,7 +91,7 @@ msgstr ""
"Nu puteți suprascrie instalarea existentă. \\n\\nClick `OK` pentru a elimina "
"versiunea anterioară sau `Anulare` pentru a anula actualizarea."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Setările şi informaţiile vor fi salvate."

View File

@@ -7,63 +7,63 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Pavel Maryanov <Unknown>\n"
"Language-Team: Russian <gnu@mx.ru>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-19 06:37+0000\n"
"X-Generator: Launchpad (build 18332)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Показать заметки о выпуске"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Поддержите проект. Сделайте пожертвование!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Завершите сначала работу процесса SABnzbd.exe"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr ""
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Приложение SABnzbd будет удалено из вашей системы"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Запускать вместе с системой"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Значок на рабочем столе"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "Ассоциировать с файлами NZB"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Удалить программу"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Удалить параметры"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -71,21 +71,21 @@ msgstr ""
"Для этой системы сначала необходимо установить библиотеку времени выполнения "
"Microsoft VC90. Сделать это сейчас?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Загрузка программы установки Microsoft..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Ошибка загрузки. Повторить попытку?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr ""
"Не удаётся выполнить установку без библиотеки времени выполнения. Повторить "
"попытку?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -94,6 +94,6 @@ msgstr ""
"удалить предыдущую версию, нажмите кнопку «ОК». Чтобы отменить обновление, "
"нажмите кнопку «Отмена»."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Ваши параметры и данные будут сохранены."

View File

@@ -7,64 +7,64 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Ozzii <Unknown>\n"
"Language-Team: Launchpad Serbian Translators\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-19 06:37+0000\n"
"X-Generator: Launchpad (build 18332)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
"Language: sr\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Прикажи белешке о издању"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Подржите пројекат, дајте добровољан прилог!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Прво затворите „SABnzbd.exe“"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr ""
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Ово ће уклонити САБнзбд са вашег система"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Покрени са системом"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Иконица радне површи"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "Придруживање НЗБ датотеке"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Обриши програм"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Обриши подешавања"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -72,19 +72,19 @@ msgstr ""
"Овај систем захтева да буде прво инсталирана Мајкрософтова извршна "
"библиотека „VC90“. Да ли желите то да урадите?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Преузимам Мајкрософтов извршни програм за инсталацију..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Грешка у преузимању, да поновим?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Не могу да инсталирам без извршне библиотеке, да поновим?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -92,7 +92,7 @@ msgstr ""
"Не можете да препишете постојећу инсталацију. \\n\\nПритисните „У реду“ да "
"уклоните претходно издање или „Откажи“ да поништите ову надоградњу."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Ваша подешавања и подаци биће сачувани."

View File

@@ -7,63 +7,63 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
"Last-Translator: Andreas Lindberg <andypandyswe@gmail.com>\n"
"Language-Team: Swedish <sv@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-03-19 06:37+0000\n"
"X-Generator: Launchpad (build 18332)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "Visa releasenoteringar"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr ""
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "Donera och stöd detta projekt!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "Var vänlig stäng \"SABnzbd.exe\" först"
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr ""
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "Detta kommer att avinstallera SABnzbd från systemet"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "Kör vid uppstart"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "Skrivbordsikon"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "NZB Filassosication"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "Radera programmet"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "Radera inställningar"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
@@ -71,19 +71,19 @@ msgstr ""
"Detta system kräver att Microsofts runtimebibliotek VC90 är installerat. "
"Vill du göra detta nu?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "Laddar ned Microsofts runtimeinstaller..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "Misslyckat nedladdningsförsök, försök igen?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "Kan inte installera utan runtimebibliotek, försök igen?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
@@ -92,7 +92,7 @@ msgstr ""
"avinstallera tidigare version eller 'Avbryt' för att avbryta denna "
"uppgradering."
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "Dina inställningar och ditt data kommer att bevaras."

View File

@@ -7,87 +7,87 @@ msgid ""
msgstr ""
"Project-Id-Version: sabnzbd\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2017-03-18 21:42+0000\n"
"POT-Creation-Date: 2017-06-22 20:42+0000\n"
"PO-Revision-Date: 2017-05-28 17:17+0000\n"
"Last-Translator: ninjai <ninjai.us@gmail.com>\n"
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2017-05-29 06:02+0000\n"
"X-Generator: Launchpad (build 18391)\n"
"X-Launchpad-Export-Date: 2017-06-23 05:56+0000\n"
"X-Generator: Launchpad (build 18416)\n"
#: NSIS_Installer.nsi:473
#: NSIS_Installer.nsi
msgid "Show Release Notes"
msgstr "显示版本说明"
#: NSIS_Installer.nsi:475
#: NSIS_Installer.nsi
msgid "Start SABnzbd"
msgstr "启动 SABnzbd"
#: NSIS_Installer.nsi:477
#: NSIS_Installer.nsi
msgid "Support the project, Donate!"
msgstr "支持该项目,捐助!"
#: NSIS_Installer.nsi:479
#: NSIS_Installer.nsi
msgid "Please close \"SABnzbd.exe\" first"
msgstr "请先关闭 \"SABnzbd.exe\""
#: NSIS_Installer.nsi:481
#: NSIS_Installer.nsi
msgid ""
"The installation directory has changed (now in \"Program Files\"). \\nIf you "
"run SABnzbd as a service, you need to update the service settings."
msgstr "安装目录已更改(现在位于 \"Program Files\" 目录)。\\n如果以服务模式运行你需要更新相应服务的设置。"
#: NSIS_Installer.nsi:483
#: NSIS_Installer.nsi
msgid "This will uninstall SABnzbd from your system"
msgstr "这将从您的系统中卸载 SABnzbd"
#: NSIS_Installer.nsi:485
#: NSIS_Installer.nsi
msgid "Run at startup"
msgstr "启动时运行"
#: NSIS_Installer.nsi:487
#: NSIS_Installer.nsi
msgid "Desktop Icon"
msgstr "桌面图标"
#: NSIS_Installer.nsi:489
#: NSIS_Installer.nsi
msgid "NZB File association"
msgstr "NZB 文件关联"
#: NSIS_Installer.nsi:491
#: NSIS_Installer.nsi
msgid "Delete Program"
msgstr "删除程序"
#: NSIS_Installer.nsi:493
#: NSIS_Installer.nsi
msgid "Delete Settings"
msgstr "删除设置"
#: NSIS_Installer.nsi:495
#: NSIS_Installer.nsi
msgid ""
"This system requires the Microsoft runtime library VC90 to be installed "
"first. Do you want to do that now?"
msgstr "该系统需要先安装 Microsoft 运行时库 VC90。是否希望立即安装?"
#: NSIS_Installer.nsi:497
#: NSIS_Installer.nsi
msgid "Downloading Microsoft runtime installer..."
msgstr "正在下载 Microsoft 运行时安装程序..."
#: NSIS_Installer.nsi:499
#: NSIS_Installer.nsi
msgid "Download error, retry?"
msgstr "下载出错,重试?"
#: NSIS_Installer.nsi:501
#: NSIS_Installer.nsi
msgid "Cannot install without runtime library, retry?"
msgstr "没有运行时库无法安装,重试?"
#: NSIS_Installer.nsi:503
#: NSIS_Installer.nsi
msgid ""
"You cannot overwrite an existing installation. \\n\\nClick `OK` to remove "
"the previous version or `Cancel` to cancel this upgrade."
msgstr "不可以覆盖安装。\\n\\n点击“确定”可移除旧版或点击“取消”取消升级。"
#: NSIS_Installer.nsi:505
#: NSIS_Installer.nsi
msgid "Your settings and data will be preserved."
msgstr "您的设置及数据将会保留。"

View File

@@ -15,9 +15,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Imported to be referenced from other files directly
from sabnzbd.version import __version__, __baseline__
__configversion__ = 18
__queueversion__ = 8
import os
import logging
@@ -25,8 +24,6 @@ import datetime
import tempfile
import cPickle
import pickle
import zipfile
import glob
import gzip
import subprocess
import time
@@ -34,7 +31,7 @@ import socket
import cherrypy
import sys
import re
from threading import RLock, Lock, Condition, Thread
from threading import Lock, Thread
try:
import sleepless
except ImportError:
@@ -43,7 +40,7 @@ except ImportError:
##############################################################################
# Determine platform flags
##############################################################################
WIN32 = DARWIN = POSIX = FOUNDATION = WIN64 = False
WIN32 = DARWIN = FOUNDATION = WIN64 = False
KERNEL32 = None
if os.name == 'nt':
@@ -57,7 +54,6 @@ if os.name == 'nt':
elif os.name == 'posix':
ORG_UMASK = os.umask(18)
os.umask(ORG_UMASK)
POSIX = True
import platform
if platform.system().lower() == 'darwin':
DARWIN = True
@@ -110,9 +106,9 @@ import sabnzbd.cfg as cfg
import sabnzbd.database
import sabnzbd.lang as lang
import sabnzbd.api
from sabnzbd.decorators import synchronized, synchronized_CV, IO_LOCK
from sabnzbd.decorators import synchronized, notify_downloader
from sabnzbd.constants import NORMAL_PRIORITY, VALID_ARCHIVES, GIGI, \
REPAIR_REQUEST, QUEUE_FILE_NAME, QUEUE_VERSION, QUEUE_FILE_TMPL
REPAIR_REQUEST, QUEUE_FILE_NAME, QUEUE_VERSION, QUEUE_FILE_TMPL
import sabnzbd.getipaddress as getipaddress
LINUX_POWER = powersup.HAVE_DBUS
@@ -161,7 +157,7 @@ WEBUI_READY = False
LAST_WARNING = None
LAST_ERROR = None
EXTERNAL_IPV6 = False
LAST_HISTORY_UPDATE = time.time()
LAST_HISTORY_UPDATE = 1
# Performance measure for dashboard
PYSTONE_SCORE = 0
@@ -177,10 +173,10 @@ __SHUTTING_DOWN__ = False
##############################################################################
def sig_handler(signum=None, frame=None):
global SABSTOP, WINTRAY
if sabnzbd.WIN32 and type(signum) != type(None) and DAEMON and signum == 5:
if sabnzbd.WIN32 and signum is not None and DAEMON and signum == 5:
# Ignore the "logoff" event when running as a Win32 daemon
return True
if type(signum) != type(None):
if signum is not None:
logging.warning(T('Signal %s caught, saving and exiting...'), signum)
try:
save_state()
@@ -580,12 +576,9 @@ def unpause_all():
##############################################################################
# NZB_LOCK Methods
# NZB Saving Methods
##############################################################################
NZB_LOCK = Lock()
@synchronized(NZB_LOCK)
def backup_exists(filename):
""" Return True if backup exists and no_dupes is set """
path = cfg.nzb_backup_dir.get_path()
@@ -599,7 +592,6 @@ def backup_nzb(filename, data):
save_compressed(path, filename, data)
@synchronized(NZB_LOCK)
def save_compressed(folder, filename, data):
""" Save compressed NZB file in folder """
# Need to go to the save folder to
@@ -625,9 +617,9 @@ def save_compressed(folder, filename, data):
##############################################################################
# CV synchronized (notifies downloader)
# Unsynchronized methods
##############################################################################
@synchronized_CV
def add_nzbfile(nzbfile, pp=None, script=None, cat=None, priority=NORMAL_PRIORITY, nzbname=None, reuse=False, password=None):
""" Add disk-based NZB file, optional attributes,
'reuse' flag will suppress duplicate detection
@@ -697,9 +689,6 @@ def add_nzbfile(nzbfile, pp=None, script=None, cat=None, priority=NORMAL_PRIORIT
keep=keep, reuse=reuse, password=password)
##############################################################################
# Unsynchronized methods
##############################################################################
def enable_server(server):
""" Enable server (scheduler only) """
try:
@@ -809,7 +798,6 @@ def change_queue_complete_action(action, new=True):
# keep the name of the action for matching the current select in queue.tmpl
QUEUECOMPLETE = action
QUEUECOMPLETEACTION = _action
QUEUECOMPLETEARG = _argument
@@ -854,7 +842,7 @@ def keep_awake():
def CheckFreeSpace():
""" Check if enough disk space is free, if not pause downloader and send email """
if cfg.download_free() and not sabnzbd.downloader.Downloader.do.paused:
if misc.diskspace(cfg.download_dir.get_path(), force=True)[1] < cfg.download_free.get_float() / GIGI:
if misc.diskspace(force=True)['download_dir'][1] < cfg.download_free.get_float() / GIGI:
logging.warning(T('Too little diskspace forcing PAUSE'))
# Pause downloader, but don't save, since the disk is almost full!
Downloader.do.pause(save=False)
@@ -865,7 +853,6 @@ def CheckFreeSpace():
# Data IO #
################################################################################
@synchronized(IO_LOCK)
def get_new_id(prefix, folder, check_list=None):
""" Return unique prefixed admin identifier within folder
optionally making sure that id is not in the check_list.
@@ -886,7 +873,6 @@ def get_new_id(prefix, folder, check_list=None):
raise IOError
@synchronized(IO_LOCK)
def save_data(data, _id, path, do_pickle=True, silent=False):
""" Save data to a diskfile """
if not silent:
@@ -899,14 +885,17 @@ def save_data(data, _id, path, do_pickle=True, silent=False):
with open(path, 'wb') as data_file:
if do_pickle:
if cfg.use_pickle():
cPickle.dump(data, data_file)
else:
pickle.dump(data, data_file)
else:
cPickle.dump(data, data_file)
else:
data_file.write(data)
break
except:
if t == 2:
if silent:
# This can happen, probably a removed folder
pass
elif t == 2:
logging.error(T('Saving %s failed'), path)
logging.info("Traceback: ", exc_info=True)
else:
@@ -914,7 +903,6 @@ def save_data(data, _id, path, do_pickle=True, silent=False):
time.sleep(0.1)
@synchronized(IO_LOCK)
def load_data(_id, path, remove=True, do_pickle=True, silent=False):
""" Read data from disk file """
path = os.path.join(path, _id)
@@ -946,7 +934,6 @@ def load_data(_id, path, remove=True, do_pickle=True, silent=False):
return data
@synchronized(IO_LOCK)
def remove_data(_id, path):
""" Remove admin file """
path = os.path.join(path, _id)
@@ -958,7 +945,6 @@ def remove_data(_id, path):
logging.debug("Failed to remove %s", path)
@synchronized(IO_LOCK)
def save_admin(data, _id):
""" Save data in admin folder in specified format """
path = os.path.join(cfg.admin_dir.get_path(), _id)
@@ -982,7 +968,6 @@ def save_admin(data, _id):
time.sleep(0.1)
@synchronized(IO_LOCK)
def load_admin(_id, remove=False, silent=False):
""" Read data in admin folder in specified format """
path = os.path.join(cfg.admin_dir.get_path(), _id)
@@ -1170,10 +1155,6 @@ def highest_server(me):
return sabnzbd.downloader.Downloader.do.highest_server(me)
def proxy_pre_queue(name, pp, cat, script, priority, size, groups):
return sabnzbd.newsunpack.pre_queue(name, pp, cat, script, priority, size, groups)
def test_ipv6():
""" Check if external IPv6 addresses are reachable """
if not cfg.selftest_host():
@@ -1199,3 +1180,11 @@ def test_ipv6():
except:
logging.debug('Test IPv6: Problem during IPv6 connect. Disabling IPv6. Reason: %s', sys.exc_info()[0])
return False
def history_updated():
""" To make sure we always have a fresh history """
sabnzbd.LAST_HISTORY_UPDATE += 1
# Never go over the limit
if sabnzbd.LAST_HISTORY_UPDATE+1 >= sys.maxint:
sabnzbd.LAST_HISTORY_UPDATE = 1

View File

@@ -27,7 +27,7 @@ import time
import json
import cherrypy
import locale
import socket
from threading import Thread
try:
locale.setlocale(locale.LC_ALL, "")
@@ -40,15 +40,14 @@ try:
except ImportError:
pass
import sabnzbd
from sabnzbd.constants import VALID_ARCHIVES, Status, \
TOP_PRIORITY, REPAIR_PRIORITY, HIGH_PRIORITY, HIGH_PRIORITY, NORMAL_PRIORITY, LOW_PRIORITY, \
TOP_PRIORITY, REPAIR_PRIORITY, HIGH_PRIORITY, NORMAL_PRIORITY, LOW_PRIORITY, \
KIBI, MEBI, GIGI, JOB_ADMIN
import sabnzbd.config as config
import sabnzbd.cfg as cfg
from sabnzbd.downloader import Downloader
from sabnzbd.nzbqueue import NzbQueue, set_priority, sort_queue, scan_jobs, repair_job
from sabnzbd.nzbqueue import NzbQueue
import sabnzbd.scheduler as scheduler
from sabnzbd.skintext import SKIN_TEXT
from sabnzbd.utils.json import JsonWriter
@@ -165,14 +164,8 @@ def _api_del_config(name, output, kwargs):
def _api_qstatus(name, output, kwargs):
""" API: accepts output """
if output == 'json':
# Compatibility Fix:
# Old qstatus did not have a keyword, so do not use one now.
keyword = ''
else:
keyword = 'queue'
info, pnfo_list, bytespersec = build_queue()
return report(output, keyword='', data=remove_callable(info))
return report(output, data=remove_callable(info))
def _api_queue(name, output, kwargs):
@@ -253,7 +246,7 @@ def _api_queue_priority(output, value, kwargs):
priority = int(value2)
except:
return report(output, _MSG_INT_VALUE)
pos = set_priority(value, priority)
pos = NzbQueue.do.set_priority(value, priority)
# Returns the position in the queue, -1 is incorrect job-id
return report(output, keyword='position', data=pos)
except:
@@ -267,7 +260,7 @@ def _api_queue_sort(output, value, kwargs):
sort = kwargs.get('sort')
direction = kwargs.get('dir', '')
if sort:
sort_queue(sort, direction)
NzbQueue.do.sort_queue(sort, direction)
return report(output)
else:
return report(output, _MSG_NO_VALUE2)
@@ -491,13 +484,14 @@ def _api_history(name, output, kwargs):
value = kwargs.get('value', '')
start = int_conv(kwargs.get('start'))
limit = int_conv(kwargs.get('limit'))
last_history_update = int_conv(kwargs.get('last_history_update', 0))
search = kwargs.get('search')
failed_only = kwargs.get('failed_only')
categories = kwargs.get('category')
last_history_update = kwargs.get('last_history_update', 0)
# Do we need to send anything?
if int(last_history_update) == int(sabnzbd.LAST_HISTORY_UPDATE):
if last_history_update == sabnzbd.LAST_HISTORY_UPDATE:
return report(output, keyword='history', data=False)
if categories and not isinstance(categories, list):
@@ -517,15 +511,13 @@ def _api_history(name, output, kwargs):
history_db.remove_failed(search)
if special in ('all', 'completed'):
history_db.remove_completed(search)
# Update the last check time
sabnzbd.LAST_HISTORY_UPDATE = time.time()
sabnzbd.history_updated()
return report(output)
elif value:
jobs = value.split(',')
for job in jobs:
del_hist_job(job, del_files)
# Update the last check time
sabnzbd.LAST_HISTORY_UPDATE = time.time()
sabnzbd.history_updated()
return report(output)
else:
return report(output, _MSG_NO_VALUE)
@@ -539,7 +531,7 @@ def _api_history(name, output, kwargs):
search=search, failed_only=failed_only,
categories=categories,
output=output)
history['last_history_update'] = int(sabnzbd.LAST_HISTORY_UPDATE)
history['last_history_update'] = sabnzbd.LAST_HISTORY_UPDATE
history['version'] = sabnzbd.__version__
return report(output, keyword='history', data=remove_callable(history))
else:
@@ -686,7 +678,7 @@ def _api_osx_icon(name, output, kwargs):
def _api_rescan(name, output, kwargs):
""" API: accepts output """
scan_jobs(all=False, action=True)
NzbQueue.do.scan_jobs(all=False, action=True)
return report(output)
@@ -1196,7 +1188,7 @@ def build_status(skip_dashboard=False, output=None):
info['logfile'] = sabnzbd.LOGFILE
info['weblogfile'] = sabnzbd.WEBLOGFILE
info['loglevel'] = str(cfg.log_level())
info['folders'] = [xml_name(item) for item in sabnzbd.nzbqueue.scan_jobs(all=False, action=False)]
info['folders'] = [xml_name(item) for item in NzbQueue.do.scan_jobs(all=False, action=False)]
info['configfn'] = xml_name(config.get_filename())
# Dashboard: Speed of System
@@ -1340,7 +1332,6 @@ def build_queue(start=0, limit=0, trans=False, output=None, search=None):
priority = pnfo.priority
mbleft = (bytesleft / MEBI)
mb = (bytes / MEBI)
missing = pnfo.missing
slot = {'index': n, 'nzo_id': str(nzo_id)}
slot['unpackopts'] = str(sabnzbd.opts_to_pp(pnfo.repair, pnfo.unpack, pnfo.delete))
@@ -1355,6 +1346,7 @@ def build_queue(start=0, limit=0, trans=False, output=None, search=None):
slot['sizeleft'] = format_bytes(bytesleft)
slot['percentage'] = "%s" % (int(((mb - mbleft) / mb) * 100)) if mb != mbleft else '0'
slot['missing'] = pnfo.missing
slot['mbmissing'] = "%.2f" % (pnfo.bytes_missing / MEBI)
if not output:
slot['mb_fmt'] = locale.format('%d', int(mb), True)
slot['mbdone_fmt'] = locale.format('%d', int(mb - mbleft), True)
@@ -1548,7 +1540,7 @@ def retry_job(job, new_nzb, password):
else:
path = history_db.get_path(job)
if path:
nzo_id = repair_job(platform_encode(path), new_nzb, password)
nzo_id = NzbQueue.do.repair_job(platform_encode(path), new_nzb, password)
history_db.remove_history(job)
return nzo_id
return None
@@ -1592,6 +1584,7 @@ def Tspec(txt):
else:
return txt
_SKIN_CACHE = {} # Stores pre-translated acronyms
# This special is to be used in interface.py for template processing
# to be passed for the $T function: so { ..., 'T' : Ttemplate, ...}
@@ -1629,8 +1622,7 @@ def build_header(webdir='', output=None):
if speed_limit_abs <= 0:
speed_limit_abs = ''
disk_total1, disk_free1 = diskspace(cfg.download_dir.get_path())
disk_total2, disk_free2 = diskspace(cfg.complete_dir.get_path())
diskspace_info = diskspace()
header = {}
@@ -1662,18 +1654,17 @@ def build_header(webdir='', output=None):
header['session'] = cfg.api_key()
header['new_release'], header['new_rel_url'] = sabnzbd.NEW_VERSION
header['version'] = sabnzbd.__version__
header['paused'] = Downloader.do.paused or Downloader.do.postproc
header['pause_int'] = scheduler.pause_int()
header['paused_all'] = sabnzbd.PAUSED_ALL
header['diskspace1'] = "%.2f" % disk_free1
header['diskspace2'] = "%.2f" % disk_free2
header['diskspace1_norm'] = to_units(disk_free1 * GIGI)
header['diskspace2_norm'] = to_units(disk_free2 * GIGI)
header['diskspacetotal1'] = "%.2f" % disk_total1
header['diskspacetotal2'] = "%.2f" % disk_total2
header['diskspace1'] = "%.2f" % diskspace_info['download_dir'][1]
header['diskspace2'] = "%.2f" % diskspace_info['complete_dir'][1]
header['diskspace1_norm'] = to_units(diskspace_info['download_dir'][1] * GIGI)
header['diskspace2_norm'] = to_units(diskspace_info['complete_dir'][1] * GIGI)
header['diskspacetotal1'] = "%.2f" % diskspace_info['download_dir'][0]
header['diskspacetotal2'] = "%.2f" % diskspace_info['complete_dir'][0]
header['loadavg'] = loadavg()
header['speedlimit'] = "{1:0.{0}f}".format(int(speed_limit % 1 > 0), speed_limit)
header['speedlimit_abs'] = "%s" % speed_limit_abs
@@ -1812,9 +1803,6 @@ def build_history(start=None, limit=None, verbose=False, verbose_list=None, sear
cookie = cherrypy.request.cookie
if 'history_verbosity' in cookie:
k = cookie['history_verbosity'].value
c_path = cookie['history_verbosity']['path']
c_age = cookie['history_verbosity']['max-age']
c_version = cookie['history_verbosity']['version']
if k == 'all':
details_show_all = True

View File

@@ -30,24 +30,26 @@ from sabnzbd.constants import GIGI, ANFO
ARTICLE_LOCK = threading.Lock()
class ArticleCache(object):
""" Operations on lists/dicts are atomic enough that we
do not have to put locks. Only the cache-size needs
a lock since the integer needs to stay synced.
With less locking, the decoder and assembler do not
have to wait on each other.
"""
do = None
def __init__(self):
self.__cache_limit_org = 0
self.__cache_limit = 0
self.__cache_size = 0
self.__article_list = [] # List of buffered articles
self.__article_table = {} # Dict of buffered articles
ArticleCache.do = self
@synchronized(ARTICLE_LOCK)
def cache_info(self):
return ANFO(len(self.__article_list), abs(self.__cache_size), self.__cache_limit_org)
@synchronized(ARTICLE_LOCK)
def new_limit(self, limit):
""" Called when cache limit changes """
self.__cache_limit_org = limit
@@ -57,23 +59,28 @@ class ArticleCache(object):
self.__cache_limit = min(limit, GIGI)
@synchronized(ARTICLE_LOCK)
def increase_cache_size(self, value):
self.__cache_size += value
@synchronized(ARTICLE_LOCK)
def decrease_cache_size(self, value):
self.__cache_size -= value
def reserve_space(self, data):
""" Is there space left in the set limit? """
data_size = sys.getsizeof(data) * 64
self.__cache_size += data_size
self.increase_cache_size(data_size)
if self.__cache_size + data_size > self.__cache_limit:
return False
else:
return True
@synchronized(ARTICLE_LOCK)
def free_reserve_space(self, data):
""" Remove previously reserved space """
data_size = sys.getsizeof(data) * 64
self.__cache_size -= data_size
self.decrease_cache_size(data_size)
return self.__cache_size + data_size < self.__cache_limit
@synchronized(ARTICLE_LOCK)
def save_article(self, article, data):
nzf = article.nzf
nzo = nzf.nzo
@@ -81,8 +88,6 @@ class ArticleCache(object):
if nzo.is_gone():
# Do not discard this article because the
# file might still be processed at this moment!!
if sabnzbd.LOG_ALL:
logging.debug("%s is discarded", article)
return
saved_articles = article.nzf.nzo.saved_articles
@@ -93,7 +98,6 @@ class ArticleCache(object):
if self.__cache_limit:
if self.__cache_limit < 0:
self.__add_to_cache(article, data)
else:
data_size = len(data)
@@ -102,7 +106,7 @@ class ArticleCache(object):
# Flush oldest article in cache
old_article = self.__article_list.pop(0)
old_data = self.__article_table.pop(old_article)
self.__cache_size -= len(old_data)
self.decrease_cache_size(len(old_data))
# No need to flush if this is a refreshment article
if old_article != article:
self.__flush_article(old_article, old_data)
@@ -116,7 +120,6 @@ class ArticleCache(object):
else:
self.__flush_article(article, data)
@synchronized(ARTICLE_LOCK)
def load_article(self, article):
data = None
nzo = article.nzf.nzo
@@ -124,9 +127,7 @@ class ArticleCache(object):
if article in self.__article_list:
data = self.__article_table.pop(article)
self.__article_list.remove(article)
self.__cache_size -= len(data)
if sabnzbd.LOG_ALL:
logging.debug("Loaded %s from cache", article)
self.decrease_cache_size(len(data))
elif article.art_id:
data = sabnzbd.load_data(article.art_id, nzo.workpath, remove=True,
do_pickle=False, silent=True)
@@ -136,23 +137,19 @@ class ArticleCache(object):
return data
@synchronized(ARTICLE_LOCK)
def flush_articles(self):
self.__cache_size = 0
while self.__article_list:
article = self.__article_list.pop(0)
data = self.__article_table.pop(article)
self.__flush_article(article, data)
self.__cache_size = 0
@synchronized(ARTICLE_LOCK)
def purge_articles(self, articles):
if sabnzbd.LOG_ALL:
logging.debug("Purgeable articles -> %s", articles)
for article in articles:
if article in self.__article_list:
self.__article_list.remove(article)
data = self.__article_table.pop(article)
self.__cache_size -= len(data)
self.decrease_cache_size(len(data))
if article.art_id:
sabnzbd.remove_data(article.art_id, article.nzf.nzo.workpath)
@@ -163,14 +160,10 @@ class ArticleCache(object):
if nzo.is_gone():
# Do not discard this article because the
# file might still be processed at this moment!!
if sabnzbd.LOG_ALL:
logging.debug("%s is discarded", article)
return
art_id = article.get_art_id()
if art_id:
if sabnzbd.LOG_ALL:
logging.debug("Flushing %s to disk", article)
# Save data, but don't complain when destination folder is missing
# because this flush may come after completion of the NZO.
sabnzbd.save_data(data, art_id, nzo.workpath, do_pickle=False, silent=True)
@@ -179,14 +172,12 @@ class ArticleCache(object):
def __add_to_cache(self, article, data):
if article in self.__article_table:
self.__cache_size -= len(self.__article_table[article])
self.decrease_cache_size(len(self.__article_table[article]))
else:
self.__article_list.append(article)
self.__article_table[article] = data
self.__cache_size += len(data)
if sabnzbd.LOG_ALL:
logging.debug("Added %s to cache", article)
self.increase_cache_size(len(data))
# Create the instance

View File

@@ -37,7 +37,7 @@ from sabnzbd.articlecache import ArticleCache
from sabnzbd.postproc import PostProcessor
import sabnzbd.downloader
import sabnzbd.utils.rarfile as rarfile
from sabnzbd.encoding import unicoder, deunicode, is_utf8
from sabnzbd.encoding import unicoder, is_utf8
from sabnzbd.rating import Rating
@@ -134,14 +134,12 @@ class Assembler(Thread):
filter, reason = nzo_filtered_by_rating(nzo)
if filter == 1:
logging.warning(Ta('WARNING: Paused job "%s" because of rating (%s)'), nzo.final_name, reason)
logging.warning(T('WARNING: Paused job "%s" because of rating (%s)'), nzo.final_name, reason)
nzo.pause()
elif filter == 2:
logging.warning(Ta('WARNING: Aborted job "%s" because of rating (%s)'), nzo.final_name, reason)
logging.warning(T('WARNING: Aborted job "%s" because of rating (%s)'), nzo.final_name, reason)
nzo.fail_msg = T('Aborted, rating filter matched (%s)') % reason
sabnzbd.nzbqueue.NzbQueue.do.end_job(nzo)
nzf.completed = True
else:
sabnzbd.nzbqueue.NzbQueue.do.remove(nzo.nzo_id, add_to_history=False, cleanup=False)
PostProcessor.do.process(nzo)

View File

@@ -73,18 +73,6 @@ def last_month_day(tm):
return day
def this_month_day(t=None):
""" Return current day of the week, month 1..31 """
t = t or time.localtime(t)
return time.localtime(t).tm_mday
def this_week_day(t=None):
""" Return current day of the week 1..7 """
t = t or time.localtime(t)
return time.localtime(t).tm_wday + 1
def next_month(t):
""" Return timestamp for start of next month """
now = time.localtime(t)

View File

@@ -22,7 +22,7 @@ import re
import sabnzbd
from sabnzbd.constants import DEF_HOST, DEF_PORT, DEF_STDINTF, DEF_ADMIN_DIR, \
DEF_DOWNLOAD_DIR, DEF_NZBBACK_DIR, DEF_SCANRATE, DEF_COMPLETE_DIR
DEF_DOWNLOAD_DIR, DEF_NZBBACK_DIR, DEF_SCANRATE, DEF_COMPLETE_DIR, QUEUE_VERSION
from sabnzbd.config import OptionBool, OptionNumber, OptionPassword, \
OptionDir, OptionStr, OptionList, no_nonsense, \
@@ -91,6 +91,7 @@ enable_7zip = OptionBool('misc', 'enable_7zip', True)
enable_recursive = OptionBool('misc', 'enable_recursive', True)
enable_filejoin = OptionBool('misc', 'enable_filejoin', True)
enable_tsjoin = OptionBool('misc', 'enable_tsjoin', True)
enable_par_cleanup = OptionBool('misc', 'enable_par_cleanup', True)
enable_all_par = OptionBool('misc', 'enable_all_par', False)
ignore_unrar_dates = OptionBool('misc', 'ignore_unrar_dates', False)
overwrite_files = OptionBool('misc', 'overwrite_files', False)
@@ -208,8 +209,9 @@ cache_limit = OptionStr('misc', 'cache_limit')
web_dir = OptionStr('misc', 'web_dir', DEF_STDINTF)
web_color = OptionStr('misc', 'web_color', '')
cleanup_list = OptionList('misc', 'cleanup_list')
warned_old_queue = OptionBool('misc', 'warned_old_queue9', False)
warned_old_queue = OptionNumber('misc', 'warned_old_queue', QUEUE_VERSION)
notified_new_skin = OptionNumber('misc', 'notified_new_skin', 0)
converted_nzo_pickles = OptionBool('misc', 'converted_nzo_pickles', False)
unwanted_extensions = OptionList('misc', 'unwanted_extensions')
action_on_unwanted_extensions = OptionNumber('misc', 'action_on_unwanted_extensions', 0)

View File

@@ -24,6 +24,9 @@ import re
import logging
import threading
import shutil
import time
import random
from hashlib import md5
import sabnzbd.misc
from sabnzbd.constants import CONFIG_VERSION, NORMAL_PRIORITY, DEFAULT_PRIORITY, MAX_WIN_DFOLDER
from sabnzbd.utils import configobj
@@ -791,7 +794,6 @@ def _read_config(path, try_backup=False):
def save_config(force=False):
""" Update Setup file with current option values """
global CFG, database, modified
if 0: assert isinstance(CFG, configobj.ConfigObj)
if not (modified or force):
return True
@@ -1065,15 +1067,6 @@ def validate_safedir(root, value, default):
return T('Error: Queue not empty, cannot change folder.'), None
def validate_dir_exists(root, value, default):
""" Check if directory exists """
p = sabnzbd.misc.real_path(root, value)
if os.path.exists(p):
return None, value
else:
return T('Folder "%s" does not exist') % p, None
def validate_notempty(root, value, default):
""" If value is empty, return default """
if value:
@@ -1084,12 +1077,6 @@ def validate_notempty(root, value, default):
def create_api_key():
""" Return a new randomized API_KEY """
import time
try:
from hashlib import md5
except ImportError:
from md5 import md5
import random
# Create some values to seed md5
t = str(time.time())
r = str(random.random())

View File

@@ -25,9 +25,9 @@ POSTPROC_QUEUE_VERSION = 2
REC_RAR_VERSION = 500
PNFO = namedtuple('PNFO', 'repair unpack delete script nzo_id filename password '
'unpackstrht msgid category url bytes_left bytes avg_stamp '
'avg_date finished_files active_files queued_files status priority missing')
PNFO = namedtuple('PNFO', 'repair unpack delete script nzo_id filename password unpackstrht '
'msgid category url bytes_left bytes avg_stamp avg_date finished_files '
'active_files queued_files status priority missing bytes_missing')
QNFO = namedtuple('QNFO', 'bytes bytes_left bytes_left_previous_page list q_size_list q_fullsize')
@@ -55,19 +55,14 @@ REPAIR_REQUEST = 'repair-all.sab'
SABYENC_VERSION_REQUIRED = '3.0.2'
DB_HISTORY_VERSION = 1
DB_QUEUE_VERSION = 1
DB_HISTORY_NAME = 'history%s.db' % DB_HISTORY_VERSION
DB_QUEUE_NAME = 'queue%s.db' % DB_QUEUE_VERSION
DEF_DOWNLOAD_DIR = 'Downloads/incomplete'
DEF_COMPLETE_DIR = 'Downloads/complete'
DEF_ADMIN_DIR = 'admin'
DEF_LOG_DIR = 'logs'
DEF_NZBBACK_DIR = ''
DEF_LANGUAGE = 'locale'
DEF_INTERFACES = 'interfaces'
DEF_INT_LANGUAGE = 'locale'
DEF_EMAIL_TMPL = 'email'
DEF_STDCONFIG = 'Config'
DEF_STDINTF = 'Glitter'
@@ -82,11 +77,7 @@ DEF_LOG_ERRFILE = 'sabnzbd.error.log'
DEF_LOG_CHERRY = 'cherrypy.log'
DEF_CACHE_LIMIT = '450M'
DEF_TIMEOUT = 60
MIN_TIMEOUT = 10
MAX_TIMEOUT = 200
DEF_LOGLEVEL = 1
DEF_SCANRATE = 5
DEF_QRATE = 0
MAX_DECODE_QUEUE = 10
LIMIT_DECODE_QUEUE = 100
MAX_WARNINGS = 20

View File

@@ -217,6 +217,7 @@ class HistoryDB(object):
def remove_completed(self, search=None):
""" Remove all completed jobs from the database, optional with `search` pattern """
search = convert_search(search)
logging.info('Removing all completed jobs from history')
return self.execute("""DELETE FROM history WHERE name LIKE ? AND status = 'Completed'""", (search,), save=True)
def get_failed_paths(self, search=None):
@@ -231,6 +232,7 @@ class HistoryDB(object):
def remove_failed(self, search=None):
""" Remove all failed jobs from the database, optional with `search` pattern """
search = convert_search(search)
logging.info('Removing all failed jobs from history')
return self.execute("""DELETE FROM history WHERE name LIKE ? AND status = 'Failed'""", (search,), save=True)
def remove_history(self, jobs=None):
@@ -243,6 +245,7 @@ class HistoryDB(object):
for job in jobs:
self.execute("""DELETE FROM history WHERE nzo_id=?""", (job,))
logging.info('Removing job %s from history', job)
self.save()
@@ -255,6 +258,7 @@ class HistoryDB(object):
downloaded, completeness, fail_message, url_info, bytes, series, md5sum, password)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", t):
self.save()
logging.info('Added job %s to history', nzo.final_name)
def fetch_history(self, start=None, limit=None, search=None, failed_only=0, categories=None):
""" Return records for specified jobs """
@@ -531,7 +535,7 @@ def unpack_history_info(item):
if 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'):
if 'action_line' not in item:
item['action_line'] = ''
return item

View File

@@ -19,7 +19,6 @@
sabnzbd.decoder - article decoder
"""
import Queue
import binascii
import logging
import re
@@ -31,7 +30,6 @@ from sabnzbd.constants import Status, MAX_DECODE_QUEUE, LIMIT_DECODE_QUEUE, SABY
import sabnzbd.articlecache
import sabnzbd.downloader
import sabnzbd.nzbqueue
import sabnzbd.cfg as cfg
from sabnzbd.encoding import yenc_name_fixer
from sabnzbd.misc import match_str
@@ -224,7 +222,7 @@ class Decoder(Thread):
return True
msg = T('%s => missing from all servers, discarding') % article
logging.debug(msg)
logging.info(msg)
article.nzf.nzo.inc_log('missing_art_log', msg)
return False

View File

@@ -20,9 +20,7 @@
##############################################################################
from threading import RLock, Condition
NZBQUEUE_LOCK = RLock()
CV = Condition(NZBQUEUE_LOCK)
IO_LOCK = RLock()
DOWNLOADER_CV = Condition(RLock())
def synchronized(lock):
def wrap(f):
@@ -36,13 +34,13 @@ def synchronized(lock):
return wrap
def synchronized_CV(func):
global CV
def notify_downloader(func):
global DOWNLOADER_CV
def call_func(*params, **kparams):
CV.acquire()
DOWNLOADER_CV.acquire()
try:
return func(*params, **kparams)
finally:
CV.notifyAll()
CV.release()
DOWNLOADER_CV.notify_all()
DOWNLOADER_CV.release()
return call_func

View File

@@ -99,7 +99,6 @@ def ProcessArchiveFile(filename, path, pp=None, script=None, cat=None, catdir=No
returns (status, nzo_ids)
status: -1==Error/Retry, 0==OK, 1==Ignore
"""
from sabnzbd.nzbqueue import add_nzo
nzo_ids = []
if catdir is None:
catdir = cat
@@ -145,7 +144,7 @@ def ProcessArchiveFile(filename, path, pp=None, script=None, cat=None, catdir=No
sabnzbd.nzbqueue.NzbQueue.do.remove(nzo_id, add_to_history=False)
nzo.nzo_id = nzo_id
nzo_id = None
nzo_ids.append(add_nzo(nzo))
nzo_ids.append(sabnzbd.nzbqueue.NzbQueue.do.add(nzo))
nzo.update_rating()
zf.close()
try:
@@ -170,7 +169,6 @@ def ProcessSingleFile(filename, path, pp=None, script=None, cat=None, catdir=Non
returns (status, nzo_ids)
status: -2==Error/retry, -1==Error, 0==OK, 1==OK-but-ignorecannot-delete
"""
from sabnzbd.nzbqueue import add_nzo
nzo_ids = []
if catdir is None:
catdir = cat
@@ -231,7 +229,7 @@ def ProcessSingleFile(filename, path, pp=None, script=None, cat=None, catdir=Non
# Re-use existing nzo_id, when a "future" job gets it payload
sabnzbd.nzbqueue.NzbQueue.do.remove(nzo_id, add_to_history=False)
nzo.nzo_id = nzo_id
nzo_ids.append(add_nzo(nzo, quiet=reuse))
nzo_ids.append(sabnzbd.nzbqueue.NzbQueue.do.add(nzo, quiet=reuse))
nzo.update_rating()
try:
if not keep:

View File

@@ -30,7 +30,7 @@ import sys
import Queue
import sabnzbd
from sabnzbd.decorators import synchronized, synchronized_CV, CV
from sabnzbd.decorators import synchronized, notify_downloader, DOWNLOADER_CV
from sabnzbd.constants import MAX_DECODE_QUEUE, LIMIT_DECODE_QUEUE
from sabnzbd.decoder import Decoder
from sabnzbd.newswrapper import NewsWrapper, request_server_info
@@ -252,12 +252,12 @@ class Downloader(Thread):
return
@synchronized_CV
@notify_downloader
def set_paused_state(self, state):
""" Set downloader to specified paused state """
self.paused = state
@synchronized_CV
@notify_downloader
def resume(self):
# Do not notify when SABnzbd is still starting
if self.paused and sabnzbd.WEB_DIR:
@@ -265,7 +265,7 @@ class Downloader(Thread):
notifier.send_notification("SABnzbd", T('Resuming'), 'download')
self.paused = False
@synchronized_CV
@notify_downloader
def pause(self, save=True):
""" Pause the downloader, optionally saving admin """
if not self.paused:
@@ -279,22 +279,20 @@ class Downloader(Thread):
if save:
ArticleCache.do.flush_articles()
@synchronized_CV
def delay(self):
logging.debug("Delaying")
self.delayed = True
@synchronized_CV
@notify_downloader
def undelay(self):
logging.debug("Undelaying")
self.delayed = False
@synchronized_CV
def wait_for_postproc(self):
logging.info("Waiting for post-processing to finish")
self.postproc = True
@synchronized_CV
@notify_downloader
def resume_from_postproc(self):
logging.info("Post-processing finished, resuming download")
self.postproc = False
@@ -302,7 +300,6 @@ class Downloader(Thread):
def disconnect(self):
self.force_disconnect = True
@synchronized_CV
def limit_speed(self, value):
''' Set the actual download speed in Bytes/sec
When 'value' ends with a '%' sign or is within 1-100, it is interpreted as a pecentage of the maximum bandwidth
@@ -356,7 +353,6 @@ class Downloader(Thread):
""" Return True when this server has the highest priority of the active ones
0 is the highest priority
"""
for server in self.servers:
if server is not me and server.active and server.priority < me.priority:
return False
@@ -421,7 +417,6 @@ class Downloader(Thread):
while 1:
for server in self.servers:
if 0: assert isinstance(server, Server) # Assert only for debug purposes
for nw in server.busy_threads[:]:
if (nw.nntp and nw.nntp.error_msg) or (nw.timeout and time.time() > nw.timeout):
if nw.nntp and nw.nntp.error_msg:
@@ -445,7 +440,6 @@ class Downloader(Thread):
# Restart pending, don't add new articles
continue
if 0: assert isinstance(server, Server) # Assert only for debug purposes
if not server.idle_threads or server.restart or self.is_paused() or self.shutdown or self.delayed or self.postproc:
continue
@@ -453,7 +447,6 @@ class Downloader(Thread):
continue
for nw in server.idle_threads[:]:
if 0: assert isinstance(nw, NewsWrapper) # Assert only for debug purposes
if nw.timeout:
if time.time() < nw.timeout:
continue
@@ -471,10 +464,11 @@ class Downloader(Thread):
break
if server.retention and article.nzf.nzo.avg_stamp < time.time() - server.retention:
# Article too old for the server, treat as missing
if sabnzbd.LOG_ALL:
logging.debug('Article %s too old for %s', article.article, server.id)
self.decode(article, None, None)
# Let's get rid of all the articles for this server at once
logging.info('Job %s too old for %s, moving on', article.nzf.nzo.work_name, server.id)
while article:
self.decode(article, None, None)
article = article.nzf.nzo.get_article(server, self.servers)
break
server.idle_threads.remove(nw)
@@ -553,11 +547,11 @@ class Downloader(Thread):
time.sleep(1.0)
CV.acquire()
DOWNLOADER_CV.acquire()
while (sabnzbd.nzbqueue.NzbQueue.do.is_empty() or self.is_paused() or self.delayed or self.postproc) and not \
self.shutdown and not self.__restart:
CV.wait()
CV.release()
DOWNLOADER_CV.wait()
DOWNLOADER_CV.release()
self.force_disconnect = False
@@ -714,7 +708,7 @@ class Downloader(Thread):
elif nw.status_code in ('411', '423', '430'):
done = True
logging.info('Thread %s@%s: Article %s missing (error=%s)',
logging.debug('Thread %s@%s: Article %s missing (error=%s)',
nw.thrdnum, nw.server.id, article.article, nw.status_code)
nw.clear_data()
@@ -866,7 +860,7 @@ class Downloader(Thread):
del self._timers[server_id]
self.init_server(server_id, server_id)
@synchronized_CV
@notify_downloader
@synchronized(TIMER_LOCK)
def unblock(self, server_id):
# Remove timer
@@ -885,7 +879,7 @@ class Downloader(Thread):
for server_id in self._timers.keys():
self.unblock(server_id)
@synchronized_CV
@notify_downloader
@synchronized(TIMER_LOCK)
def check_timers(self):
""" Make sure every server without a non-expired timer is active """
@@ -905,11 +899,10 @@ class Downloader(Thread):
logging.debug('Forcing activation of server %s', server.id)
self.init_server(server.id, server.id)
@synchronized_CV
def update_server(self, oldserver, newserver):
self.init_server(oldserver, newserver)
@synchronized_CV
@notify_downloader
def wakeup(self):
""" Just rattle the semaphore """
pass
@@ -920,12 +913,12 @@ class Downloader(Thread):
def stop():
CV.acquire()
DOWNLOADER_CV.acquire()
try:
Downloader.do.stop()
finally:
CV.notifyAll()
CV.release()
DOWNLOADER_CV.notify_all()
DOWNLOADER_CV.release()
try:
Downloader.do.join()
except:

View File

@@ -354,7 +354,7 @@ def _prepare_message(txt):
msg.set_payload('\n'.join(payload), code)
# Check for proper encoding, else call it explicitly
if not msg.has_key('Content-Transfer-Encoding'):
if 'Content-Transfer-Encoding' not in msg:
encode_quopri(msg)
return msg.as_string()

View File

@@ -51,14 +51,6 @@ def change_fsys(value):
auto_fsys()
def reliable_unpack_names():
""" See if it is safe to rely on unrar names """
if sabnzbd.WIN32 or sabnzbd.DARWIN:
return True
else:
return gUTF
def platform_encode(p):
""" Return Unicode name, if not already Unicode, decode with UTF-8 or latin1 """
if isinstance(p, str):
@@ -70,22 +62,6 @@ def platform_encode(p):
return p
def name_fixer(p):
""" 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:
try:
return p.decode(codepage)
except:
return p.decode('cp1252', 'replace').replace('?', '!')
else:
return p
def yenc_name_fixer(p):
""" Return Unicode name of 8bit ASCII string, first try utf-8, then cp1252 """
try:
@@ -145,13 +121,6 @@ def unicoder(p, force=False):
return unicode(str(p))
def unicode2local(p):
""" Convert Unicode filename to appropriate local encoding
Leave ? characters for uncovertible characters
"""
return p
def xml_name(p, keep_escape=False, encoding=None):
""" Prepare name for use in HTML/XML contect """
@@ -173,19 +142,6 @@ def xml_name(p, keep_escape=False, encoding=None):
return escape(p).encode('ascii', 'xmlcharrefreplace')
def encode_for_xml(ustr, encoding='ascii'):
""" Encode unicode_data for use as XML or HTML, with characters outside
of the encoding converted to XML numeric character references.
"""
if isinstance(ustr, unicode):
pass
elif isinstance(ustr, str):
ustr = ustr.decode(codepage, 'replace')
else:
ustr = unicode(str(ustr))
return ustr.encode(encoding, 'xmlcharrefreplace')
class LatinFilter(Filter):
""" Make sure Cheetah gets only Unicode strings """

View File

@@ -21,7 +21,6 @@ sabnzbd.interface - webinterface
import os
import time
import datetime
import cherrypy
import logging
import urllib
@@ -41,7 +40,6 @@ from Cheetah.Template import Template
from sabnzbd.misc import real_path, to_units, from_units, \
time_format, long_path, calc_age, \
cat_to_opts, int_conv, globber, globber_full, remove_all, get_base_url
from sabnzbd.panic import panic_old_queue
from sabnzbd.newswrapper import GetServerParms
from sabnzbd.rating import Rating
from sabnzbd.bpsmeter import BPSMeter
@@ -60,9 +58,8 @@ from sabnzbd.utils.sslinfo import ssl_version, ssl_protocols_labels
from sabnzbd.utils.diskspeed import diskspeedmeasure
from sabnzbd.utils.getperformance import getpystone
from sabnzbd.constants import \
NORMAL_PRIORITY, MEBI, DEF_SKIN_COLORS, DEF_STDINTF, DEF_STDCONFIG, DEF_MAIN_TMPL, \
DEFAULT_PRIORITY
from sabnzbd.constants import NORMAL_PRIORITY, MEBI, DEF_SKIN_COLORS, DEF_STDINTF, \
DEF_STDCONFIG, DEF_MAIN_TMPL, DEFAULT_PRIORITY
from sabnzbd.lang import list_languages, set_language
@@ -330,11 +327,6 @@ class MainPage(object):
if not check_login():
raise NeedLogin()
if sabnzbd.OLD_QUEUE and not cfg.warned_old_queue():
cfg.warned_old_queue.set(True)
config.save_config()
return panic_old_queue()
if not cfg.notified_new_skin() and cfg.web_dir() != 'Glitter':
logging.warning(T('Try our new skin Glitter! Fresh new design that is optimized for desktop and mobile devices. Go to Config -> General to change your skin.'))
if not cfg.notified_new_skin():
@@ -386,31 +378,6 @@ class MainPage(object):
# Redirect to the setup wizard
raise cherrypy.HTTPRedirect('/sabnzbd/wizard/')
def add_handler(self, kwargs):
if not check_access():
return Protected()
url = kwargs.get('url', '')
pp = kwargs.get('pp')
script = kwargs.get('script')
cat = kwargs.get('cat')
priority = kwargs.get('priority')
redirect = kwargs.get('redirect')
nzbname = kwargs.get('nzbname')
url = Strip(url)
if url:
sabnzbd.add_url(url, pp, script, cat, priority, nzbname)
if not redirect:
redirect = self.__root
raise cherrypy.HTTPRedirect(redirect)
@cherrypy.expose
def addURL(self, **kwargs):
msg = check_session(kwargs)
if msg:
return msg
raise self.add_handler(kwargs)
@cherrypy.expose
def addFile(self, **kwargs):
msg = check_session(kwargs)
@@ -664,7 +631,7 @@ class NzoPage(object):
n = 0
for pnfo in pnfo_list:
if pnfo.nzo_id == nzo_id:
nzo = sabnzbd.nzbqueue.get_nzo(nzo_id)
nzo = NzbQueue.do.get_nzo(nzo_id)
repair = pnfo.repair
unpack = pnfo.unpack
delete = pnfo.delete
@@ -737,7 +704,7 @@ class NzoPage(object):
script = kwargs.get('script', None)
cat = kwargs.get('cat', None)
priority = kwargs.get('priority', None)
nzo = sabnzbd.nzbqueue.get_nzo(nzo_id)
nzo = NzbQueue.do.get_nzo(nzo_id)
if index is not None:
NzbQueue.do.switch(nzo_id, index)
@@ -785,7 +752,7 @@ class NzoPage(object):
elif kwargs['action_key'] == 'Bottom':
NzbQueue.do.move_bottom_bulk(nzo_id, nzf_ids)
if sabnzbd.nzbqueue.get_nzo(nzo_id):
if NzbQueue.do.get_nzo(nzo_id):
url = cherrypy.lib.httputil.urljoin(self.__root, nzo_id)
else:
url = cherrypy.lib.httputil.urljoin(self.__root, '../queue')
@@ -835,17 +802,6 @@ class QueuePage(object):
NzbQueue.do.remove_all(kwargs.get('search'))
raise queueRaiser(self.__root, kwargs)
@cherrypy.expose
def removeNzf(self, **kwargs):
msg = check_session(kwargs)
if msg:
return msg
nzo_id = kwargs.get('nzo_id')
nzf_id = kwargs.get('nzf_id')
if nzo_id and nzf_id:
NzbQueue.do.remove_nzf(nzo_id, nzf_id, delete=True)
raise queueRaiser(self.__root, kwargs)
@cherrypy.expose
def change_queue_complete_action(self, **kwargs):
""" Action or script to be performed once the queue has been completed
@@ -964,7 +920,7 @@ class QueuePage(object):
msg = check_session(kwargs)
if msg:
return msg
sabnzbd.nzbqueue.set_priority(kwargs.get('nzo_id'), kwargs.get('priority'))
NzbQueue.do.set_priority(kwargs.get('nzo_id'), kwargs.get('priority'))
raise queueRaiser(self.__root, kwargs)
@cherrypy.expose
@@ -972,7 +928,7 @@ class QueuePage(object):
msg = check_session(kwargs)
if msg:
return msg
sabnzbd.nzbqueue.sort_queue('avg_age', kwargs.get('dir'))
NzbQueue.do.sort_queue('avg_age', kwargs.get('dir'))
raise queueRaiser(self.__root, kwargs)
@cherrypy.expose
@@ -980,7 +936,7 @@ class QueuePage(object):
msg = check_session(kwargs)
if msg:
return msg
sabnzbd.nzbqueue.sort_queue('name', kwargs.get('dir'))
NzbQueue.do.sort_queue('name', kwargs.get('dir'))
raise queueRaiser(self.__root, kwargs)
@cherrypy.expose
@@ -988,25 +944,9 @@ class QueuePage(object):
msg = check_session(kwargs)
if msg:
return msg
sabnzbd.nzbqueue.sort_queue('size', kwargs.get('dir'))
NzbQueue.do.sort_queue('size', kwargs.get('dir'))
raise queueRaiser(self.__root, kwargs)
@cherrypy.expose
def set_speedlimit(self, **kwargs):
msg = check_session(kwargs)
if msg:
return msg
Downloader.do.limit_speed(int_conv(kwargs.get('value')))
raise Raiser(self.__root)
@cherrypy.expose
def set_pause(self, **kwargs):
msg = check_session(kwargs)
if msg:
return msg
scheduler.plan_resume(int_conv(kwargs.get('value')))
raise Raiser(self.__root)
##############################################################################
class HistoryPage(object):
@@ -1179,33 +1119,6 @@ class HistoryPage(object):
del_hist_job(job, del_files=True)
raise Raiser(self.__root)
@cherrypy.expose
def show_edit_rating(self, **kwargs):
msg = check_session(kwargs)
if msg:
return msg
self.__edit_rating = kwargs.get('job')
raise queueRaiser(self.__root, kwargs)
@cherrypy.expose
def action_edit_rating(self, **kwargs):
flag_map = {'spam': Rating.FLAG_SPAM, 'encrypted': Rating.FLAG_ENCRYPTED, 'expired': Rating.FLAG_EXPIRED}
msg = check_session(kwargs)
if msg:
return msg
try:
if kwargs.get('send'):
video = kwargs.get('video') if kwargs.get('video') != "-" else None
audio = kwargs.get('audio') if kwargs.get('audio') != "-" else None
flag = flag_map.get(kwargs.get('rating_flag'))
detail = kwargs.get('expired_host') if kwargs.get('expired_host') != '<Host>' else None
if cfg.rating_enable():
Rating.do.update_user_rating(kwargs.get('job'), video, audio, flag, detail)
except:
pass
self.__edit_rating = None
raise queueRaiser(self.__root, kwargs)
##############################################################################
class ConfigPage(object):
@@ -1251,7 +1164,7 @@ class ConfigPage(object):
new[svr] = {}
conf['servers'] = new
conf['folders'] = sabnzbd.nzbqueue.scan_jobs(all=False, action=False)
conf['folders'] = NzbQueue.do.scan_jobs(all=False, action=False)
template = Template(file=os.path.join(sabnzbd.WEB_DIR_CONFIG, 'config.tmpl'),
filter=FILTER, searchList=[conf], compilerSettings=DIRECTIVES)
@@ -1303,10 +1216,11 @@ def orphan_delete(kwargs):
if path:
path = platform_encode(path)
path = os.path.join(long_path(cfg.download_dir.get_path()), path)
logging.info('Removing orphaned job %s', path)
remove_all(path, recursive=True)
def orphan_delete_all():
paths = sabnzbd.nzbqueue.scan_jobs(all=False, action=False)
paths = NzbQueue.do.scan_jobs(all=False, action=False)
for path in paths:
kwargs = {'name': path}
orphan_delete(kwargs)
@@ -1316,10 +1230,11 @@ def orphan_add(kwargs):
if path:
path = platform_encode(path)
path = os.path.join(long_path(cfg.download_dir.get_path()), path)
sabnzbd.nzbqueue.repair_job(path, None, None)
logging.info('Re-adding orphaned job %s', path)
NzbQueue.do.repair_job(path, None, None)
def orphan_add_all():
paths = sabnzbd.nzbqueue.scan_jobs(all=False, action=False)
paths = NzbQueue.do.scan_jobs(all=False, action=False)
for path in paths:
kwargs = {'name': path}
orphan_add(kwargs)
@@ -1385,13 +1300,13 @@ class ConfigFolders(object):
##############################################################################
SWITCH_LIST = \
('par2_multicore', 'multipar', 'par_option', 'top_only', 'ssl_ciphers',
('par2_multicore', 'par_option', 'top_only', 'ssl_ciphers',
'auto_sort', 'propagation_delay', 'auto_disconnect', 'flat_unpack',
'safe_postproc', 'no_dupes', 'replace_spaces', 'replace_dots', 'replace_illegal',
'safe_postproc', 'no_dupes', 'replace_spaces', 'replace_dots',
'ignore_samples', 'pause_on_post_processing', 'nice', 'ionice',
'pre_script', 'pause_on_pwrar', 'sfv_check', 'folder_rename', 'load_balancing',
'quota_size', 'quota_day', 'quota_resume', 'quota_period',
'pre_check', 'max_art_tries', 'max_art_opt', 'fail_hopeless_jobs', 'enable_all_par',
'pre_check', 'max_art_tries', 'fail_hopeless_jobs', 'enable_all_par',
'enable_recursive', 'no_series_dupes', 'script_can_fail', 'new_nzb_on_failure',
'unwanted_extensions', 'action_on_unwanted_extensions', 'sanitize_safe',
'rating_enable', 'rating_api_key', 'rating_filter_enable',
@@ -1459,13 +1374,13 @@ class ConfigSwitches(object):
##############################################################################
SPECIAL_BOOL_LIST = \
('start_paused', 'no_penalties', 'ignore_wrong_unrar', 'overwrite_files',
('start_paused', 'no_penalties', 'ignore_wrong_unrar', 'overwrite_files', 'enable_par_cleanup',
'queue_complete_pers', 'api_warnings', 'ampm', 'enable_unrar', 'enable_unzip', 'enable_7zip',
'enable_filejoin', 'enable_tsjoin', 'allow_streaming', 'ignore_unrar_dates', 'par2_multicore',
'osx_menu', 'osx_speed', 'win_menu', 'use_pickle', 'allow_incomplete_nzb', 'rss_filenames',
'ipv6_hosting', 'keep_awake', 'empty_postproc', 'html_login', 'wait_for_dfolder',
'warn_empty_nzb', 'enable_bonjour','allow_duplicate_files', 'warn_dupl_jobs',
'backup_for_duplicates', 'disable_api_key', 'api_logging', 'enable_meta'
'multipar', 'osx_menu', 'osx_speed', 'win_menu', 'use_pickle', 'allow_incomplete_nzb',
'rss_filenames', 'ipv6_hosting', 'keep_awake', 'empty_postproc', 'html_login', 'wait_for_dfolder',
'max_art_opt', 'warn_empty_nzb', 'enable_bonjour','allow_duplicate_files', 'warn_dupl_jobs',
'replace_illegal', 'backup_for_duplicates', 'disable_api_key', 'api_logging', 'enable_meta',
)
SPECIAL_VALUE_LIST = \
('size_limit', 'folder_max_length', 'fsys_type', 'movie_rename_limit', 'nomedia_marker',
@@ -1658,28 +1573,6 @@ class ConfigGeneral(object):
else:
raise Raiser(self.__root)
@cherrypy.expose
def generateAPIKey(self, **kwargs):
msg = check_session(kwargs)
if msg:
return msg
logging.debug('API Key Changed')
cfg.api_key.set(config.create_api_key())
config.save_config()
raise Raiser(self.__root)
@cherrypy.expose
def generateNzbKey(self, **kwargs):
msg = check_session(kwargs)
if msg:
return msg
logging.debug('NZB Key Changed')
cfg.nzb_key.set(config.create_api_key())
config.save_config()
raise Raiser(self.__root)
def change_web_dir(web_dir):
try:
@@ -2604,16 +2497,6 @@ class Status(object):
cherrypy.response.headers['Content-Disposition'] = 'attachment;filename="sabnzbd.log"'
return log_data
@cherrypy.expose
def showweb(self, **kwargs):
msg = check_session(kwargs)
if msg:
return msg
if sabnzbd.WEBLOGFILE:
return cherrypy.lib.static.serve_file(sabnzbd.WEBLOGFILE, "application/x-download", "attachment")
else:
return "Web logging is off!"
@cherrypy.expose
def clearwarnings(self, **kwargs):
msg = check_session(kwargs)
@@ -2976,7 +2859,7 @@ def rss_history(url, limit=50, search=None):
rss = RSS()
rss.channel.title = "SABnzbd History"
rss.channel.description = "Overview of completed downloads"
rss.channel.link = "http://sabnzbd.org/"
rss.channel.link = "https://sabnzbd.org/"
rss.channel.language = "en"
items, _fetched_items, _max_items = build_history(limit=limit, search=search)
@@ -3023,7 +2906,7 @@ def rss_warnings():
rss = RSS()
rss.channel.title = "SABnzbd Warnings"
rss.channel.description = "Overview of warnings/errors"
rss.channel.link = "http://sabnzbd.org/"
rss.channel.link = "https://sabnzbd.org/"
rss.channel.language = "en"
for warn in sabnzbd.GUIHANDLER.content():

View File

@@ -141,6 +141,7 @@ LanguageTable = {
'fr': ('French', 'Français', 0),
'gl': ('Galician', 'Galego', 0),
'de': ('German', 'Deutsch', 0),
'he': ('Hebrew', 'עִבְרִית‎', 1255),
'hz': ('Herero', 'Otjiherero', 0),
'ho': ('Hiri Motu', 'Hiri Motu', 0),
'hu': ('Hungarian', 'Magyar', 0),

View File

@@ -237,6 +237,11 @@ def replace_win_devices(name):
if lname == dev or lname.startswith(dev + '.'):
name = '_' + name
break
# Remove special NTFS filename
if lname.startswith('$mft'):
name = name.replace('$', 'S', 1)
return name
@@ -846,12 +851,9 @@ def get_cache_limit():
##############################################################################
# Locked directory operations
# Directory operations
##############################################################################
DIR_LOCK = threading.RLock()
@synchronized(DIR_LOCK)
def get_unique_path(dirpath, n=0, create_dir=True):
""" Determine a unique folder or filename """
@@ -871,7 +873,6 @@ def get_unique_path(dirpath, n=0, create_dir=True):
return get_unique_path(dirpath, n=n + 1, create_dir=create_dir)
@synchronized(DIR_LOCK)
def get_unique_filename(path):
""" Check if path is unique. If not, add number like: "/path/name.NUM.ext". """
num = 1
@@ -884,7 +885,6 @@ def get_unique_filename(path):
return path
@synchronized(DIR_LOCK)
def create_dirs(dirpath):
""" Create directory tree, obeying permissions """
if not os.path.exists(dirpath):
@@ -895,7 +895,6 @@ def create_dirs(dirpath):
return dirpath
@synchronized(DIR_LOCK)
def move_to_path(path, new_path):
""" Move a file to a new path, optionally give unique filename
Return (ok, new_path)
@@ -912,8 +911,7 @@ def move_to_path(path, new_path):
new_path = get_unique_filename(new_path)
if new_path:
logging.debug("Moving. Old path: %s New path: %s Overwrite: %s",
path, new_path, overwrite)
logging.debug("Moving (overwrite: %s) %s => %s", overwrite, path, new_path)
try:
# First try cheap rename
renamer(path, new_path)
@@ -937,7 +935,6 @@ def move_to_path(path, new_path):
return ok, new_path
@synchronized(DIR_LOCK)
def cleanup_empty_directories(path):
""" Remove all empty folders inside (and including) 'path' """
path = os.path.normpath(path)
@@ -958,18 +955,14 @@ def cleanup_empty_directories(path):
pass
@synchronized(DIR_LOCK)
def get_filepath(path, nzo, filename):
""" Create unique filepath """
# This procedure is only used by the Assembler thread
# It does no umask setting
# It uses the dir_lock for the (rare) case that the
# download_dir is equal to the complete_dir.
dirname = nzo.work_name
created = nzo.created
dName = dirname
if not created:
dName = nzo.work_name
if not nzo.created:
for n in xrange(200):
dName = dirname
if n:
@@ -1009,15 +1002,6 @@ def trim_win_path(path):
return path
def check_win_maxpath(folder):
""" Return False if any file path in folder exceeds the Windows maximum """
if sabnzbd.WIN32:
for p in os.listdir(folder):
if len(os.path.join(folder, p)) > 259:
return False
return True
def make_script_path(script):
""" Return full script path, if any valid script exists, else None """
s_path = None
@@ -1198,24 +1182,40 @@ else:
return 20.0, 10.0
__LAST_DISK_RESULT = {}
__LAST_DISK_CALL = {}
def diskspace(_dir, force=False):
# Store all results to speed things up
__DIRS_CHECKED = []
__DISKS_SAME = None
__LAST_DISK_RESULT = {'download_dir': [], 'complete_dir': []}
__LAST_DISK_CALL = 0
def diskspace(force=False):
""" Wrapper to cache results """
if _dir not in __LAST_DISK_RESULT:
__LAST_DISK_RESULT[_dir] = [0.0, 0.0]
__LAST_DISK_CALL[_dir] = 0.0
global __DIRS_CHECKED, __DISKS_SAME, __LAST_DISK_RESULT, __LAST_DISK_CALL
# Reset everything when folders changed
dirs_to_check = [cfg.download_dir.get_path(), cfg.complete_dir.get_path()]
if __DIRS_CHECKED != dirs_to_check:
__DIRS_CHECKED = dirs_to_check
__DISKS_SAME = None
__LAST_DISK_RESULT = {'download_dir': [], 'complete_dir': []}
__LAST_DISK_CALL = 0
# When forced, ignore any cache to avoid problems in UI
if force:
return diskspace_base(_dir)
__LAST_DISK_CALL = 0
# Check against cache
if time.time() > __LAST_DISK_CALL[_dir] + 10.0:
__LAST_DISK_RESULT[_dir] = diskspace_base(_dir)
__LAST_DISK_CALL[_dir] = time.time()
if time.time() > __LAST_DISK_CALL + 10.0:
# Same disk? Then copy-paste
__LAST_DISK_RESULT['download_dir'] = diskspace_base(cfg.download_dir.get_path())
__LAST_DISK_RESULT['complete_dir'] = __LAST_DISK_RESULT['download_dir'] if __DISKS_SAME else diskspace_base(cfg.complete_dir.get_path())
__LAST_DISK_CALL = time.time()
return __LAST_DISK_RESULT[_dir]
# Do we know if it's same disk?
if __DISKS_SAME is None:
__DISKS_SAME = (__LAST_DISK_RESULT['download_dir'] == __LAST_DISK_RESULT['complete_dir'])
return __LAST_DISK_RESULT
##############################################################################
@@ -1231,7 +1231,7 @@ def create_https_certificates(ssl_cert, ssl_key):
try:
from sabnzbd.utils.certgen import generate_key, generate_local_cert
private_key = generate_key(key_size=2048, output_file=ssl_key)
cert = generate_local_cert(private_key, days_valid=3560, output_file=ssl_cert, LN=u'SABnzbd', ON=u'SABnzbd', CN=u'localhost')
generate_local_cert(private_key, days_valid=3560, output_file=ssl_cert, LN=u'SABnzbd', ON=u'SABnzbd', CN=u'localhost')
logging.info('Self-signed certificates generated successfully')
except:
logging.error(T('Error creating SSL key and certificate'))
@@ -1380,6 +1380,7 @@ def renamer(old, new):
def remove_dir(path):
""" Remove directory with retries for Win32 """
logging.debug('Removing dir %s', path)
if sabnzbd.WIN32:
retries = 15
while retries > 0:
@@ -1408,6 +1409,7 @@ def remove_all(path, pattern='*', keep_folder=False, recursive=False):
for f in files:
if os.path.isfile(f):
try:
logging.debug('Removing file %s', f)
os.remove(f)
except:
logging.info('Cannot remove file %s', f)
@@ -1415,6 +1417,7 @@ def remove_all(path, pattern='*', keep_folder=False, recursive=False):
remove_all(f, pattern, False, True)
if not keep_folder:
try:
logging.debug('Removing dir %s', path)
os.rmdir(path)
except:
logging.info('Cannot remove folder %s', path)
@@ -1466,6 +1469,7 @@ def starts_with_path(path, prefix):
def set_chmod(path, permissions, report):
""" Set 'permissions' on 'path', report any errors when 'report' is True """
try:
logging.debug('Applying %s to %s', permissions, path)
os.chmod(path, permissions)
except:
lpath = path.lower()

View File

@@ -29,8 +29,7 @@ import binascii
import shutil
import sabnzbd
from sabnzbd.encoding import TRANS, UNTRANS, unicode2local, \
reliable_unpack_names, unicoder, platform_encode, deunicode
from sabnzbd.encoding import TRANS, UNTRANS, unicoder, platform_encode, deunicode
import sabnzbd.utils.rarfile as rarfile
from sabnzbd.misc import format_time_string, find_on_path, make_script_path, int_conv, \
flag_file, real_path, globber, globber_full, get_all_passwords, renamer, clip_path, \
@@ -38,7 +37,6 @@ from sabnzbd.misc import format_time_string, find_on_path, make_script_path, int
from sabnzbd.tvsort import SeriesSorter
import sabnzbd.cfg as cfg
from sabnzbd.constants import Status, QCHECK_FILE, RENAMES_FILE
load_data = save_data = None
if sabnzbd.WIN32:
try:
@@ -68,7 +66,6 @@ SPLITFILE_RE = re.compile(r'\.(\d\d\d$)', re.I)
ZIP_RE = re.compile(r'\.(zip$)', re.I)
SEVENZIP_RE = re.compile(r'\.7z$', re.I)
SEVENMULTI_RE = re.compile(r'\.7z\.\d+$', re.I)
VOLPAR2_RE = re.compile(r'\.*vol[0-9]+\+[0-9]+\.par2', re.I)
FULLVOLPAR2_RE = re.compile(r'(.*[^.])(\.*vol[0-9]+\+[0-9]+\.par2)', re.I)
TS_RE = re.compile(r'\.(\d+)\.(ts$)', re.I)
@@ -87,8 +84,6 @@ RAR_VERSION = 0
def find_programs(curdir):
""" Find external programs """
global load_data, save_data
def check(path, program):
p = os.path.abspath(os.path.join(path, program))
if os.access(p, os.X_OK):
@@ -96,10 +91,6 @@ def find_programs(curdir):
else:
return None
# Another crazy Python import bug work-around
load_data = sabnzbd.load_data
save_data = sabnzbd.save_data
if sabnzbd.DARWIN:
sabnzbd.newsunpack.PAR2C_COMMAND = check(curdir, 'osx/par2/par2-classic')
sabnzbd.newsunpack.PAR2_COMMAND = check(curdir, 'osx/par2/par2-sl64')
@@ -499,7 +490,7 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, one_folder, rars):
success = False
fail = True
msg = sys.exc_info()[1]
nzo.set_fail = T('Unpacking failed, %s') % msg
nzo.fail_msg = T('Unpacking failed, %s') % msg
setname = nzo.final_name
nzo.set_unpack_info('Unpack', T('[%s] Error "%s" while unpacking RAR files') % (unicoder(setname), msg))
@@ -1105,59 +1096,60 @@ def par2_repair(parfile_nzf, nzo, workdir, setname, single):
return readd, result
try:
new_dir_content = os.listdir(workdir)
if cfg.enable_par_cleanup():
new_dir_content = os.listdir(workdir)
for path in new_dir_content:
if os.path.splitext(path)[1] == '.1' and path not in old_dir_content:
for path in new_dir_content:
if os.path.splitext(path)[1] == '.1' and path not in old_dir_content:
try:
path = os.path.join(workdir, path)
logging.info("Deleting %s", path)
os.remove(path)
except:
logging.warning(T('Deleting %s failed!'), path)
path = os.path.join(workdir, setname + '.par2')
path2 = os.path.join(workdir, setname + '.PAR2')
if os.path.exists(path):
try:
path = os.path.join(workdir, path)
logging.info("Deleting %s", path)
os.remove(path)
except:
logging.warning(T('Deleting %s failed!'), path)
path = os.path.join(workdir, setname + '.par2')
path2 = os.path.join(workdir, setname + '.PAR2')
if os.path.exists(path):
try:
logging.info("Deleting %s", path)
os.remove(path)
except:
logging.warning(T('Deleting %s failed!'), path)
if os.path.exists(path2):
try:
logging.info("Deleting %s", path2)
os.remove(path2)
except:
logging.warning(T('Deleting %s failed!'), path2)
if os.path.exists(parfile):
try:
logging.info("Deleting %s", parfile)
os.remove(parfile)
except OSError:
logging.warning(T('Deleting %s failed!'), parfile)
deletables = []
deletables.extend(used_joinables)
deletables.extend(used_for_repair)
# Delete pars of the set and maybe extra ones that par2 found
deletables.extend([os.path.join(workdir, f) for f in setpars])
deletables.extend([os.path.join(workdir, f) for f in pars])
for filepath in deletables:
if filepath in joinables:
joinables.remove(filepath)
if os.path.exists(filepath):
logging.info("Deleting %s", filepath)
if os.path.exists(path2):
try:
os.remove(filepath)
logging.info("Deleting %s", path2)
os.remove(path2)
except:
logging.warning(T('Deleting %s failed!'), path2)
if os.path.exists(parfile):
try:
logging.info("Deleting %s", parfile)
os.remove(parfile)
except OSError:
logging.warning(T('Deleting %s failed!'), filepath)
logging.warning(T('Deleting %s failed!'), parfile)
deletables = []
deletables.extend(used_joinables)
deletables.extend([os.path.join(workdir, f) for f in used_for_repair])
# Delete pars of the set and maybe extra ones that par2 found
deletables.extend([os.path.join(workdir, f) for f in setpars])
deletables.extend([os.path.join(workdir, f) for f in pars])
for filepath in deletables:
if filepath in joinables:
joinables.remove(filepath)
if os.path.exists(filepath):
logging.info("Deleting %s", filepath)
try:
os.remove(filepath)
except OSError:
logging.warning(T('Deleting %s failed!'), filepath)
except:
msg = sys.exc_info()[1]
nzo.fail_msg = T('Repairing failed, %s') % msg
@@ -1306,12 +1298,12 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False, sin
if extra_par2_name and line.startswith('Loaded '):
m = _RE_LOADED_PAR2.search(line)
if m and int(m.group(1)) > 0:
used_for_repair.append(os.path.join(nzo.downpath, extra_par2_name))
used_for_repair.append(extra_par2_name)
extra_par2_name = None
continue
extra_par2_name = None
if line.startswith('Invalid option specified') or line.startswith('Cannot specify recovery file count'):
if line.startswith(('Invalid option specified', 'Invalid thread option', 'Cannot specify recovery file count')):
msg = T('[%s] PAR2 received incorrect options, check your Config->Switches settings') % unicoder(setname)
nzo.set_unpack_info('Repair', msg)
nzo.status = Status.FAILED
@@ -1341,9 +1333,7 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False, sin
elif line.startswith('Main packet not found') or 'The recovery file does not exist' in line:
# Initialparfile probably didn't decode properly,
logging.info(T('Main packet not found...'))
extrapars = parfile_nzf.extrapars
logging.info("Extra pars = %s", extrapars)
# Look for the smallest par2file
@@ -1354,7 +1344,6 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False, sin
if block_table:
nzf = block_table[min(block_table.keys())]
logging.info("Found new par2file %s", nzf.filename)
# Move from extrapar list to files to be downloaded
@@ -1591,10 +1580,10 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False, sin
# If successful, add renamed files to the collection
if finished and renames:
previous = load_data(RENAMES_FILE, nzo.workpath, remove=False)
previous = sabnzbd.load_data(RENAMES_FILE, nzo.workpath, remove=False)
for name in previous or {}:
renames[name] = previous[name]
save_data(renames, RENAMES_FILE, nzo.workpath)
sabnzbd.save_data(renames, RENAMES_FILE, nzo.workpath)
# If successful and files were reconstructed, remove incomplete original files
if finished and reconstructed:
@@ -1611,6 +1600,7 @@ _RE_FILENAME = re.compile(r'"([^"]+)"')
def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False, single=False):
""" Run par2 on par-set """
parfolder = os.path.split(parfile)[0]
used_joinables = []
used_for_repair = []
@@ -1618,10 +1608,9 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
nzo.status = Status.VERIFYING
start = time()
# Can implement caching of verification by adding:
# '-vs2', '-vd%s' % parfolder
# Caching of verification implemented by adding:
# But not really required due to prospective-par2
command = [str(MULTIPAR_COMMAND), 'r', parfile]
command = [str(MULTIPAR_COMMAND), 'r', '-vs2', '-vd%s' % parfolder, parfile]
# Only add user-options if supplied
options = cfg.par_option().strip()
@@ -1629,7 +1618,6 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
command.insert(2, options)
# Append the wildcard for this set
parfolder = os.path.split(parfile)[0]
if single or len(globber(parfolder, setname + '*')) < 2:
# Support bizarre naming conventions
wildcard = '*'
@@ -1669,6 +1657,7 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
in_check = False
in_verify = False
in_repair = False
in_verify_repaired = False
misnamed_files = False
old_name = None
@@ -1698,8 +1687,6 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
# Skip empty lines
if line == '':
# Empty lines also end every section
in_repair = False
continue
# Save it all
@@ -1731,7 +1718,6 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
# Move from extrapar list to files to be downloaded
nzo.add_parfile(nzf)
extrapars.remove(nzf)
# Now set new par2 file as primary par2
nzo.partable[setname] = nzf
nzf.extrapars = extrapars
@@ -1752,7 +1738,7 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
nzo.set_unpack_info('Repair', msg)
nzo.status = Status.FAILED
# ----------------- Verify stage
# ----------------- Start check/verify stage
# List of Par2 files we will use today
if line.startswith('PAR File list'):
in_parlist = True
@@ -1762,9 +1748,20 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
elif in_parlist:
m = _RE_FILENAME.search(line)
if m:
used_for_repair.append(os.path.join(nzo.downpath, TRANS(m.group(1))))
used_for_repair.append(TRANS(m.group(1)))
pars.append(TRANS(m.group(1)))
elif line.startswith('Recovery Set ID'):
# Remove files were MultiPar stores verification result when repaired succesfull
recovery_id = line.split()[-1]
used_for_repair.append('2_%s.bin' % recovery_id)
used_for_repair.append('2_%s.ini' % recovery_id)
elif line.startswith('Input File total count'):
# How many files will it try to find?
verifytotal = int(line.split()[-1])
# ----------------- Misnamed-detection stage
# Misnamed files
elif line.startswith('Searching misnamed file'):
# We are in the misnamed files block
@@ -1788,22 +1785,31 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
datafiles.append(new_name)
reconstructed.append(old_name)
# How many files will it try to find?
elif line.startswith('Input File total count'):
verifytotal = int(line.split()[-1])
# ----------------- Checking stage
# Checking input files
elif line.startswith('Complete file count'):
in_check = False
verifynum = 0
old_name = None
elif line.startswith('Verifying Input File'):
in_check = True
nzo.status = Status.VERIFYING
elif in_check:
m = _RE_FILENAME.search(line)
if m:
verifynum += 1
# Only increase counter if it was really the detection line
if line.startswith('= ') or '%' not in line:
verifynum += 1
nzo.set_action_line(T('Checking'), '%02d/%02d' % (verifynum, verifytotal))
old_name = TRANS(m.group(1))
# ----------------- Verify stage
# Which files need extra verification?
elif line.startswith('Damaged file count'):
verifytotal = int(line.split()[-1])
elif line.startswith('Missing file count'):
verifytotal += int(line.split()[-1])
# Actual verification
elif line.startswith('Input File Slice found'):
@@ -1845,7 +1851,7 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
datafiles.pop()
datafiles.append(new_name)
# Need to remove the old file after repair (Multipar keeps it)
used_for_repair.append(os.path.join(parfolder, old_name))
used_for_repair.append(old_name)
# Need to reset it to avoid collision
old_name = None
@@ -1929,7 +1935,8 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
logging.info('Verified in %s, all files correct',
format_time_string(time() - start))
finished = 1
elif line.startswith('Ready to repair') or line.startswith('Ready to rejoin'):
elif line.startswith(('Ready to repair', 'Ready to rejoin')):
# Ready to repair!
# Or we are re-joining a split file when there's no damage but takes time
msg = T('[%s] Verified in %s, repair is required') % (unicoder(setname), format_time_string(time() - start))
@@ -1948,6 +1955,14 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
start = time()
in_repair = True
nzo.set_action_line(T('Repairing'), '%2d%%' % (0))
elif in_repair and line.startswith('Verifying repair'):
in_repair = False
in_verify_repaired = True
# How many will be checked?
verifytotal = int(line.split()[-1])
verifynum = 0
elif in_repair:
# Line with percentage of repair (nothing else)
per = float(line[:-1])
@@ -1960,6 +1975,12 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
logging.info('Repaired in %s', format_time_string(time() - start))
finished = 1
elif in_verify_repaired and line.startswith('Repaired :'):
# Track verification of repaired files (can sometimes take a while)
verifynum += 1
nzo.set_action_line(T('Verifying repair'), '%02d/%02d' % (verifynum, verifytotal))
p.wait()
logging.debug('MultiPar output was\n%s', '\n'.join(lines))
@@ -1970,10 +1991,10 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, classic=False
# But the ones in 'Finding available slices'-section will only be renamed after succesfull repair
if renames:
# Adding to the collection
previous = load_data(RENAMES_FILE, nzo.workpath, remove=False)
previous = sabnzbd.load_data(RENAMES_FILE, nzo.workpath, remove=False)
for name in previous or {}:
renames[name] = previous[name]
save_data(renames, RENAMES_FILE, nzo.workpath)
sabnzbd.save_data(renames, RENAMES_FILE, nzo.workpath)
# If succes, we also remove the possibly previously renamed ones
if finished and previous:
@@ -2110,20 +2131,6 @@ def rar_sort(a, b):
return cmp(a, b)
# Sort the various PAR filename formats properly :\
def par_sort(a, b):
""" Define sort method for par2 file names """
aext = a.lower().split('.')[-1]
bext = b.lower().split('.')[-1]
if aext == bext:
return cmp(a, b)
elif aext == 'par2':
return -1
elif bext == 'par2':
return 1
def build_filelists(workdir, workdir_complete=None, check_rar=True):
""" Build filelists, if workdir_complete has files, ignore workdir.
Optionally test content to establish RAR-ness
@@ -2248,10 +2255,10 @@ def QuickCheck(set, nzo):
# Save renames
if renames:
previous = load_data(RENAMES_FILE, nzo.workpath, remove=False)
previous = sabnzbd.load_data(RENAMES_FILE, nzo.workpath, remove=False)
for name in previous or {}:
renames[name] = previous[name]
save_data(renames, RENAMES_FILE, nzo.workpath)
sabnzbd.save_data(renames, RENAMES_FILE, nzo.workpath)
return result
@@ -2265,14 +2272,6 @@ def pars_of_set(wdir, setname):
return list
def add_s(i):
""" Return an "s" when 'i' > 1 """
if i > 1:
return 's'
else:
return ''
def unrar_check(rar):
""" Return version number of unrar, where "5.01" returns 501
Also return whether an original version is found

View File

@@ -26,7 +26,6 @@ from nntplib import NNTPPermanentError
import time
import logging
import re
import select
import ssl
import sabnzbd
@@ -114,7 +113,6 @@ def get_ssl_version(sock):
def con(sock, host, port, sslenabled, write_fds, nntp):
if 0: assert isinstance(nntp, NNTP) # Assert only for debug purposes
try:
sock.connect((host, port))
sock.setblocking(0)
@@ -164,9 +162,10 @@ def probablyipv6(ip):
class NNTP(object):
# Pre-define attributes to save memory
__slots__ = ('host', 'port', 'nw', 'blocking', 'error_msg', 'sock')
def __init__(self, host, port, info, sslenabled, send_group, nw, user=None, password=None, block=False, write_fds=None):
if 0: assert isinstance(nw, NewsWrapper) # Assert only for debug purposes
self.host = host
self.port = port
self.nw = nw
@@ -248,16 +247,31 @@ class NNTP(object):
self.error(e)
def error(self, error):
if 'SSL23_GET_SERVER_HELLO' in str(error) or 'SSL3_GET_RECORD' in str(error):
raw_error_str = str(error)
if 'SSL23_GET_SERVER_HELLO' in str(error) or 'SSL3_GET_RECORD' in raw_error_str:
error = T('This server does not allow SSL on this port')
# Catch certificate errors
if type(error) == CertificateError or 'CERTIFICATE_VERIFY_FAILED' in str(error):
error = T('Server %s uses an untrusted certificate [%s]') % (self.nw.server.host, str(error))
error += ' - https://sabnzbd.org/certificate-errors'
if type(error) == CertificateError or 'CERTIFICATE_VERIFY_FAILED' in raw_error_str:
# Log the raw message for debug purposes
logging.info('Certificate error for host %s: %s', self.nw.server.host, raw_error_str)
# Try to see if we should catch this message and provide better text
if 'hostname' in raw_error_str:
raw_error_str = T('Certificate hostname mismatch: the server hostname is not listed in the certificate. This is a server issue.')
elif 'certificate verify failed' in raw_error_str:
raw_error_str = T('Certificate not valid. This is most probably a server issue.')
# Reformat error
error = T('Server %s uses an untrusted certificate [%s]') % (self.nw.server.host, raw_error_str)
error = '%s - %s: %s' % (error, T('Wiki'), 'https://sabnzbd.org/certificate-errors')
# Prevent throwing a lot of errors or when testing server
if error not in self.nw.server.warning and self.nw.server.id != -1:
if error not in self.nw.server.warning and not self.blocking:
logging.error(error)
# Pass to server-test
if self.blocking:
raise CertificateError(error)
# Blocking = server-test, pass directly to display code
if self.blocking:
@@ -271,6 +285,9 @@ class NNTP(object):
class NewsWrapper(object):
# Pre-define attributes to save memory
__slots__ = ('server', 'thrdnum', 'blocking', 'timeout', 'article', 'data', 'lines', 'last_line', 'nntp',
'recv', 'connected', 'user_sent', 'pass_sent', 'group', 'user_ok', 'pass_ok', 'force_login')
def __init__(self, server, thrdnum, block=False):
self.server = server

View File

@@ -251,7 +251,6 @@ def send_growl(title, msg, gtype, test=None):
if not _GROWL:
_GROWL, error = register_growl(growl_server, growl_password)
if _GROWL:
if 0: assert isinstance(_GROWL, GrowlNotifier) # Assert only for debug purposes
_GROWL_REG = True
if isinstance(msg, unicode):
msg = msg.decode('utf-8')

View File

@@ -25,18 +25,16 @@ import time
import datetime
import sabnzbd
from sabnzbd.trylist import TryList
from sabnzbd.nzbstuff import NzbObject
from sabnzbd.misc import exit_sab, cat_to_opts, \
get_admin_path, remove_all, globber_full
from sabnzbd.panic import panic_queue
import sabnzbd.database as database
from sabnzbd.decorators import NZBQUEUE_LOCK, synchronized, synchronized_CV
from sabnzbd.constants import QUEUE_FILE_NAME, QUEUE_VERSION, FUTURE_Q_FOLDER, JOB_ADMIN, \
LOW_PRIORITY, NORMAL_PRIORITY, HIGH_PRIORITY, TOP_PRIORITY, \
from sabnzbd.decorators import notify_downloader
from sabnzbd.constants import QUEUE_FILE_NAME, QUEUE_VERSION, FUTURE_Q_FOLDER, \
JOB_ADMIN, LOW_PRIORITY, NORMAL_PRIORITY, HIGH_PRIORITY, TOP_PRIORITY, \
REPAIR_PRIORITY, STOP_PRIORITY, VERIFIED_FILE, \
Status, QUEUE_FILE_TMPL, \
IGNORED_FOLDERS, QNFO
Status, IGNORED_FOLDERS, QNFO
import sabnzbd.cfg as cfg
from sabnzbd.articlecache import ArticleCache
@@ -47,7 +45,7 @@ from sabnzbd.encoding import platform_encode
from sabnzbd.bpsmeter import BPSMeter
class NzbQueue:
class NzbQueue(object):
""" Singleton NzbQueue """
do = None
@@ -68,41 +66,21 @@ class NzbQueue:
if repair < 2:
# Read the queue from the saved files
data = sabnzbd.load_admin(QUEUE_FILE_NAME)
if not data:
try:
# Try previous queue file
queue_vers, nzo_ids, dummy = sabnzbd.load_admin(QUEUE_FILE_TMPL % '9')
except:
nzo_ids = []
if nzo_ids:
logging.warning(T('Old queue detected, use Status->Repair to convert the queue'))
nzo_ids = []
else:
try:
queue_vers, nzo_ids, dummy = data
if not queue_vers == QUEUE_VERSION:
nzo_ids = []
logging.error(T('Incompatible queuefile found, cannot proceed'))
if not repair:
panic_queue(os.path.join(cfg.admin_dir.get_path(), QUEUE_FILE_NAME))
exit_sab(2)
except ValueError:
nzo_ids = []
logging.error(T('Error loading %s, corrupt file detected'),
os.path.join(cfg.admin_dir.get_path(), QUEUE_FILE_NAME))
if not repair:
return
# Process the data and check compatibility
nzo_ids = self.check_compatibility(data)
# First handle jobs in the queue file
folders = []
for nzo_id in nzo_ids:
folder, _id = os.path.split(nzo_id)
path = get_admin_path(folder, future=False)
# Try as normal job
path = get_admin_path(folder, False)
nzo = sabnzbd.load_data(_id, path, remove=False)
if not nzo:
# Try as future job
path = get_admin_path(folder, True)
path = get_admin_path(folder, future=True)
nzo = sabnzbd.load_data(_id, path)
if nzo:
self.add(nzo, save=False, quiet=True)
@@ -125,13 +103,54 @@ class NzbQueue:
except:
pass
def check_compatibility(self, data):
""" Do compatibility checks on the loaded data """
nzo_ids = []
if not data:
# Warn about old queue
if sabnzbd.OLD_QUEUE and cfg.warned_old_queue() < QUEUE_VERSION:
logging.warning(T('Old queue detected, use Status->Repair to convert the queue'))
cfg.warned_old_queue.set(QUEUE_VERSION)
else:
# Try to process
try:
queue_vers, nzo_ids, dummy = data
if not queue_vers == QUEUE_VERSION:
nzo_ids = []
logging.error(T('Incompatible queuefile found, cannot proceed'))
if not repair:
panic_queue(os.path.join(cfg.admin_dir.get_path(), QUEUE_FILE_NAME))
exit_sab(2)
except ValueError:
nzo_ids = []
logging.error(T('Error loading %s, corrupt file detected'),
os.path.join(cfg.admin_dir.get_path(), QUEUE_FILE_NAME))
# We need to do a repair in case of old-style pickles
if not cfg.converted_nzo_pickles():
for nzo_id in nzo_ids:
folder, _id = os.path.split(nzo_id)
path = get_admin_path(folder, future=False)
# This will update them but preserve queue-order
if os.path.exists(os.path.join(path, _id)):
self.repair_job(os.path.dirname(path))
continue
# Remove any future-jobs, we can't save those
for item in globber_full(os.path.join(cfg.admin_dir.get_path(), FUTURE_Q_FOLDER)):
os.remove(item)
# Done converting
cfg.converted_nzo_pickles.set(True)
nzo_ids = []
return nzo_ids
def scan_jobs(self, all=False, action=True):
""" Scan "incomplete" for missing folders,
'all' is True: Include active folders
'action' is True, do the recovery action
returns list of orphaned folders
"""
from sabnzbd.api import build_history
result = []
# Folders from the download queue
if all:
@@ -140,7 +159,7 @@ class NzbQueue:
registered = [nzo.work_name for nzo in self.__nzo_list]
# Retryable folders from History
items = build_history(output=True)[0]
items = sabnzbd.api.build_history(output=True)[0]
# Anything waiting or active or retryable is a known item
registered.extend([platform_encode(os.path.basename(item['path']))
for item in items if item['retry'] or item['loaded'] or item['status'] == Status.QUEUED])
@@ -160,11 +179,10 @@ class NzbQueue:
def retry_all_jobs(self, history_db):
""" Retry all retryable jobs in History """
from sabnzbd.api import build_history
result = []
# Retryable folders from History
items = build_history()[0]
items = sabnzbd.api.build_history()[0]
registered = [(platform_encode(os.path.basename(item['path'])),
item['nzo_id'])
for item in items if item['retry']]
@@ -210,6 +228,7 @@ class NzbQueue:
return nzo_id
@notify_downloader
def send_back(self, nzo):
""" Send back job to queue after successful pre-check """
try:
@@ -224,7 +243,6 @@ class NzbQueue:
# Reset reuse flag to make pause/abort on encryption possible
nzo.reuse = False
@synchronized(NZBQUEUE_LOCK)
def replace_in_q(self, nzo, nzo_id):
""" Replace nzo by new in at the same spot in the queue, destroy nzo """
# Must be a separate function from "send_back()", due to the required queue-lock
@@ -241,6 +259,7 @@ class NzbQueue:
del self.__nzo_table[nzo_id]
# And attach the new nzo to the old nzo_id
self.__nzo_table[old_id] = new_nzo
logging.info('Replacing in queue %s by %s', nzo.final_name, new_nzo.final_name)
del nzo
return new_nzo
except:
@@ -248,7 +267,6 @@ class NzbQueue:
logging.info("Traceback: ", exc_info=True)
return nzo
@synchronized(NZBQUEUE_LOCK)
def save(self, save_nzo=None):
""" Save queue, all nzo's or just the specified one """
logging.info("Saving queue")
@@ -267,67 +285,16 @@ class NzbQueue:
sabnzbd.save_admin((QUEUE_VERSION, nzo_ids, []), QUEUE_FILE_NAME)
@synchronized(NZBQUEUE_LOCK)
def set_top_only(self, value):
self.__top_only = value
@synchronized(NZBQUEUE_LOCK)
def generate_future(self, msg, pp=None, script=None, cat=None, url=None, priority=NORMAL_PRIORITY, nzbname=None):
""" Create and return a placeholder nzo object """
logging.debug('Creating placeholder NZO')
future_nzo = NzbObject(msg, pp, script, None, True, cat=cat, url=url, priority=priority, nzbname=nzbname, status=Status.GRABBING)
self.add(future_nzo)
return future_nzo
@synchronized(NZBQUEUE_LOCK)
def insert_future(self, future, filename, data, pp=None, script=None, cat=None, priority=NORMAL_PRIORITY, nzbname=None, nzo_info=None):
""" Refresh a placeholder nzo with an actual nzo """
if 0: assert isinstance(future, NzbObject) # Assert only for debug purposes
if nzo_info is None:
nzo_info = {}
nzo_id = future.nzo_id
if nzo_id in self.__nzo_table:
try:
sabnzbd.remove_data(nzo_id, future.workpath)
logging.info("Regenerating item: %s", nzo_id)
r, u, d = future.repair_opts
if r is not None:
pp = sabnzbd.opts_to_pp(r, u, d)
scr = future.script
if scr is None:
scr = script
categ = future.cat
if categ is None:
categ = cat
categ, pp, script, priority = cat_to_opts(categ, pp, script, priority)
# Remember old priority
old_prio = future.priority
try:
future.__init__(filename, pp, scr, nzb=data, futuretype=False, cat=categ, priority=priority, nzbname=nzbname, nzo_info=nzo_info)
future.nzo_id = nzo_id
self.save(future)
except ValueError:
self.remove(nzo_id, False)
except TypeError:
self.remove(nzo_id, False)
# Make sure the priority is changed now that we know the category
if old_prio != priority:
future.priority = None
self.set_priority(future.nzo_id, priority)
if cfg.auto_sort():
self.sort_by_avg_age()
except:
logging.error(T('Error while adding %s, removing'), nzo_id)
logging.info("Traceback: ", exc_info=True)
self.remove(nzo_id, False)
else:
logging.info("Item %s no longer in queue, omitting",
nzo_id)
@synchronized(NZBQUEUE_LOCK)
def change_opts(self, nzo_ids, pp):
result = 0
for nzo_id in [item.strip() for item in nzo_ids.split(',')]:
@@ -336,32 +303,32 @@ class NzbQueue:
result += 1
return result
@synchronized(NZBQUEUE_LOCK)
def change_script(self, nzo_ids, script):
result = 0
for nzo_id in [item.strip() for item in nzo_ids.split(',')]:
if nzo_id in self.__nzo_table:
self.__nzo_table[nzo_id].script = script
logging.info('Set script=%s for job %s', script, self.__nzo_table[nzo_id].final_name)
result += 1
return result
@synchronized(NZBQUEUE_LOCK)
def change_cat(self, nzo_ids, cat, explicit_priority=None):
result = 0
for nzo_id in [item.strip() for item in nzo_ids.split(',')]:
if nzo_id in self.__nzo_table:
nzo = self.__nzo_table[nzo_id]
nzo.cat, pp, nzo.script, prio = cat_to_opts(cat)
logging.info('Set cat=%s for job %s', cat, nzo.final_name)
nzo.set_pp(pp)
if explicit_priority is None:
self.set_priority(nzo_id, prio)
result += 1
return result
@synchronized(NZBQUEUE_LOCK)
def change_name(self, nzo_id, name, password=None):
if nzo_id in self.__nzo_table:
nzo = self.__nzo_table[nzo_id]
logging.info('Renaming %s to %s', nzo.final_name, name)
if not nzo.futuretype:
nzo.set_final_name_pw(name, password)
else:
@@ -371,16 +338,14 @@ class NzbQueue:
else:
return False
@synchronized(NZBQUEUE_LOCK)
def get_nzo(self, nzo_id):
if nzo_id in self.__nzo_table:
return self.__nzo_table[nzo_id]
else:
return None
@synchronized(NZBQUEUE_LOCK)
@notify_downloader
def add(self, nzo, save=True, quiet=False):
if 0: assert isinstance(nzo, NzbObject) # Assert only for debug purposes
if not nzo.nzo_id:
nzo.nzo_id = sabnzbd.get_new_id('nzo', nzo.workpath, self.__nzo_table)
@@ -435,7 +400,6 @@ class NzbQueue:
self.sort_by_avg_age()
return nzo.nzo_id
@synchronized(NZBQUEUE_LOCK)
def remove(self, nzo_id, add_to_history=True, save=True, cleanup=True, keep_basic=False, del_files=False):
if nzo_id in self.__nzo_table:
nzo = self.__nzo_table.pop(nzo_id)
@@ -451,23 +415,19 @@ class NzbQueue:
# Other information is obtained from the nzo
history_db.add_history_db(nzo, '', '', 0, '', '')
history_db.close()
sabnzbd.history_updated()
elif cleanup:
self.cleanup_nzo(nzo, keep_basic, del_files)
sabnzbd.remove_data(nzo_id, nzo.workpath)
logging.info('Removed job %s', nzo.final_name)
if save:
self.save(nzo)
else:
nzo_id = None
# Update the last check time, since history was updated
sabnzbd.LAST_HISTORY_UPDATE = time.time()
return nzo_id
@synchronized(NZBQUEUE_LOCK)
def remove_multiple(self, nzo_ids, del_files=False):
removed = []
for nzo_id in nzo_ids:
@@ -477,7 +437,6 @@ class NzbQueue:
self.save('x')
return removed
@synchronized(NZBQUEUE_LOCK)
def remove_all(self, search=None):
if search:
search = search.lower()
@@ -493,7 +452,6 @@ class NzbQueue:
self.save()
return removed
@synchronized(NZBQUEUE_LOCK)
def remove_nzf(self, nzo_id, nzf_id, force_delete=False):
removed = []
if nzo_id in self.__nzo_table:
@@ -514,10 +472,9 @@ class NzbQueue:
nzo.bytes_tried -= (nzf.bytes - nzf.bytes_left)
del nzo.files_table[nzf_id]
nzo.finished_files.remove(nzf)
logging.info('Removed NZFs %s from job %s', removed, nzo.final_name)
return removed
@synchronized(NZBQUEUE_LOCK)
def pause_multiple_nzo(self, nzo_ids):
handled = []
for nzo_id in nzo_ids:
@@ -525,17 +482,15 @@ class NzbQueue:
handled.append(nzo_id)
return handled
@synchronized(NZBQUEUE_LOCK)
def pause_nzo(self, nzo_id):
handled = []
if nzo_id in self.__nzo_table:
nzo = self.__nzo_table[nzo_id]
nzo.pause()
logging.debug("Paused nzo: %s", nzo_id)
logging.info("Paused nzo: %s", nzo_id)
handled.append(nzo_id)
return handled
@synchronized(NZBQUEUE_LOCK)
def resume_multiple_nzo(self, nzo_ids):
handled = []
for nzo_id in nzo_ids:
@@ -543,19 +498,17 @@ class NzbQueue:
handled.append(nzo_id)
return handled
@synchronized_CV
@synchronized(NZBQUEUE_LOCK)
@notify_downloader
def resume_nzo(self, nzo_id):
handled = []
if nzo_id in self.__nzo_table:
nzo = self.__nzo_table[nzo_id]
nzo.resume()
nzo.reset_all_try_lists()
logging.debug("Resumed nzo: %s", nzo_id)
logging.info("Resumed nzo: %s", nzo_id)
handled.append(nzo_id)
return handled
@synchronized(NZBQUEUE_LOCK)
def switch(self, item_id_1, item_id_2):
try:
# Allow an index as second parameter, easier for some skins
@@ -597,57 +550,43 @@ class NzbQueue:
item_id_pos2 = i
if (item_id_pos1 > -1) and (item_id_pos2 > -1):
item = self.__nzo_list[item_id_pos1]
logging.info('Switching job [%s] %s => [%s] %s', item_id_pos1, item.final_name, item_id_pos2, self.__nzo_list[item_id_pos2].final_name)
del self.__nzo_list[item_id_pos1]
self.__nzo_list.insert(item_id_pos2, item)
return (item_id_pos2, nzo1.priority)
# If moving failed/no movement took place
return (-1, nzo1.priority)
@synchronized(NZBQUEUE_LOCK)
def get_position(self, nzb_id):
for i in xrange(len(self.__nzo_list)):
if nzb_id == self.__nzo_list[i].nzo_id:
return i
return -1
@synchronized(NZBQUEUE_LOCK)
def move_up_bulk(self, nzo_id, nzf_ids, size):
if nzo_id in self.__nzo_table:
for unused in range(size):
self.__nzo_table[nzo_id].move_up_bulk(nzf_ids)
@synchronized(NZBQUEUE_LOCK)
def move_top_bulk(self, nzo_id, nzf_ids):
if nzo_id in self.__nzo_table:
self.__nzo_table[nzo_id].move_top_bulk(nzf_ids)
@synchronized(NZBQUEUE_LOCK)
def move_down_bulk(self, nzo_id, nzf_ids, size):
if nzo_id in self.__nzo_table:
for unused in range(size):
self.__nzo_table[nzo_id].move_down_bulk(nzf_ids)
@synchronized(NZBQUEUE_LOCK)
def move_bottom_bulk(self, nzo_id, nzf_ids):
if nzo_id in self.__nzo_table:
self.__nzo_table[nzo_id].move_bottom_bulk(nzf_ids)
@synchronized(NZBQUEUE_LOCK)
def sort_by_avg_age(self, reverse=False):
logging.info("Sorting by average date...(reversed:%s)", reverse)
logging.info("Sorting by average date... (reversed:%s)", reverse)
self.__nzo_list = sort_queue_function(self.__nzo_list, _nzo_date_cmp, reverse)
@synchronized(NZBQUEUE_LOCK)
def sort_by_name(self, reverse=False):
logging.info("Sorting by name...(reversed:%s)", reverse)
logging.info("Sorting by name... (reversed:%s)", reverse)
self.__nzo_list = sort_queue_function(self.__nzo_list, _nzo_name_cmp, reverse)
@synchronized(NZBQUEUE_LOCK)
def sort_by_size(self, reverse=False):
logging.info("Sorting by size...(reversed:%s)", reverse)
logging.info("Sorting by size... (reversed:%s)", reverse)
self.__nzo_list = sort_queue_function(self.__nzo_list, _nzo_size_cmp, reverse)
@synchronized(NZBQUEUE_LOCK)
def sort_queue(self, field, reverse=None):
if isinstance(reverse, basestring):
if reverse.lower() == 'desc':
@@ -730,12 +669,14 @@ class NzbQueue:
# if the queue is empty then simple append the item to the bottom
self.__nzo_list.append(nzo)
pos = 0
logging.info('Set priority=%s for job %s => position=%s ', priority, self.__nzo_table[nzo_id].final_name, pos)
return pos
except:
return -1
@synchronized(NZBQUEUE_LOCK)
@notify_downloader
def set_priority(self, nzo_ids, priority):
try:
n = -1
@@ -745,35 +686,16 @@ class NzbQueue:
except:
return -1
@synchronized(NZBQUEUE_LOCK)
def reset_try_lists(self, nzf=None, nzo=None):
if nzf:
nzf.reset_try_list()
if nzo:
nzo.reset_try_list()
@synchronized(NZBQUEUE_LOCK)
def reset_all_try_lists(self):
for nzo in self.__nzo_list:
nzo.reset_all_try_lists()
@synchronized(NZBQUEUE_LOCK)
def has_articles_for(self, server):
""" Check whether there are any pending articles for the downloader """
if not self.__nzo_list:
return False
# Check if this server is allowed for any object, then return if we've tried this server.
for nzo in self.__nzo_list:
# 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:
# Check if past propagation delay, or forced
if not cfg.propagation_delay() or nzo.priority == TOP_PRIORITY or (nzo.avg_stamp + float(cfg.propagation_delay() * 60)) < time.time():
# Check if category allowed
if nzo.server_allowed(server) or self.__top_only:
return True
return False
@synchronized(NZBQUEUE_LOCK)
def has_forced_items(self):
""" Check if the queue contains any Forced
Priority items to download while paused
@@ -783,7 +705,6 @@ class NzbQueue:
return True
return False
@synchronized(NZBQUEUE_LOCK)
def get_article(self, server, servers):
for nzo in self.__nzo_list:
# Not when queue paused and not a forced item
@@ -800,7 +721,6 @@ class NzbQueue:
if self.__top_only:
return
@synchronized(NZBQUEUE_LOCK)
def register_article(self, article, found=True):
nzf = article.nzf
nzo = nzf.nzo
@@ -814,11 +734,11 @@ class NzbQueue:
filename = nzf.filename
if nzo.is_gone():
logging.debug('Discarding file completion %s for deleted job', filename)
logging.debug('Discarding article %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)
nzo.save_to_disk()
BPSMeter.do.save()
if nzo.save_timeout is None:
nzo.next_save = None
@@ -840,6 +760,7 @@ class NzbQueue:
def end_job(self, nzo):
""" Send NZO to the post-processing queue """
logging.info('Ending job %s', nzo.final_name)
if self.actives(grabs=False) < 2 and cfg.autodisconnect():
# This was the last job, close server connections
if sabnzbd.downloader.Downloader.do:
@@ -854,7 +775,6 @@ class NzbQueue:
enough, _ratio = nzo.check_quality()
if enough:
# Enough data present, do real download
_workdir = nzo.downpath
self.cleanup_nzo(nzo, keep_basic=True)
self.send_back(nzo)
return
@@ -863,7 +783,6 @@ class NzbQueue:
pass
Assembler.do.process((nzo, None))
@synchronized(NZBQUEUE_LOCK)
def actives(self, grabs=True):
""" Return amount of non-paused jobs, optionally with 'grabbing' items """
n = 0
@@ -875,7 +794,6 @@ class NzbQueue:
n += 1
return n
@synchronized(NZBQUEUE_LOCK)
def queue_info(self, search=None, start=0, limit=0):
""" Return list of queued jobs,
optionally filtered by 'search' and limited by start and limit.
@@ -908,7 +826,6 @@ class NzbQueue:
n = len(self.__nzo_list)
return QNFO(bytes_total, bytes_left, bytes_left_previous_page, pnfo_list, q_size, n)
@synchronized(NZBQUEUE_LOCK)
def remaining(self):
""" Return bytes left in the queue by non-paused items """
bytes_left = 0
@@ -917,7 +834,6 @@ class NzbQueue:
bytes_left += nzo.remaining()
return bytes_left
@synchronized(NZBQUEUE_LOCK)
def is_empty(self):
empty = True
for nzo in self.__nzo_list:
@@ -926,13 +842,10 @@ class NzbQueue:
break
return empty
@synchronized(NZBQUEUE_LOCK)
def cleanup_nzo(self, nzo, keep_basic=False, del_files=False):
nzo.purge_data(keep_basic, del_files)
ArticleCache.do.purge_articles(nzo.saved_articles)
@synchronized(NZBQUEUE_LOCK)
def stop_idle_jobs(self):
""" Detect jobs that have zero files left and send them to post processing """
empty = []
@@ -942,13 +855,12 @@ class NzbQueue:
for nzo in empty:
self.end_job(nzo)
@synchronized(NZBQUEUE_LOCK)
def pause_on_prio(self, priority):
for nzo in self.__nzo_list:
if not nzo.futuretype and nzo.priority == priority:
nzo.pause()
@synchronized(NZBQUEUE_LOCK)
@notify_downloader
def resume_on_prio(self, priority):
for nzo in self.__nzo_list:
if not nzo.futuretype and nzo.priority == priority:
@@ -1018,44 +930,3 @@ def sort_queue_function(nzo_list, method, reverse):
new_list.append(item)
return new_list
# Synchronized wrappers
@synchronized_CV
def add_nzo(nzo, quiet=False):
return NzbQueue.do.add(nzo, quiet=quiet)
@synchronized_CV
def insert_future_nzo(future_nzo, filename, data, pp=None, script=None, cat=None, priority=NORMAL_PRIORITY, nzbname=None, nzo_info=None):
if nzo_info is None:
nzo_info = {}
NzbQueue.do.insert_future(future_nzo, filename, data, pp=pp, script=script, cat=cat, priority=priority, nzbname=nzbname, nzo_info=nzo_info)
@synchronized_CV
def set_priority(nzo_ids, priority):
return NzbQueue.do.set_priority(nzo_ids, priority)
@synchronized_CV
def get_nzo(nzo_id):
return NzbQueue.do.get_nzo(nzo_id)
@synchronized_CV
def sort_queue(field, reverse=False):
NzbQueue.do.sort_queue(field, reverse)
@synchronized_CV
@synchronized(NZBQUEUE_LOCK)
def repair_job(folder, new_nzb, password):
return NzbQueue.do.repair_job(folder, new_nzb, password)
@synchronized_CV
@synchronized(NZBQUEUE_LOCK)
def scan_jobs(all=False, action=True):
return NzbQueue.do.scan_jobs(all, action)

View File

@@ -25,6 +25,7 @@ import time
import re
import logging
import datetime
import threading
import xml.sax
import xml.sax.handler
import xml.sax.xmlreader
@@ -43,12 +44,11 @@ from sabnzbd.constants import GIGI, ATTRIB_FILE, JOB_ADMIN, \
RENAMES_FILE, Status, PNFO
from sabnzbd.misc import to_units, cat_to_opts, cat_convert, sanitize_foldername, \
get_unique_path, get_admin_path, remove_all, sanitize_filename, globber_full, \
sanitize_foldername, int_conv, set_permissions, format_time_string, long_path, \
trim_win_path, fix_unix_encoding, calc_age
from sabnzbd.decorators import synchronized, IO_LOCK
int_conv, set_permissions, format_time_string, long_path, trim_win_path, \
fix_unix_encoding, calc_age
from sabnzbd.decorators import synchronized
import sabnzbd.config as config
import sabnzbd.cfg as cfg
from sabnzbd.trylist import TryList
from sabnzbd.encoding import unicoder, platform_encode
from sabnzbd.database import HistoryDB
from sabnzbd.rating import Rating
@@ -61,6 +61,36 @@ PROBABLY_PAR2_RE = re.compile(r'(.*)\.vol(\d*)[\+\-](\d*)\.par2', re.I)
REJECT_PAR2_RE = re.compile(r'\.par2\.\d+', re.I) # Reject duplicate par2 files
RE_NORMAL_NAME = re.compile(r'\.\w{2,5}$') # Test reasonably sized extension at the end
##############################################################################
# Trylist
##############################################################################
class TryList(object):
""" TryList keeps track of which servers have been tried for a specific article
This used to have a Lock, but it's not needed (all atomic) and faster without
"""
# Pre-define attributes to save memory
__slots__ = ('__try_list', 'fetcher_priority')
def __init__(self):
self.__try_list = []
self.fetcher_priority = 0
def server_in_try_list(self, server):
""" Return whether specified server has been tried """
return server in self.__try_list
def add_to_try_list(self, server):
""" Register server as having been tried already """
self.__try_list.append(server)
def reset_try_list(self):
""" Clean the list """
self.__try_list = []
self.fetcher_priority = 0
##############################################################################
# Article
##############################################################################
@@ -71,6 +101,8 @@ ArticleSaver = (
class Article(TryList):
""" Representation of one article """
# Pre-define attributes to save memory
__slots__ = ArticleSaver + ('fetcher', 'fetcher_priority', 'tries')
def __init__(self, article, bytes, partnum, nzf):
TryList.__init__(self)
@@ -152,17 +184,17 @@ class Article(TryList):
""" Save to pickle file, selecting attributes """
dict_ = {}
for item in ArticleSaver:
dict_[item] = self.__dict__[item]
dict_[item] = getattr(self, item)
return dict_
def __setstate__(self, dict_):
""" Load from pickle file, selecting attributes """
for item in ArticleSaver:
try:
self.__dict__[item] = dict_[item]
setattr(self, item, dict_[item])
except KeyError:
# Handle new attributes
self.__dict__[item] = None
setattr(self, item, None)
TryList.__init__(self)
self.fetcher = None
self.fetcher_priority = 0
@@ -178,14 +210,16 @@ class Article(TryList):
##############################################################################
NzbFileSaver = (
'date', 'subject', 'filename', 'type', 'is_par2', 'vol', 'blocks', 'setname',
'extrapars', 'initial_article', 'articles', 'decodetable', 'bytes', 'bytes_left',
'extrapars', 'articles', 'decodetable', 'bytes', 'bytes_left',
'article_count', 'nzo', 'nzf_id', 'deleted', 'valid', 'import_finished',
'md5sum', 'valid', 'completed'
'md5sum'
)
class NzbFile(TryList):
""" Representation of one file consisting of multiple articles """
# Pre-define attributes to save memory
__slots__ = NzbFileSaver
def __init__(self, date, subject, article_db, bytes, nzo):
""" Setup object """
@@ -193,9 +227,7 @@ class NzbFile(TryList):
self.date = date
self.subject = subject
self.filename = None
self.type = None
self.filename = name_extractor(subject)
self.is_par2 = False
@@ -204,8 +236,6 @@ class NzbFile(TryList):
self.setname = None
self.extrapars = None
self.initial_article = None
self.articles = []
self.decodetable = {}
@@ -216,8 +246,6 @@ class NzbFile(TryList):
self.nzo = nzo
self.nzf_id = sabnzbd.get_new_id("nzf", nzo.workpath)
self.deleted = False
self.completed = False
self.valid = False
self.import_finished = False
@@ -250,8 +278,10 @@ class NzbFile(TryList):
self.articles.remove(article)
if found:
self.bytes_left -= article.bytes
# To keep counter correct for pre-check
if self.nzo.precheck:
self.nzo.bytes_downloaded += article.bytes
self.nzo.bytes_tried += article.bytes
return (not self.articles)
def set_par2(self, setname, vol, blocks):
@@ -292,17 +322,17 @@ class NzbFile(TryList):
""" Save to pickle file, selecting attributes """
dict_ = {}
for item in NzbFileSaver:
dict_[item] = self.__dict__[item]
dict_[item] = getattr(self, item)
return dict_
def __setstate__(self, dict_):
""" Load from pickle file, selecting attributes """
for item in NzbFileSaver:
try:
self.__dict__[item] = dict_[item]
setattr(self, item, dict_[item])
except KeyError:
# Handle new attributes
self.__dict__[item] = None
setattr(self, item, None)
TryList.__init__(self)
def __repr__(self):
@@ -317,7 +347,6 @@ class NzbParser(xml.sax.handler.ContentHandler):
def __init__(self, nzo):
self.nzo = nzo
if 0: assert isinstance(self.nzo, NzbObject) # Assert only for debug purposes
self.in_nzb = False
self.in_file = False
self.in_groups = False
@@ -502,7 +531,7 @@ class NzbParser(xml.sax.handler.ContentHandler):
##############################################################################
NzbObjectSaver = (
'filename', 'work_name', 'final_name', 'created', 'bytes', 'bytes_downloaded', 'bytes_tried',
'repair', 'unpack', 'delete', 'script', 'cat', 'url', 'groups', 'avg_date', 'dirprefix',
'repair', 'unpack', 'delete', 'script', 'cat', 'url', 'groups', 'avg_date',
'partable', 'extrapars', 'md5packs', 'files', 'files_table', 'finished_files', 'status',
'avg_bps_freq', 'avg_bps_total', 'priority', 'dupe_table', 'saved_articles', 'nzo_id',
'futuretype', 'deleted', 'parsed', 'action_line', 'unpack_info', 'fail_msg', 'nzo_info',
@@ -511,6 +540,9 @@ NzbObjectSaver = (
'md5sum', 'servercount', 'unwanted_ext', 'rating_filtered'
)
# Lock to prevent errors when saving the NZO data
NZO_LOCK = threading.RLock()
class NzbObject(TryList):
@@ -569,7 +601,6 @@ class NzbObject(TryList):
self.groups = []
self.avg_date = datetime.datetime.fromtimestamp(0.0)
self.avg_stamp = 0.0 # Avg age in seconds (calculated from avg_age)
self.dirprefix = []
self.partable = {} # Holds one parfile-name for each set
self.extrapars = {} # Holds the extra parfile names for all sets
@@ -644,12 +675,12 @@ class NzbObject(TryList):
return
# Apply conversion option to final folder
if cfg.replace_dots() and ' ' not in self.final_name:
logging.info('Replacing dots with spaces in %s', self.final_name)
self.final_name = self.final_name.replace('.', ' ')
if cfg.replace_spaces():
logging.info('Replacing spaces with underscores in %s', self.final_name)
self.final_name = self.final_name.replace(' ', '_')
if cfg.replace_dots():
logging.info('Replacing dots with spaces in %s', self.final_name)
self.final_name = self.final_name.replace('.', ' ')
# Determine "incomplete" folder
wdir = long_path(os.path.join(cfg.download_dir.get_path(), self.work_name))
@@ -680,9 +711,6 @@ class NzbObject(TryList):
# by setting "feature_external_ges" to 0.
if nzb and '<nzb' in nzb:
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)
parser = xml.sax.make_parser()
parser.setFeature(xml.sax.handler.feature_external_ges, 0)
@@ -755,8 +783,8 @@ class NzbObject(TryList):
# Run user pre-queue script if needed
if not reuse:
accept, name, pp, cat, script, priority, group = \
sabnzbd.proxy_pre_queue(self.final_name_pw_clean, pp, cat, script,
priority, self.bytes, self.groups)
sabnzbd.newsunpack.pre_queue(self.final_name_pw_clean, pp, cat, script,
priority, self.bytes, self.groups)
accept = int_conv(accept)
try:
pp = int(pp)
@@ -867,7 +895,7 @@ class NzbObject(TryList):
if accept == 2:
self.deleted = True
self.status = Status.FAILED
nzo_id = sabnzbd.NzbQueue.do.add(self, quiet=True)
sabnzbd.NzbQueue.do.add(self, quiet=True)
sabnzbd.NzbQueue.do.end_job(self)
# Raise error, so it's not added
raise TypeError
@@ -887,7 +915,7 @@ class NzbObject(TryList):
return dupe
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def update_download_stats(self, bps, serverid, bytes):
if bps:
self.avg_bps_total += bps / 1024
@@ -898,7 +926,7 @@ class NzbObject(TryList):
self.servercount[serverid] = bytes
self.bytes_downloaded += bytes
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def remove_nzf(self, nzf):
if nzf in self.files:
self.files.remove(nzf)
@@ -908,13 +936,12 @@ class NzbObject(TryList):
nzf.deleted = True
return not bool(self.files)
@synchronized(IO_LOCK)
def reset_all_try_lists(self):
for nzf in self.files:
nzf.reset_all_try_lists()
self.reset_try_list()
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def postpone_pars(self, nzf, parset):
""" Move all vol-par files matching 'parset' to the extrapars table """
self.partable[parset] = nzf
@@ -929,10 +956,11 @@ class NzbObject(TryList):
if head and matcher(lparset, head.lower()):
xnzf.set_par2(parset, vol, block)
self.extrapars[parset].append(xnzf)
if not self.precheck:
# Don't postpone during pre-check or if all par2 should be kept
if not self.precheck and cfg.enable_par_cleanup():
self.files.remove(xnzf)
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def handle_par2(self, nzf, file_done):
""" Check if file is a par2 and build up par2 collection """
fn = nzf.filename
@@ -983,7 +1011,7 @@ class NzbObject(TryList):
else:
nzf.filename = nzf.subject
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def remove_article(self, article, found):
nzf = article.nzf
file_done = nzf.remove_article(article, found)
@@ -997,8 +1025,6 @@ class NzbObject(TryList):
self.fail_msg = T('Aborted, cannot be completed') + ' - https://sabnzbd.org/not-complete'
self.set_unpack_info('Download', self.fail_msg, unique=False)
logging.debug('Abort job "%s", due to impossibility to complete it', self.final_name_pw_clean)
# Update the last check time
sabnzbd.LAST_HISTORY_UPDATE = time.time()
return True, True
if file_done:
@@ -1018,7 +1044,7 @@ class NzbObject(TryList):
return (file_done, post_done)
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def remove_saved_article(self, article):
self.saved_articles.remove(article)
@@ -1051,7 +1077,6 @@ class NzbObject(TryList):
subject = sanitize_filename(name_extractor(nzf.subject))
if (nzf.filename == filename) or (subject == filename) or (filename in subject):
nzf.filename = filename
nzf.completed = True
nzf.bytes_left = 0
self.handle_par2(nzf, file_done=True)
self.remove_nzf(nzf)
@@ -1070,7 +1095,6 @@ class NzbObject(TryList):
self.files_table[nzf.nzf_id] = nzf
self.bytes += nzf.bytes
nzf.filename = filename
nzf.completed = True
nzf.bytes_left = 0
self.handle_par2(nzf, file_done=True)
self.remove_nzf(nzf)
@@ -1088,6 +1112,7 @@ class NzbObject(TryList):
def set_pp(self, value):
self.repair, self.unpack, self.delete = sabnzbd.pp_to_opts(value)
logging.info('Set pp=%s for job %s', value, self.final_name)
self.save_to_disk()
@property
@@ -1104,7 +1129,7 @@ class NzbObject(TryList):
if self.unwanted_ext and self.status == 'Paused':
prefix += T('UNWANTED') + ' / ' # : Queue indicator for unwanted extensions
if self.rating_filtered and self.status == 'Paused':
prefix += Ta('FILTERED') + ' / ' # : Queue indicator for filtered
prefix += T('FILTERED') + ' / ' # : Queue indicator for filtered
if isinstance(self.wait, float):
dif = int(self.wait - time.time() + 0.5)
if dif > 0:
@@ -1138,7 +1163,7 @@ class NzbObject(TryList):
self.status = Status.PAUSED
# Prevent loss of paused state when terminated
if self.nzo_id and not self.is_gone():
sabnzbd.save_data(self, self.nzo_id, self.workpath)
self.save_to_disk()
def resume(self):
self.status = Status.QUEUED
@@ -1156,7 +1181,7 @@ class NzbObject(TryList):
# If user resumes after "unwanted" warning, no more auto-pauses
self.unwanted_ext = 2
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def add_parfile(self, parfile):
if not parfile.completed and parfile not in self.files:
self.files.append(parfile)
@@ -1164,11 +1189,11 @@ class NzbObject(TryList):
parfile.extrapars.remove(parfile)
self.remove_extrapar(parfile)
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def remove_parset(self, setname):
self.partable.pop(setname)
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def remove_extrapar(self, parfile):
""" Remove par file from any/all sets """
for _set in self.extrapars:
@@ -1179,7 +1204,7 @@ class NzbObject(TryList):
__re_quick_par2_check = re.compile(r'\.par2\W*', re.I)
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def prospective_add(self, nzf):
""" Add par2 files to compensate for missing articles
"""
@@ -1203,16 +1228,17 @@ class NzbObject(TryList):
for parset in self.extrapars.keys():
if parset in nzf.filename and self.extrapars[parset]:
extrapars_sorted = sorted(self.extrapars[parset], key=lambda x: x.blocks, reverse=True)
# Loop untill we have enough
# Loop until we have enough
while blocks_already < total_need and extrapars_sorted:
# Add the first one
new_nzf = extrapars_sorted.pop()
# Reset NZF TryList, in case something was on it before it became extrapar
new_nzf.reset_try_list()
self.add_parfile(new_nzf)
self.extrapars[parset] = extrapars_sorted
blocks_already = blocks_already + int_conv(new_nzf.blocks)
logging.info('Prospectively added %s repair blocks to %s', new_nzf.blocks, self.final_name)
# Reset all try lists
self.reset_all_try_lists()
# Reset NZO TryList
self.reset_try_list()
def check_quality(self, req_ratio=0):
""" Determine amount of articles present on servers
@@ -1224,7 +1250,6 @@ class NzbObject(TryList):
anypars = False
for nzf_id in self.files_table:
nzf = self.files_table[nzf_id]
if 0: assert isinstance(nzf, NzbFile) # Assert only for debug purposes
if nzf.deleted:
short += nzf.bytes_left
if self.__re_quick_par2_check.search(nzf.subject):
@@ -1241,9 +1266,8 @@ class NzbObject(TryList):
logging.debug('Download Quality: enough=%s, have=%s, need=%s, ratio=%s', enough, have, need, ratio)
return enough, ratio
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def set_download_report(self):
import sabnzbd.api
if self.avg_bps_total and self.bytes_downloaded and self.avg_bps_freq:
# get the deltatime since the download started
avg_bps = self.avg_bps_total / self.avg_bps_freq
@@ -1282,7 +1306,7 @@ class NzbObject(TryList):
msgs = ['%s=%sB' % (servers[server].displayname(), to_units(self.servercount[server])) for server in self.servercount if server in servers]
self.set_unpack_info('Servers', ', '.join(msgs), unique=True)
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def inc_log(self, log, txt):
""" Append string txt to nzo_info element "log" """
try:
@@ -1305,7 +1329,6 @@ class NzbObject(TryList):
nzf_remove_list = []
for nzf in self.files:
if 0: assert isinstance(nzf, NzbFile) # Assert only for debug purposes
if nzf.deleted:
logging.debug('Skipping existing file %s', nzf.filename or nzf.subject)
else:
@@ -1317,7 +1340,7 @@ class NzbObject(TryList):
if sabnzbd.highest_server(server):
nzf.finish_import()
# Still not finished? Something went wrong...
if not nzf.import_finished:
if not nzf.import_finished and not self.is_gone():
logging.error(T('Error importing %s'), nzf)
nzf_remove_list.append(nzf)
continue
@@ -1331,7 +1354,6 @@ class NzbObject(TryList):
# Remove all files for which admin could not be read
for nzf in nzf_remove_list:
nzf.deleted = True
nzf.completed = True
self.files.remove(nzf)
# If cleanup emptied the active files list, end this job
if nzf_remove_list and not self.files:
@@ -1342,7 +1364,7 @@ class NzbObject(TryList):
self.add_to_try_list(server)
return article
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def move_top_bulk(self, nzf_ids):
self.cleanup_nzf_ids(nzf_ids)
if nzf_ids:
@@ -1359,7 +1381,7 @@ class NzbObject(TryList):
if target == keys:
break
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def move_bottom_bulk(self, nzf_ids):
self.cleanup_nzf_ids(nzf_ids)
if nzf_ids:
@@ -1376,7 +1398,7 @@ class NzbObject(TryList):
if target == keys:
break
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def move_up_bulk(self, nzf_ids, cleanup=True):
if cleanup:
self.cleanup_nzf_ids(nzf_ids)
@@ -1393,7 +1415,7 @@ class NzbObject(TryList):
self.files[pos - 1] = nzf
self.files[pos] = tmp_nzf
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def move_down_bulk(self, nzf_ids, cleanup=True):
if cleanup:
self.cleanup_nzf_ids(nzf_ids)
@@ -1412,7 +1434,7 @@ class NzbObject(TryList):
# Determine if rating information (including site identifier so rating can be updated)
# is present in metadata and if so store it
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def update_rating(self):
if cfg.rating_enable():
try:
@@ -1451,7 +1473,7 @@ class NzbObject(TryList):
else:
return None
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def purge_data(self, keep_basic=False, del_files=False):
""" Remove all admin info, 'keep_basic' preserves attribs and nzb """
wpath = self.workpath
@@ -1505,14 +1527,15 @@ class NzbObject(TryList):
self.files if full else [],
queued_files,
self.status, self.priority,
len(self.nzo_info.get('missing_art_log', []))
len(self.nzo_info.get('missing_art_log', [])),
self.bytes_tried - self.bytes_downloaded,
)
def get_nzf_by_id(self, nzf_id):
if nzf_id in self.files_table:
return self.files_table[nzf_id]
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def set_unpack_info(self, key, msg, unique=False):
""" Builds a dictionary containing the stage name (key) and a message
If unique is present, it will only have a single line message
@@ -1525,19 +1548,19 @@ class NzbObject(TryList):
else:
self.unpack_info[key] = [msg]
@synchronized(IO_LOCK)
def set_action_line(self, action=None, msg=None):
# Update the last check time
sabnzbd.LAST_HISTORY_UPDATE = time.time()
if action and msg:
self.action_line = '%s: %s' % (action, msg)
else:
self.action_line = ''
# Make sure it's updated in the interface
sabnzbd.history_updated()
@property
def repair_opts(self):
return self.repair, self.unpack, self.delete
@synchronized(NZO_LOCK)
def save_to_disk(self):
""" Save job's admin to disk """
self.save_attribs()
@@ -1547,7 +1570,7 @@ class NzbObject(TryList):
def save_attribs(self):
set_attrib_file(self.workpath, (self.cat, self.pp, self.script, self.priority, self.final_name, self.password, self.url))
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def build_pos_nzf_table(self, nzf_ids):
pos_nzf_table = {}
for nzf_id in nzf_ids:
@@ -1558,7 +1581,7 @@ class NzbObject(TryList):
return pos_nzf_table
@synchronized(IO_LOCK)
@synchronized(NZO_LOCK)
def cleanup_nzf_ids(self, nzf_ids):
for nzf_id in nzf_ids[:]:
if nzf_id in self.files_table:
@@ -1653,14 +1676,6 @@ def nzf_get_filename(nzf):
return name.lower()
def ext_on_list(name, lst):
""" Return True if `name` contains any extension in `lst` """
for ext in lst:
if name.rfind(ext) >= 0:
return True
return False
def nzf_cmp_date(nzf1, nzf2):
""" Compare files based on date, but give vol-par files preference.
Wrapper needed, because `cmp` function doesn't handle extra parms.

View File

@@ -618,8 +618,8 @@ class SABnzbdDelegate(NSObject):
def diskspaceUpdate(self):
try:
self.completefolder_menu_item.setTitle_("%s%.2f GB" % (T('Complete Folder') + '\t\t\t', diskspace(sabnzbd.cfg.complete_dir.get_path())[1]))
self.incompletefolder_menu_item.setTitle_("%s%.2f GB" % (T('Incomplete Folder') + '\t\t', diskspace(sabnzbd.cfg.download_dir.get_path())[1]))
self.completefolder_menu_item.setTitle_("%s%.2f GB" % (T('Complete Folder') + '\t\t\t', diskspace()['complete_dir'][1]))
self.incompletefolder_menu_item.setTitle_("%s%.2f GB" % (T('Incomplete Folder') + '\t\t', diskspace()['download_dir'][1]))
except:
logging.info("[osx] diskspaceUpdate Exception %s" % (sys.exc_info()[0]))

View File

@@ -30,11 +30,9 @@ except ImportError:
import sabnzbd
import sabnzbd.cfg as cfg
PANIC_NONE = 0
PANIC_PORT = 1
PANIC_TEMPL = 2
PANIC_QUEUE = 3
PANIC_FWALL = 4
PANIC_OTHER = 5
PANIC_SQLITE = 7
PANIC_HOST = 8
@@ -59,16 +57,6 @@ def MSG_BAD_NEWS():
'''
def MSG_BAD_FWALL():
return Ta(r'''
SABnzbd is not compatible with some software firewalls.<br>
%s<br>
Sorry, but we cannot solve this incompatibility right now.<br>
Please file a complaint at your firewall supplier.<br>
<br>
''')
def MSG_BAD_PORT():
return Ta(r'''
SABnzbd needs a free tcp/ip port for its internal web server.<br>
@@ -127,15 +115,6 @@ def MSG_OTHER():
return T('SABnzbd detected a fatal error:') + '<br>%s<br><br>%s<br>'
def MSG_OLD_QUEUE():
return Ta(r'''
SABnzbd detected a queue from an older release.<br><br>
You can convert the queue by clicking "Repair" in Status-&gt;"Queue Repair".<br><br>
You may choose to stop SABnzbd and finish the queue with the older program.<br><br>
Click OK to proceed to SABnzbd''') + \
('''<br><br><FORM><input type="button" onclick="this.form.action='/.'; this.form.submit(); return false;" value="%s"/></FORM>''' % T('OK'))
def MSG_SQLITE():
return Ta(r'''
SABnzbd detected that the file sqlite3.dll is missing.<br><br>
@@ -162,11 +141,6 @@ def panic_message(panic, a=None, b=None):
msg = MSG_BAD_TEMPL() % a
elif panic == PANIC_QUEUE:
msg = MSG_BAD_QUEUE() % (a, os_str, prog_path)
elif panic == PANIC_FWALL:
if a:
msg = MSG_BAD_FWALL() % T('It is likely that you are using ZoneAlarm on Vista.<br>')
else:
msg = MSG_BAD_FWALL() % "<br>"
elif panic == PANIC_SQLITE:
msg = MSG_SQLITE()
elif panic == PANIC_HOST:
@@ -189,10 +163,6 @@ def panic_message(panic, a=None, b=None):
return url
def panic_fwall(vista):
launch_a_browser(panic_message(PANIC_FWALL, vista))
def panic_port(host, port):
print "\n%s:\n %s" % (T('Fatal error'), T('Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running.') % (port, host))
launch_a_browser(panic_message(PANIC_PORT, host, port))
@@ -214,11 +184,6 @@ def panic_sqlite(name):
launch_a_browser(panic_message(PANIC_SQLITE, name, 0))
def panic_old_queue():
msg = MSG_OLD_QUEUE()
return MSG_BAD_NEWS() % (sabnzbd.MY_NAME, sabnzbd.__version__, sabnzbd.MY_NAME, sabnzbd.__version__, msg, '')
def panic(reason, remedy=""):
print "\n%s:\n %s\n%s" % (T('Fatal error'), reason, remedy)
launch_a_browser(panic_message(PANIC_OTHER, reason, remedy))

View File

@@ -34,12 +34,12 @@ from threading import Thread
from sabnzbd.misc import real_path, get_unique_path, create_dirs, move_to_path, \
make_script_path, long_path, clip_path, \
on_cleanup_list, renamer, remove_dir, remove_all, globber, globber_full, \
set_permissions, cleanup_empty_directories, check_win_maxpath, fix_unix_encoding, \
set_permissions, cleanup_empty_directories, fix_unix_encoding, \
sanitize_and_trim_path, sanitize_files_in_folder
from sabnzbd.tvsort import Sorter
from sabnzbd.constants import REPAIR_PRIORITY, TOP_PRIORITY, POSTPROC_QUEUE_FILE_NAME, \
POSTPROC_QUEUE_VERSION, sample_match, JOB_ADMIN, Status, VERIFIED_FILE
from sabnzbd.encoding import TRANS, unicoder, deunicode
from sabnzbd.encoding import TRANS, unicoder
from sabnzbd.rating import Rating
import sabnzbd.emailer as emailer
import sabnzbd.dirscanner as dirscanner
@@ -125,8 +125,7 @@ class PostProcessor(Thread):
self.history_queue.append(nzo)
self.queue.put(nzo)
self.save()
# Update the last check time
sabnzbd.LAST_HISTORY_UPDATE = time.time()
sabnzbd.history_updated()
def remove(self, nzo):
""" Remove given nzo from the queue """
@@ -135,8 +134,7 @@ class PostProcessor(Thread):
except:
pass
self.save()
# Update the last check time
sabnzbd.LAST_HISTORY_UPDATE = time.time()
sabnzbd.history_updated()
def stop(self):
""" Stop thread after finishing running job """
@@ -186,7 +184,6 @@ class PostProcessor(Thread):
try:
nzo = self.queue.get(timeout=1)
if 0: assert isinstance(nzo, sabnzbd.nzbstuff.NzbObject)
except Queue.Empty:
if check_eoq:
check_eoq = False
@@ -230,7 +227,6 @@ class PostProcessor(Thread):
def process_job(nzo):
""" Process one job """
if 0: assert isinstance(nzo, sabnzbd.nzbstuff.NzbObject) # Assert only for debug purposes
start = time.time()
# keep track of whether we can continue
@@ -537,14 +533,6 @@ def process_job(nzo):
for host in hosts:
Rating.do.update_auto_flag(nzo.nzo_id, Rating.FLAG_EXPIRED, host)
# Show final status in history
if all_ok:
notifier.send_notification(T('Download Completed'), filename, 'complete')
nzo.status = Status.COMPLETED
else:
notifier.send_notification(T('Download Failed'), filename, 'failed')
nzo.status = Status.FAILED
except:
logging.error(T('Post Processing Failed for %s (%s)'), filename, crash_msg)
if not crash_msg:
@@ -565,17 +553,6 @@ def process_job(nzo):
workdir_complete = one_file_or_folder(workdir_complete)
workdir_complete = os.path.normpath(workdir_complete)
# Log the overall time taken for postprocessing
postproc_time = int(time.time() - start)
# Create the history DB instance
history_db = database.HistoryDB()
# Add the nzo to the database. Only the path, script and time taken is passed
# Other information is obtained from the nzo
history_db.add_history_db(nzo, clip_path(workdir_complete), nzo.downpath, postproc_time, script_log, script_line)
# The connection is only used once, so close it here
history_db.close()
# Clean up the NZO
try:
logging.info('Cleaning up %s (keep_basic=%s)', filename, str(not all_ok))
@@ -598,9 +575,25 @@ def process_job(nzo):
if par_error or unpack_error in (2, 3):
try_alt_nzb(nzo)
# Update the last check time
sabnzbd.LAST_HISTORY_UPDATE = time.time()
# Show final status in history
if all_ok:
notifier.send_notification(T('Download Completed'), filename, 'complete')
nzo.status = Status.COMPLETED
else:
notifier.send_notification(T('Download Failed'), filename, 'failed')
nzo.status = Status.FAILED
# Log the overall time taken for postprocessing
postproc_time = int(time.time() - start)
# Create the history DB instance
history_db = database.HistoryDB()
# Add the nzo to the database. Only the path, script and time taken is passed
# Other information is obtained from the nzo
history_db.add_history_db(nzo, clip_path(workdir_complete), nzo.downpath, postproc_time, script_log, script_line)
# The connection is only used once, so close it here
history_db.close()
sabnzbd.history_updated()
return True
@@ -700,7 +693,7 @@ def parring(nzo, workdir):
logging.info('Re-added %s to queue', filename)
if nzo.priority != TOP_PRIORITY:
nzo.priority = REPAIR_PRIORITY
sabnzbd.nzbqueue.add_nzo(nzo)
sabnzbd.nzbqueue.NzbQueue.do.add(nzo)
sabnzbd.downloader.Downloader.do.resume_from_postproc()
sabnzbd.save_data(verified, VERIFIED_FILE, nzo.workpath)
@@ -795,21 +788,6 @@ def try_rar_check(nzo, workdir, setname):
return True
def addPrefixes(path, dirprefix):
""" Add list of prefixes as sub folders to path
'/my/path' and ['a', 'b', 'c'] will give '/my/path/a/b/c'
"""
for folder in dirprefix:
if not folder:
continue
if not path:
break
basepath = os.path.basename(os.path.abspath(path))
if folder != basepath.lower():
path = os.path.join(path, folder)
return path
def handle_empty_queue():
""" Check if empty queue calls for action """
if sabnzbd.nzbqueue.NzbQueue.do.actives() == 0:

View File

@@ -116,6 +116,10 @@ except ImportError:
HAVE_DBUS = False
_IS_NOT_INTERACTIVE = False
_LOGIND_SUCCESSFUL_RESULT = 'yes'
def _get_sessionproxy():
""" Return (proxy-object, interface), (None, None) if not available """
name = 'org.freedesktop.PowerManagement'
@@ -145,6 +149,11 @@ def _get_systemproxy(method):
path = '/org/freedesktop/UPower'
interface = 'org.freedesktop.UPower'
pinterface = 'org.freedesktop.DBus.Properties'
elif method == 'Logind':
name = 'org.freedesktop.login1'
path = '/org/freedesktop/login1'
interface = 'org.freedesktop.login1.Manager'
pinterface = None
try:
bus = dbus.SystemBus()
return bus.get_object(name, path), interface, pinterface
@@ -158,20 +167,26 @@ def linux_shutdown():
if not HAVE_DBUS:
os._exit(0)
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanShutdown():
proxy.Shutdown(dbus_interface=interface)
else:
proxy, interface, _pinterface = _get_systemproxy('ConsoleKit')
try:
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanStop(dbus_interface=interface):
try:
proxy.Stop(dbus_interface=interface)
except dbus.exceptions.DBusException, msg:
logging.info('Received a DBus exception %s', msg)
if proxy.CanShutdown():
proxy.Shutdown(dbus_interface=interface)
else:
logging.info('DBus does not support Stop (shutdown)')
proxy, interface, pinterface = _get_systemproxy('Logind')
if proxy:
if proxy.CanPowerOff(dbus_interface=interface) == _LOGIND_SUCCESSFUL_RESULT:
proxy.PowerOff(_IS_NOT_INTERACTIVE, dbus_interface=interface)
else:
proxy, interface, _pinterface = _get_systemproxy('ConsoleKit')
if proxy:
if proxy.CanStop(dbus_interface=interface):
proxy.Stop(dbus_interface=interface)
else:
logging.info('DBus does not support Stop (shutdown)')
except dbus.exceptions.DBusException, msg:
logging.error('Received a DBus exception %s', msg)
os._exit(0)
@@ -180,23 +195,28 @@ def linux_hibernate():
if not HAVE_DBUS:
return
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanHibernate():
proxy.Hibernate(dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('UPower')
if not proxy:
proxy, interface, pinterface = _get_systemproxy('DeviceKit')
try:
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.Get(interface, 'can-hibernate', dbus_interface=pinterface):
try:
proxy.Hibernate(dbus_interface=interface)
except dbus.exceptions.DBusException, msg:
logging.info('Received a DBus exception %s', msg)
if proxy.CanHibernate():
proxy.Hibernate(dbus_interface=interface)
else:
logging.info('DBus does not support Hibernate')
time.sleep(10)
proxy, interface, pinterface = _get_systemproxy('Logind')
if proxy:
if proxy.CanHibernate(dbus_interface=interface) == _LOGIND_SUCCESSFUL_RESULT:
proxy.Hibernate(_IS_NOT_INTERACTIVE, dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('UPower')
if not proxy:
proxy, interface, pinterface = _get_systemproxy('DeviceKit')
if proxy:
if proxy.Get(interface, 'can-hibernate', dbus_interface=pinterface):
proxy.Hibernate(dbus_interface=interface)
else:
logging.info('DBus does not support Hibernate')
time.sleep(10)
except dbus.exceptions.DBusException, msg:
logging.error('Received a DBus exception %s', msg)
def linux_standby():
@@ -204,20 +224,25 @@ def linux_standby():
if not HAVE_DBUS:
return
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.CanSuspend():
proxy.Suspend(dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('UPower')
if not proxy:
proxy, interface, pinterface = _get_systemproxy('DeviceKit')
try:
proxy, interface = _get_sessionproxy()
if proxy:
if proxy.Get(interface, 'can-suspend', dbus_interface=pinterface):
try:
proxy.Suspend(dbus_interface=interface)
except dbus.exceptions.DBusException, msg:
logging.info('Received a DBus exception %s', msg)
if proxy.CanSuspend():
proxy.Suspend(dbus_interface=interface)
else:
logging.info('DBus does not support Suspend (standby)')
time.sleep(10)
proxy, interface, pinterface = _get_systemproxy('Logind')
if proxy:
if proxy.CanSuspend(dbus_interface=interface) == _LOGIND_SUCCESSFUL_RESULT:
proxy.Suspend(_IS_NOT_INTERACTIVE, dbus_interface=interface)
else:
proxy, interface, pinterface = _get_systemproxy('UPower')
if not proxy:
proxy, interface, pinterface = _get_systemproxy('DeviceKit')
if proxy:
if proxy.Get(interface, 'can-suspend', dbus_interface=pinterface):
proxy.Suspend(dbus_interface=interface)
else:
logging.info('DBus does not support Suspend (standby)')
time.sleep(10)
except dbus.exceptions.DBusException, msg:
logging.error('Received a DBus exception %s', msg)

View File

@@ -59,12 +59,6 @@ def stop():
pass
def del_feed(feed):
global __RSS
if __RSS:
__RSS.delete(feed)
def run_feed(feed, download, ignoreFirst=False, force=False, readout=True):
global __RSS
if __RSS:
@@ -173,16 +167,6 @@ LOCK = threading.RLock()
class RSSQueue(object):
def __init__(self):
def check_str(p):
return p is None or p == '' or isinstance(p, basestring)
def check_int(p):
try:
int(p)
return True
except:
return False
self.jobs = {}
self.next_run = time.time()
self.shutdown = False
@@ -197,7 +181,6 @@ class RSSQueue(object):
continue
self.jobs[feed] = {}
for link in feeds[feed]:
data = feeds[feed][link]
# Consistency check on data
try:
item = feeds[feed][link]

View File

@@ -36,7 +36,6 @@ from sabnzbd.constants import LOW_PRIORITY, NORMAL_PRIORITY, HIGH_PRIORITY
__SCHED = None # Global pointer to Scheduler instance
RSSTASK_MINUTE = random.randint(0, 59)
SCHEDULE_GUARD_FLAG = False
PP_PAUSE_EVENT = False

View File

@@ -84,7 +84,6 @@ SKIN_TEXT = {
'pushover-off' : TT('Off'), #: Prowl priority
'pushover-low' : TT('Low'), #: Prowl priority
'pushover-high' : TT('High'), #: Prowl priority
'pushover-confirm' : TT('Confirm'), #: Prowl priority
# General texts
'default' : TT('Default'), #: Default value, used in dropdown menus
@@ -140,7 +139,6 @@ SKIN_TEXT = {
# General template elements
'signOn' : TT('The automatic usenet download tool'), #: SABnzbd's theme line
'button-save' : TT('Save'), #: "Save" button
'queued' : TT('Queued'), #: "Queued" used to show amount of jobs
'confirm' : TT('Are you sure?'), #: Used in confirmation popups
'delFiles' : TT('Delete all downloaded files?'), #: Used in confirmation popups
@@ -155,6 +153,7 @@ SKIN_TEXT = {
'menu-forums' : TT('Forum'), #: Main menu item
'menu-irc' : TT('IRC'), #: Main menu item
'menu-issues' : TT('Issues'), #: Main menu item
'menu-donate' : TT('Support the project, Donate!'), #: Main menu item
'cmenu-general' : TT('General'), #: Main menu item
'cmenu-folders' : TT('Folders'), #: Main menu item
'cmenu-switches' : TT('Switches'), #: Main menu item
@@ -173,7 +172,6 @@ SKIN_TEXT = {
'ft-paused' : TT('PAUSED'), # Used in Footer
'ft-buffer@2' : TT('Cached %s articles (%s)'), # Used in Footer
'ft-sysload' : TT('Sysload'), # Used in Footer
'ft-warning' : TT('WARNINGS'), # Used in Footer
'ft-newRelease@1' : TT('New release %s available at'), # Used in Footer
# Main page
@@ -204,8 +202,6 @@ SKIN_TEXT = {
'enterURL' : TT('Enter URL'), #: Add NZB Dialog
# Queue page
'link-hideFiles' : TT('Hide files'), #: Queue page button
'link-showFiles' : TT('Show files'), #: Queue page button
'onQueueFinish' : TT('On queue finish'), #: Queue page selection menu
'shutdownPc' : TT('Shutdown PC'), #: Queue page end-of-queue action
'standbyPc' : TT('Standby PC'), #: Queue page end-of-queue action
@@ -268,7 +264,6 @@ SKIN_TEXT = {
'log-info' : TT('+ Info'), #: Status page logging selection value
'log-debug' : TT('+ Debug'), #: Status page logging selection value
'connections' : TT('Connections'), #: Status page tab header
'emailResult' : TT('Email Test Result'), #: Status page, title for email test result
'lastWarnings' : TT('Latest Warnings'), #: Status page, table header
'clearWarnings' : TT('clear'), #: Status page button
'server-blocked' : TT('Unblock'), #: Status page button
@@ -299,7 +294,7 @@ SKIN_TEXT = {
# Configuration
'confgFile' : TT('Config File'),
'cache' : TT('Used cache'), #: Main config page, how much cache is in use
'explain-Restart' : TT('This will restart SABnzbd.<br />Use it when you think the program has a stability problem.<br />Downloading will be paused before the restart and resume afterwards.') + TT('<br />If authentication is enabled, you will need to login again.'),
'explain-Restart' : TT('This will restart SABnzbd.<br />Use it when you think the program has a stability problem.<br />Downloading will be paused before the restart and resume afterwards.'),
'explain-needNewLogin' : TT('<br />If authentication is enabled, you will need to login again.'),
'button-advanced' : TT('Advanced'),
'button-restart' : TT('Restart'),
@@ -311,6 +306,7 @@ SKIN_TEXT = {
#'explain-Shutdown' : TT('This will end the SABnzbd process. <br />You will be unable to access SABnzbd and no downloading will take place until the service is started again.'),
'opt-enable_unzip' : TT('Enable Unzip'),
'opt-enable_7zip' : TT('Enable 7zip'),
'opt-multicore-par2' : TT('Multicore Par2'),
'explain-nosslcontext' : TT('Secure (SSL) connections from SABnzbd to newsservers and HTTPS websites will be encrypted, however, validating a server\'s identity using its certificates is not possible. Python 2.7.9 or above, OpenSSL 1.0.2 or above and up-to-date local CA certificates are required.'),
'explain-getpar2mt': TT('Speed up repairs by installing multicore Par2, it is available for many platforms.'),
'version' : TT('Version'),
@@ -333,7 +329,6 @@ SKIN_TEXT = {
'opt-web_password' : TT('SABnzbd Password'),
'explain-web_password' : TT('Optional authentication password.'),
'security' : TT('Security'),
'httpsSupport' : TT('HTTPS Support'),
'opt-enable_https' : TT('Enable HTTPS'),
'opt-notInstalled' : TT('not installed'),
'explain-enable_https' : TT('Enable accessing the interface from a HTTPS address.'),
@@ -448,10 +443,6 @@ SKIN_TEXT = {
'explain-folder_rename' : TT('Use temporary names during post processing. Disable when your system doesn\'t handle that properly.'),
'opt-pre_script' : TT('Pre-queue user script'),
'explain-pre_script' : TT('Used before an NZB enters the queue.'),
'opt-par2_multicore' : TT('Enable MultiCore Par2'),
'explain-par2_multicore' : TT('Read the Wiki Help on this!'),
'opt-par2_multipar' : TT('Enable MultiPar'),
'explain-par2_multipar' : TT('MultiPar is the fastest par2 verification and repair implementation, using multiple cores and the GPU (if available).'),
'opt-par_option' : TT('Extra PAR2 Parameters'),
'explain-par_option' : TT('Read the Wiki Help on this!'),
'opt-nice' : TT('Nice Parameters'),
@@ -471,8 +462,6 @@ SKIN_TEXT = {
'explain-replace_spaces' : TT('Replace spaces with underscores in folder names.'),
'opt-replace_dots' : TT('Replace dots in Foldername'),
'explain-replace_dots' : TT('Replace dots with spaces in folder names.'),
'opt-replace_illegal' : TT('Replace Illegal Characters in Folder Names'),
'explain-replace_illegal' : TT('Replace illegal characters in folder names by equivalents (otherwise remove).'),
'opt-sanitize_safe' : TT('Make Windows compatible'),
'explain-sanitize_safe' : TT('For servers: make sure names are compatible with Windows.'),
'opt-auto_browser' : TT('Launch Browser on Startup'),
@@ -481,11 +470,9 @@ SKIN_TEXT = {
'explain-pause_on_post_processing' : TT('Pauses downloading at the start of post processing and resumes when finished.'),
'opt-ignore_samples' : TT('Ignore Samples'),
'explain-ignore_samples' : TT('Filter out sample files (e.g. video samples).'),
'igsam-off' : TT('Off'),
'igsam-del' : TT('Delete after download'),
'opt-enable_https_verification' : TT('HTTPS certificate verification'),
'explain-enable_https_verification' : TT('Verify certificates when connecting to indexers and RSS-sources using HTTPS.'),
'swtag-general' : TT('General'),
'swtag-server' : TT('Server'),
'swtag-queue' : TT('Queue'),
'swtag-pp' : TT('Post processing'),
@@ -506,8 +493,6 @@ SKIN_TEXT = {
'explain-ssl_ciphers' : TT('Increase performance by forcing a lower SSL encryption strength.'),
'opt-max_art_tries' : TT('Maximum retries'),
'explain-max_art_tries' : TT('Maximum number of retries per server'),
'opt-max_art_opt' : TT('Only for optional servers'),
'explain-max_art_opt' : TT('Apply maximum retries only to optional servers'),
'opt-fail_hopeless_jobs' : TT('Abort jobs that cannot be completed'),
'explain-fail_hopeless_jobs' : TT('When during download it becomes clear that too much data is missing, abort the job'),
'opt-rating_enable' : TT('Enable Indexer Integration'),
@@ -588,7 +573,6 @@ SKIN_TEXT = {
'rss-order' : TT('Order'), #: Config->RSS table column header
'rss-type' : TT('Type'), #: Config->RSS table column header
'rss-filter' : TT('Filter'), #: Config->RSS table column header
'rss-skip' : TT('Skip'), #: Config->RSS table column header
'rss-accept' : TT('Accept'), #: Config->RSS filter-type selection menu
'rss-reject' : TT('Reject'), #: Config->RSS filter-type selection menu
'rss-must' : TT('Requires'), #: Config->RSS filter-type selection menu
@@ -800,7 +784,6 @@ SKIN_TEXT = {
'Glitter-showExtraQueueColumn' : TT('Extra queue column'),
'Glitter-showExtraHistoryColumn' : TT('Extra history column'),
'Glitter-page' : TT('page'),
'Glitter-everything' : TT('Everything'),
'Glitter-loading' : TT('Loading'),
'Glitter-articles' : TT('articles'),
'Glitter-repairQueue' : TT('Queue repair'),

Some files were not shown because too many files have changed in this diff Show More