mirror of
https://github.com/sabnzbd/sabnzbd.git
synced 2026-01-17 12:00:18 -05:00
Compare commits
89 Commits
2.1.0
...
2.2.0Alpha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3e2fb7057 | ||
|
|
ece04909e7 | ||
|
|
963920eb88 | ||
|
|
cf5fa542b6 | ||
|
|
1be7e99754 | ||
|
|
14e3334682 | ||
|
|
b1e033dd55 | ||
|
|
111feb1b57 | ||
|
|
886b23d034 | ||
|
|
f2590792b3 | ||
|
|
02a497ed74 | ||
|
|
48df0eed84 | ||
|
|
0f58cbb671 | ||
|
|
9d71670f59 | ||
|
|
7f838ebb38 | ||
|
|
ef1cb05bc8 | ||
|
|
c14b3ed82a | ||
|
|
792e337936 | ||
|
|
6cd2e66052 | ||
|
|
728022b86d | ||
|
|
7718446313 | ||
|
|
66dea54053 | ||
|
|
f19b60bd41 | ||
|
|
09f1c92856 | ||
|
|
589715901d | ||
|
|
3f1a5ff5e0 | ||
|
|
49cd956d4c | ||
|
|
f9acde862f | ||
|
|
503e1dd899 | ||
|
|
c8e12b948d | ||
|
|
18949d68c0 | ||
|
|
0c51b6c016 | ||
|
|
63a5c22c1f | ||
|
|
f76e2a7b56 | ||
|
|
bab151d6f5 | ||
|
|
d43fec088b | ||
|
|
a8ca1cbcd7 | ||
|
|
ada3494483 | ||
|
|
43c238b7f1 | ||
|
|
128d10c51e | ||
|
|
1a1e01f9f6 | ||
|
|
8483e4ab8a | ||
|
|
f6c163b505 | ||
|
|
8f30173db0 | ||
|
|
0372ff95bb | ||
|
|
6fa29c7877 | ||
|
|
d4c9121593 | ||
|
|
76a8df0282 | ||
|
|
0b6d8309a0 | ||
|
|
10a9bc0817 | ||
|
|
2a14af4ffa | ||
|
|
d1a4a292e3 | ||
|
|
14c0efa151 | ||
|
|
4fc03f2581 | ||
|
|
3205b9fda9 | ||
|
|
953e0d6c22 | ||
|
|
b50ce54ca9 | ||
|
|
5e7558ce4a | ||
|
|
8aa6362432 | ||
|
|
02ebb97a8b | ||
|
|
b36063403d | ||
|
|
526ffa2afb | ||
|
|
5b3fd812d8 | ||
|
|
af6dac9cdc | ||
|
|
bc25d936bb | ||
|
|
b497fe1444 | ||
|
|
3f456cce05 | ||
|
|
4dd2f089ec | ||
|
|
b1b1bc248d | ||
|
|
d9e675469c | ||
|
|
ede0ca1772 | ||
|
|
2d098a1477 | ||
|
|
e5f014b68e | ||
|
|
b3a9dc9eeb | ||
|
|
2a06cec27c | ||
|
|
19230c889d | ||
|
|
c969ce552c | ||
|
|
2def600d21 | ||
|
|
02aa8f18c8 | ||
|
|
fcd9522dae | ||
|
|
72d3ce885e | ||
|
|
b428996eb7 | ||
|
|
2b4eb58fad | ||
|
|
240e8dff60 | ||
|
|
1c286afde6 | ||
|
|
2eeb908540 | ||
|
|
562e6ecce9 | ||
|
|
4bd0d32508 | ||
|
|
6f2ccbef80 |
@@ -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,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SABnzbd 2.1.0
|
||||
SABnzbd 2.2.0
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
0) LICENSE
|
||||
|
||||
6
PKG-INFO
6
PKG-INFO
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
59
README.mkd
59
README.mkd
@@ -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
|
||||
|
||||
23
SABnzbd.py
23
SABnzbd.py
@@ -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)
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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('')
|
||||
}
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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#-->
|
||||
|
||||
@@ -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&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&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>
|
||||
|
||||
@@ -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(/"/g,'"');
|
||||
glitterTranslate.removeDown = "$T('Glitter-confirmClearDownloads')";
|
||||
glitterTranslate.removeDow1 = "$T('Glitter-confirmClear1Download')";
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />-->
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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
121
po/email/he.po
Normal 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 ""
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
2433
po/main/SABnzbd.pot
2433
po/main/SABnzbd.pot
File diff suppressed because it is too large
Load Diff
2527
po/main/da.po
2527
po/main/da.po
File diff suppressed because it is too large
Load Diff
2529
po/main/de.po
2529
po/main/de.po
File diff suppressed because it is too large
Load Diff
@@ -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!"
|
||||
|
||||
|
||||
2529
po/main/es.po
2529
po/main/es.po
File diff suppressed because it is too large
Load Diff
2533
po/main/fi.po
2533
po/main/fi.po
File diff suppressed because it is too large
Load Diff
2539
po/main/fr.po
2539
po/main/fr.po
File diff suppressed because it is too large
Load Diff
4812
po/main/he.po
Normal file
4812
po/main/he.po
Normal file
File diff suppressed because it is too large
Load Diff
2521
po/main/nb.po
2521
po/main/nb.po
File diff suppressed because it is too large
Load Diff
2553
po/main/nl.po
2553
po/main/nl.po
File diff suppressed because it is too large
Load Diff
2523
po/main/pl.po
2523
po/main/pl.po
File diff suppressed because it is too large
Load Diff
2525
po/main/pt_BR.po
2525
po/main/pt_BR.po
File diff suppressed because it is too large
Load Diff
2526
po/main/ro.po
2526
po/main/ro.po
File diff suppressed because it is too large
Load Diff
2522
po/main/ru.po
2522
po/main/ru.po
File diff suppressed because it is too large
Load Diff
2519
po/main/sr.po
2519
po/main/sr.po
File diff suppressed because it is too large
Load Diff
2521
po/main/sv.po
2521
po/main/sv.po
File diff suppressed because it is too large
Load Diff
2521
po/main/zh_CN.po
2521
po/main/zh_CN.po
File diff suppressed because it is too large
Load Diff
@@ -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 ""
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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
98
po/nsis/he.po
Normal 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 "ההגדרות והנתונים שלך יישמרו."
|
||||
@@ -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å."
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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 "Ваши параметры и данные будут сохранены."
|
||||
|
||||
@@ -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 "Ваша подешавања и подаци биће сачувани."
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
@@ -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 "您的设置及数据将会保留。"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 """
|
||||
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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&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.
|
||||
|
||||
@@ -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]))
|
||||
|
||||
|
||||
@@ -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->"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))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user