mirror of
https://github.com/sabnzbd/sabnzbd.git
synced 2026-01-16 03:21:11 -05:00
Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ca4811689 | ||
|
|
043e5966ff | ||
|
|
f1695ec875 | ||
|
|
a3db910a4d | ||
|
|
80a29c50c9 | ||
|
|
d693e20e1a | ||
|
|
1a36f548df | ||
|
|
a6f6d88ab9 | ||
|
|
aa7fb17b4e | ||
|
|
a99d333272 | ||
|
|
801aadecfc | ||
|
|
124e2b253c | ||
|
|
39cceed580 | ||
|
|
bfcf56ec45 | ||
|
|
01603b24f5 | ||
|
|
d93d2591b7 | ||
|
|
c17fcec499 | ||
|
|
6804ac20da | ||
|
|
4ed7ac3dea | ||
|
|
eae8056366 | ||
|
|
df4680b6d0 | ||
|
|
b8f5861044 | ||
|
|
8e01ceca7a | ||
|
|
0e1cdec78f | ||
|
|
13e5e93953 | ||
|
|
02d08f38eb | ||
|
|
770951bfe6 | ||
|
|
022898bf63 | ||
|
|
4fd2d8505b | ||
|
|
cc72bb743a | ||
|
|
d7869fc3a1 | ||
|
|
4fbf870028 | ||
|
|
306558b52f | ||
|
|
db19875f5d | ||
|
|
f8061dc9c8 | ||
|
|
c73591eb20 | ||
|
|
ec132374a6 | ||
|
|
262964c6c2 | ||
|
|
cdaad3ed90 | ||
|
|
84f54f5c57 | ||
|
|
00436dfb2c | ||
|
|
c3ce87bd10 | ||
|
|
c3a48a61b6 | ||
|
|
0c03476d76 | ||
|
|
6148cd5445 | ||
|
|
7f72e2042c | ||
|
|
638b29819c | ||
|
|
b950820099 | ||
|
|
96adf76ef1 | ||
|
|
556a4db186 | ||
|
|
b9fbd19064 | ||
|
|
167e7f2870 | ||
|
|
4dba5b8caa | ||
|
|
831b64daa8 | ||
|
|
38fd5cde29 | ||
|
|
e39456cca1 | ||
|
|
8e9425855b | ||
|
|
89add6edac | ||
|
|
16b85429ae | ||
|
|
2482c8e70a | ||
|
|
ad2bb6c3a7 | ||
|
|
2c7e725e39 | ||
|
|
123f05f164 | ||
|
|
4ade2e0c60 | ||
|
|
c908a396df | ||
|
|
15f2370bca | ||
|
|
a5e208eb11 | ||
|
|
d59b3b3679 | ||
|
|
476542463a | ||
|
|
52267a9565 | ||
|
|
972e708810 | ||
|
|
a636f7f18e | ||
|
|
9d5b3e9621 | ||
|
|
9e2d8e5e55 | ||
|
|
d9899cc5cd | ||
|
|
650e83e1b8 | ||
|
|
4296e1628b | ||
|
|
5dddc7ab61 | ||
|
|
529ba69584 | ||
|
|
9f35568a24 | ||
|
|
fe40d49c26 | ||
|
|
6c0b32004a | ||
|
|
bda4e102d6 | ||
|
|
5e03204dbc | ||
|
|
b5deda4195 | ||
|
|
5076892d83 | ||
|
|
6c3a3e1694 | ||
|
|
edbbcec272 | ||
|
|
aced381763 | ||
|
|
cdd3f9cc8a | ||
|
|
a2074f06d5 | ||
|
|
39aa3a9c51 | ||
|
|
c6cf3cc45d | ||
|
|
0378f6f8b1 | ||
|
|
d6b48803a6 | ||
|
|
6da23930bf | ||
|
|
d4e1464cc0 | ||
|
|
e8dc3ebd51 | ||
|
|
4009d855c3 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -31,3 +31,6 @@ SABnzbd*.dmg
|
||||
# Some people use Emacs as an editor
|
||||
\#*
|
||||
.\#*
|
||||
|
||||
.DS_Store
|
||||
/venv
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
*******************************************
|
||||
*** This is SABnzbd 2.3.0 ***
|
||||
*** This is SABnzbd 2.4.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.3.0
|
||||
SABnzbd 2.3.1
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
0) LICENSE
|
||||
@@ -60,6 +60,7 @@ All platforms
|
||||
|
||||
Windows
|
||||
PyWin32 use "pip install pypiwin32"
|
||||
subprocessww use "pip install subprocessww"
|
||||
|
||||
Essential modules
|
||||
cheetah-2.0.1+ use "pip install cheetah"
|
||||
@@ -71,7 +72,7 @@ Essential modules
|
||||
Optional modules
|
||||
unzip >= 6.00 http://www.info-zip.org/
|
||||
7zip >= 9.20 http://www.7zip.org/
|
||||
sabyenc == 3.0.2 use "pip install sabyenc"
|
||||
sabyenc == 3.3.1 use "pip install sabyenc"
|
||||
More information: https://sabnzbd.org/sabyenc
|
||||
cryptography >= 1.0 use "pip install cryptography"
|
||||
Enables certificate generation and detection of encrypted RAR-files
|
||||
@@ -92,12 +93,11 @@ Start this from a shell terminal (or command prompt):
|
||||
python tools/make_mo.py
|
||||
|
||||
Start this from a shell terminal (or command prompt):
|
||||
python SABnzbd.py
|
||||
python -OO SABnzbd.py
|
||||
|
||||
Within a few seconds your web browser will start and show the user interface.
|
||||
Use the "Help" button in the web-interface to be directed to the Help Wiki.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
5) TROUBLESHOOTING
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -123,7 +123,6 @@ may help you solve problems easier.
|
||||
Visit our wiki:
|
||||
https://sabnzbd.org/wiki/
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
7) CREDITS
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
4
PKG-INFO
4
PKG-INFO
@@ -1,7 +1,7 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: SABnzbd
|
||||
Version: 2.3.0
|
||||
Summary: SABnzbd-2.3.0
|
||||
Version: 2.3.1
|
||||
Summary: SABnzbd-2.3.1
|
||||
Home-page: https://sabnzbd.org
|
||||
Author: The SABnzbd Team
|
||||
Author-email: team@sabnzbd.org
|
||||
|
||||
@@ -13,7 +13,6 @@ SABnzbd has a good deal of dependencies you'll need before you can get running.
|
||||
|
||||
- `python` (only 2.7.x and higher, but not 3.x.x)
|
||||
- `python-cheetah`
|
||||
- `python-support`
|
||||
- `par2` (Multi-threaded par2 installation guide can be found [here](https://sabnzbd.org/wiki/installation/multicore-par2))
|
||||
- `unrar` (Make sure you get the "official" non-free version of unrar)
|
||||
- `sabyenc` (installation guide can be found [here](https://sabnzbd.org/sabyenc))
|
||||
|
||||
88
README.mkd
88
README.mkd
@@ -1,59 +1,57 @@
|
||||
Release Notes - SABnzbd 2.3.0
|
||||
Release Notes - SABnzbd 2.3.1
|
||||
=========================================================
|
||||
|
||||
## SABYenc updated
|
||||
- Improved download performance 10-15% on CPU limited devices
|
||||
by optimizations and by removing redundant article verification.
|
||||
Linux/NAS: Update of SABYenc to version 3.3.1 is required.
|
||||
Update your package or see https://sabnzbd.org/sabyenc
|
||||
Windows/macOS: Update is included in the installers.
|
||||
## Changes since 2.3.0
|
||||
- Added post-processing script Deobfuscate.py (in "scripts" folder)
|
||||
which can automatically process "rename.par2" after unpacking
|
||||
or rename the largest file in the folder to the job's name
|
||||
- Maximum Article Cache size increased to 4GB on 64 bit systems
|
||||
- New servers will have timeout of 60 seconds instead of 120
|
||||
- Last output of a running script is shown in history
|
||||
- Paths to par2, unrar, unzip and 7zip are passed to scripts
|
||||
- Path to gzipped NZB file of job is passed to scripts
|
||||
- Windows: Single click on tray icon pauses/unpauses queue
|
||||
|
||||
## Changes since 2.2.1
|
||||
- Option to limit Servers to specific Categories removed
|
||||
- Improved par2 handling and obfuscated files detection
|
||||
- Duplicate filenames in NZB's no longer rejected by default
|
||||
- Set custom URL instead of /sabnzbd/ (in Config > Specials)
|
||||
- Article-state (which servers are tried) is preserved after restart
|
||||
- Auto disconnect (if enabled) only after verification of last item
|
||||
- Slight performance improvement when fetching RSS-feeds
|
||||
- Job title from RSS-feed is shown for URLs being grabbed
|
||||
- URL grabbing can now be individually paused
|
||||
- Scheduler can pause/unpause jobs in specific category
|
||||
- Series Duplicate Checker can allow PROPER/REAL/REPACK versions
|
||||
- Refresh-icon in Glitter when refresh rate is above 2 seconds
|
||||
- Different icon for downloads with Force priority
|
||||
- Show progress during verification of extra files
|
||||
- All dates and times are now time zone independent
|
||||
- API: 'missing' field removed from 'queue', use 'mbmissing'
|
||||
- API: 'warnings' method now returns array for better handling
|
||||
- macOS: Bundled new OpenSSL version with support for TLSv1.2
|
||||
- macOS: No longer linked to system certificate store
|
||||
- macOS and Windows: Installers include Mozilla CA certificates
|
||||
## Bugfixes since 2.3.0
|
||||
- Abort Direct Unpack if not progressing 2 minutes after download
|
||||
- Direct Unpacker could crash on some downloads
|
||||
- Added measures to prevent "Failed to import" errors
|
||||
- Downloader could crash during first few seconds after start
|
||||
- Saving errors of renames-file prevented
|
||||
- More verbose logging of creating and deleting files
|
||||
- Remove ".par2" at end of job name, could cause failure of repair
|
||||
- Fix racing-condition for files coming in after a job finishes
|
||||
- When re-adding a job, the time left was not calculated
|
||||
- Priority of category was ignored when adding new job
|
||||
- Server information in Status window was not always updated
|
||||
- Always show Direct Unpack status on smaller screens
|
||||
- Correctly adapt date and time display to local time zone
|
||||
- Category folders cannot be sub-folders of Temporary Download Folder
|
||||
- Email notifications could not be limited to categories
|
||||
- Testing email notifications did not work
|
||||
- Added "with" to list of lowercase words in titles for Sorting
|
||||
- "From SxxEyy" RSS filter did not always work
|
||||
- Show clearly that RSS "From Show SxxEyy" is an "Accept"-type filter
|
||||
- Sorting failed when "Ignore folders inside archives" was enabled
|
||||
- Always send "failure_url" to post-processing scripts
|
||||
- Decoding of articles no longer logged by default to reduce logging
|
||||
- Windows: Remove incompatible "Extra Par2 Parameters" for MultiPar
|
||||
- Windows: Special filenames could cause failures during unpack
|
||||
- Windows: Message box is shown in case of fatal startup error
|
||||
- Windows: Unpacking to network shares could fail
|
||||
- macOS: Added Safari pinned tab icon
|
||||
|
||||
## Bugfixes since 2.2.1
|
||||
- Reduce CPU usage with multiple servers
|
||||
- Fix yet another potential stalling issue
|
||||
- Remove Timeout tracebacks
|
||||
- Handle locked history database better
|
||||
- Only warn if number of actual passwords is larger than 30
|
||||
- Unexpected behavior when diskspace becomes critically low
|
||||
- Retried jobs would show incorrect download progress
|
||||
- Password file was loaded from disk excessively
|
||||
- API: Correct listing of downloaded and queued files in 'get_files'
|
||||
- API: Number of bytes missing and downloaded could be slightly off
|
||||
- API: Jobs with Force priority should always have status 'Downloading'
|
||||
- MacOS: Direct Unpack could hang in case of special characters in names
|
||||
- Windows: Unpack could fail if started instantly after previous one
|
||||
- Windows: Download with many par2 sets could get listed as failed
|
||||
In case of "Article DB missing/empty" errors, enable +Debug logging
|
||||
and report here: https://github.com/sabnzbd/sabnzbd/issues/952
|
||||
|
||||
## Upgrading from 2.1.x and older
|
||||
## Upgrading from 2.2.x and older
|
||||
- Finish queue
|
||||
- Stop SABnzbd
|
||||
- Install new version
|
||||
- Start SABnzbd
|
||||
|
||||
## Upgrade notices
|
||||
- When upgrading from 2.1.0 or older the queue will be converted. Job order,
|
||||
- When upgrading from 2.2.0 or older the queue will be converted. 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.
|
||||
- The organization of the download queue is different from 0.7.x releases.
|
||||
|
||||
@@ -87,7 +87,7 @@ import sabnzbd.interface
|
||||
from sabnzbd.constants import *
|
||||
import sabnzbd.newsunpack
|
||||
from sabnzbd.misc import real_path, \
|
||||
check_latest_version, exit_sab, \
|
||||
check_latest_version, exit_sab, get_from_url, \
|
||||
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, \
|
||||
@@ -657,7 +657,7 @@ def is_sabnzbd_running(url):
|
||||
url = '%s&mode=version' % (url)
|
||||
# Do this without certificate verification, few installations will have that
|
||||
prev = sabnzbd.set_https_verification(False)
|
||||
ver = sabnzbd.newsunpack.get_from_url(url)
|
||||
ver = get_from_url(url)
|
||||
sabnzbd.set_https_verification(prev)
|
||||
return (ver and (re.search(r'\d+\.\d+\.', ver) or ver.strip() == sabnzbd.__version__))
|
||||
except:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
install:
|
||||
- pip install --upgrade -r tests/requirements.txt
|
||||
- pip install pypiwin32
|
||||
- pip install pypiwin32 subprocessww
|
||||
|
||||
build_script:
|
||||
- pytest
|
||||
|
||||
@@ -596,7 +596,7 @@ class MemcachedSession(Session):
|
||||
# Wrap all .get and .set operations in a single lock.
|
||||
mc_lock = threading.RLock()
|
||||
|
||||
# This is a seperate set of locks per session id.
|
||||
# This is a separate set of locks per session id.
|
||||
locks = {}
|
||||
|
||||
servers = ['127.0.0.1:11211']
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
<form action="saveGeneral" method="post" name="fullform" class="fullform" autocomplete="off" novalidate>
|
||||
<form action="saveGeneral" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="session" name="session" value="$session" />
|
||||
<input type="hidden" id="ajax" name="ajax" value=1 />
|
||||
<div class="section">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<!--#end def#-->
|
||||
|
||||
<div class="colmask">
|
||||
<form action="saveEmail" method="post" name="fullform" class="fullform" autocomplete="off" novalidate>
|
||||
<form action="saveEmail" method="post" name="fullform" class="fullform" autocomplete="off">
|
||||
<input type="hidden" id="session" name="session" value="$session" />
|
||||
<input type="hidden" id="ajax" name="ajax" value="1" />
|
||||
<div class="section" id="email">
|
||||
@@ -326,6 +326,16 @@
|
||||
<input type="text" name="pushover_device" id="pushover_device" value="$pushover_device" />
|
||||
<span class="desc">$T('explain-pushover_device')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="pushover_emergency_retry">$T('opt-pushover_emergency_retry')</label>
|
||||
<input type="text" name="pushover_emergency_retry" id="pushover_emergency_retry" value="$pushover_emergency_retry" />
|
||||
<span class="desc">$T('explain-pushover_emergency_retry')</span>
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="pushover_emergency_expire">$T('opt-pushover_emergency_expire')</label>
|
||||
<input type="text" name="pushover_emergency_expire" id="pushover_emergency_expire" value="$pushover_emergency_expire" />
|
||||
<span class="desc">$T('explain-pushover_emergency_expire')</span>
|
||||
</div>
|
||||
<!--#set $section_label = 'pushover'#-->
|
||||
<!--#for $type in $notify_keys#-->
|
||||
<div class="field-pair">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="padTable">
|
||||
<a class="main-helplink" href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
|
||||
<p>$T('explain-RSS')</p>
|
||||
<form action="add_rss_feed" method="post" autocomplete="off" novalidate>
|
||||
<form action="add_rss_feed" method="post" autocomplete="off">
|
||||
<input type="hidden" name="session" value="$session" />
|
||||
<table class="catTable">
|
||||
<tr>
|
||||
@@ -37,7 +37,7 @@
|
||||
<!--#if $rss#-->
|
||||
<div class="section">
|
||||
<div class="padTable">
|
||||
<form action="save_rss_feed" method="post" autocomplete="off" novalidate>
|
||||
<form action="save_rss_feed" method="post" autocomplete="off">
|
||||
<input type="hidden" name="session" value="$session" />
|
||||
<table id="subscriptions">
|
||||
<tbody>
|
||||
@@ -73,7 +73,7 @@
|
||||
</form>
|
||||
<!--#if $feeds#-->
|
||||
<br/>
|
||||
<form action="rss_now" method="post" autocomplete="off" novalidate>
|
||||
<form action="rss_now" method="post" autocomplete="off">
|
||||
<input type="hidden" name="session" value="$session" />
|
||||
<button type="submit" class="btn btn-default readAll"><span class="glyphicon glyphicon-sort"></span> $T('button-rssNow')</button>
|
||||
</form>
|
||||
@@ -154,7 +154,7 @@
|
||||
<option value=">"> $T('rss-atleast')</option>
|
||||
<option value="<"> $T('rss-atmost')</option>
|
||||
<option value="F"> $T('rss-from')</option>
|
||||
<option value="F"> $T('rss-from-show')</option>
|
||||
<option value="F"> $T('rss-from-show') ($T('rss-accept'))</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
@@ -226,8 +226,8 @@
|
||||
<option value="C"> $T('rss-mustcat')</option>
|
||||
<option value=">"> $T('rss-atleast')</option>
|
||||
<option value="<"> $T('rss-atmost')</option>
|
||||
<option value="S"> $T('rss-from-show')</option>
|
||||
<option value="F"> $T('rss-from')</option>
|
||||
<option value="S"> $T('rss-from-show') ($T('rss-accept'))</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
@@ -287,7 +287,7 @@
|
||||
<input type="hidden" name="feed" value="$feed" />
|
||||
<table class="catTable">
|
||||
<tbody>
|
||||
<tr class="<!--#if $odd then " alt " else " "#--> <!--#if $filter[3]!="A" then 'disabled_options_rule' else ""#-->">
|
||||
<tr class="<!--#if $odd then " alt " else " "#--> <!--#if $filter[3]!="A" and $filter[3]!="S" then 'disabled_options_rule' else ""#-->">
|
||||
<td>
|
||||
<input type="checkbox" name="enabled" value="1" <!--#if $filter[6]=='1' then 'checked="checked"' else ""#--> />
|
||||
</td>
|
||||
@@ -302,8 +302,8 @@
|
||||
<option value="C" <!--#if $filter[3]=="C" then 'selected="selected"' else ""#-->> $T('rss-mustcat')</option>
|
||||
<option value=">" <!--#if $filter[3]==">" then 'selected="selected"' else ""#-->> $T('rss-atleast')</option>
|
||||
<option value="<" <!--#if $filter[3]=="<" then 'selected="selected"' else ""#-->> $T('rss-atmost')</option>
|
||||
<option value="S" <!--#if $filter[3]=="S" then 'selected="selected"' else ""#-->> $T('rss-from-show')</option>
|
||||
<option value="F" <!--#if $filter[3]=="F" then 'selected="selected"' else ""#-->> $T('rss-from')</option>
|
||||
<option value="S" <!--#if $filter[3]=="S" then 'selected="selected"' else ""#-->> $T('rss-from-show') ($T('rss-accept'))</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
@@ -568,7 +568,7 @@ function urlencode(str) {
|
||||
|
||||
// Only the Accept filter needs all the options
|
||||
\$('form[action="upd_rss_filter"]').find('select[name="filter_type"]').change(function() {
|
||||
\$(this).parent().parent().find('select:not([name="filter_type"])').attr('disabled', \$(this).val() != "A")
|
||||
\$(this).parent().parent().find('select:not([name="filter_type"])').attr('disabled', \$(this).val() != "A" && \$(this).val() != "S")
|
||||
})
|
||||
// Trigger on-load for all
|
||||
\$('.disabled_options_rule').find('td select:not([name="filter_type"])').attr('disabled', true)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
|
||||
|
||||
<div class="colmask">
|
||||
<form action="addServer" method="post" autocomplete="off" onsubmit="removeObfuscation();" novalidate>
|
||||
<form action="addServer" method="post" autocomplete="off" onsubmit="removeObfuscation();">
|
||||
<input type="hidden" name="session" value="$session" />
|
||||
<div id="addServer">
|
||||
<div class="padding alt">
|
||||
@@ -23,11 +23,11 @@
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="host">$T('srv-host')</label>
|
||||
<input type="text" name="host" id="host" />
|
||||
<input type="text" name="host" id="host" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="port">$T('srv-port')</label>
|
||||
<input type="number" name="port" id="port" size="8" value="119" />
|
||||
<input type="number" name="port" id="port" size="8" value="119" min="0" />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="ssl">$T('srv-ssl')</label>
|
||||
@@ -45,11 +45,11 @@
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="connections">$T('srv-connections')</label>
|
||||
<input type="number" name="connections" id="connections" min="0" max="100" value="8" />
|
||||
<input type="number" name="connections" id="connections" min="1" max="100" value="8" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="priority">$T('srv-priority')</label>
|
||||
<input type="number" name="priority" id="priority" min="0" max="100" /> <i>$T('explain-svrprio')</i>
|
||||
<input type="number" name="priority" id="priority" min="0" max="99" /> <i>$T('explain-svrprio')</i>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="retention">$T('srv-retention')</label>
|
||||
@@ -57,7 +57,7 @@
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="timeout">$T('srv-timeout')</label>
|
||||
<input type="number" name="timeout" id="timeout" min="30" /> <i>$T('seconds')</i>
|
||||
<input type="number" name="timeout" id="timeout" min="20" max="240" /> <i>$T('seconds')</i>
|
||||
</div>
|
||||
<div class="field-pair <!--#if int($have_ssl_context) == 0 then "disabled" else ""#--> advanced-settings">
|
||||
<label class="config" for="ssl_verify">$T('opt-ssl_verify')</label>
|
||||
@@ -156,7 +156,7 @@
|
||||
<!--#set $cur_prio_color = -1 #-->
|
||||
<!--#set $last_prio = -1 #-->
|
||||
<!--#for $cur, $server in enumerate($servers) #-->
|
||||
<form action="saveServer" method="post" class="fullform" autocomplete="off" novalidate>
|
||||
<form action="saveServer" method="post" class="fullform" autocomplete="off">
|
||||
<input type="hidden" name="session" value="$session" />
|
||||
<input type="hidden" name="server" value="$server['name']" />
|
||||
|
||||
@@ -185,11 +185,11 @@
|
||||
<fieldset>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="host$cur">$T('srv-host')</label>
|
||||
<input type="text" name="host" id="host$cur" value="$server['host']" />
|
||||
<input type="text" name="host" id="host$cur" value="$server['host']" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="port$cur">$T('srv-port')</label>
|
||||
<input type="number" name="port" id="port$cur" value="$server['port']" size="8" />
|
||||
<input type="number" name="port" id="port$cur" value="$server['port']" size="8" min="0" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="ssl$cur">$T('srv-ssl')</label>
|
||||
@@ -207,19 +207,19 @@
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="connections$cur">$T('srv-connections')</label>
|
||||
<input type="number" name="connections" id="connections$cur" value="$server['connections']" min="0" max="100" />
|
||||
<input type="number" name="connections" id="connections$cur" value="$server['connections']" min="1" max="100" required />
|
||||
</div>
|
||||
<div class="field-pair">
|
||||
<label class="config" for="priority$cur">$T('srv-priority')</label>
|
||||
<input type="number" name="priority" id="priority$cur" value="$server['priority']" min="0" max="100" /> <i>$T('explain-svrprio')</i>
|
||||
<input type="number" name="priority" id="priority$cur" value="$server['priority']" min="0" max="99" required /> <i>$T('explain-svrprio')</i>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="retention$cur">$T('srv-retention')</label>
|
||||
<input type="number" name="retention" id="retention$cur" value="$server['retention']" min="0" /> <i>$T('days')</i>
|
||||
<input type="number" name="retention" id="retention$cur" value="$server['retention']" min="0" required /> <i>$T('days')</i>
|
||||
</div>
|
||||
<div class="field-pair advanced-settings">
|
||||
<label class="config" for="timeout$cur">$T('srv-timeout')</label>
|
||||
<input type="number" name="timeout" id="timeout$cur" value="$server['timeout']" min="30" /> <i>$T('seconds')</i>
|
||||
<input type="number" name="timeout" id="timeout$cur" value="$server['timeout']" min="20" max="240" required /> <i>$T('seconds')</i>
|
||||
</div>
|
||||
|
||||
<div class="field-pair <!--#if int($have_ssl_context) == 0 then "disabled" else ""#--> advanced-settings">
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="608.000000pt" height="608.000000pt" viewBox="0 0 608.000000 608.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<g transform="translate(0.000000,608.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M1295 5818 c-46 -17 -81 -45 -107 -86 l-23 -37 -5 -1160 -5 -1160
|
||||
-386 -5 -386 -5 -40 -28 c-80 -56 -113 -173 -70 -257 9 -19 91 -113 182 -209
|
||||
91 -96 165 -177 165 -180 -1 -3 -18 -18 -39 -32 -21 -15 -48 -46 -60 -71 -21
|
||||
-43 -21 -54 -21 -514 0 -441 1 -472 19 -507 18 -36 18 -38 0 -74 -17 -33 -19
|
||||
-61 -19 -236 0 -222 6 -245 74 -305 60 -53 76 -54 851 -50 706 3 710 3 751 25
|
||||
26 13 45 18 51 12 5 -5 32 -17 60 -27 46 -15 77 -44 336 -317 157 -165 300
|
||||
-309 319 -320 24 -14 51 -20 98 -20 47 0 74 6 98 20 19 11 162 155 319 320
|
||||
200 211 295 304 321 315 20 8 46 20 56 26 15 9 26 7 55 -10 36 -21 39 -21 781
|
||||
-21 l745 0 45 25 c24 14 58 45 75 68 l30 44 3 746 2 746 -25 51 c-14 29 -40
|
||||
63 -60 77 l-35 25 170 179 c94 98 178 195 188 214 41 84 9 202 -71 257 l-40
|
||||
28 -386 5 -386 5 -5 1162 -5 1161 -30 43 c-16 23 -48 52 -70 63 l-40 21 -1725
|
||||
2 c-1202 1 -1734 -2 -1755 -9z m3215 -1488 l0 -1080 -284 0 -284 0 -53 -28
|
||||
c-39 -20 -62 -41 -84 -77 l-30 -48 -3 -199 -4 -198 -736 0 c-703 0 -739 -1
|
||||
-779 -19 -41 -19 -42 -19 -79 0 -36 18 -64 19 -510 19 l-472 0 -122 128 -122
|
||||
127 239 5 c258 5 269 8 325 67 61 64 58 -6 58 1243 l0 1140 1470 0 1470 0 0
|
||||
-1080z m32 -1562 l3 -273 408 -3 407 -2 0 -690 0 -690 -690 0 -690 0 0 965 0
|
||||
965 280 0 280 0 2 -272z m558 155 c-19 -21 -75 -80 -125 -130 l-90 -93 -67 0
|
||||
-68 0 0 130 0 130 192 0 192 0 -34 -37z m-3010 -573 l0 -140 -410 0 -410 0 0
|
||||
-130 0 -130 408 -2 407 -3 0 -415 0 -415 -692 -3 -693 -2 0 145 0 145 410 0
|
||||
410 0 0 130 0 130 -410 0 -410 0 0 415 0 415 695 0 695 0 0 -140z m1630 -550
|
||||
l0 -690 -690 0 -690 0 0 420 0 420 410 0 410 0 0 130 0 130 -410 0 -410 0 0
|
||||
140 0 140 690 0 690 0 0 -690z m-611 -967 c-35 -38 -66 -68 -69 -68 -3 0 -34
|
||||
30 -69 68 l-63 67 132 0 132 0 -63 -67z"/>
|
||||
<path d="M4547 2203 c-4 -3 -7 -186 -7 -405 l0 -398 130 0 130 0 0 405 0 405
|
||||
-123 0 c-68 0 -127 -3 -130 -7z"/>
|
||||
<path d="M2902 1533 l3 -128 128 -3 127 -3 0 131 0 130 -130 0 -131 0 3 -127z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -173,7 +173,6 @@
|
||||
</div>
|
||||
<div data-bind="foreach: statusInfo.servers">
|
||||
<div class="options-server-box">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-6">$T('swtag-server')</div>
|
||||
<div class="col-sm-6">
|
||||
@@ -650,7 +649,6 @@
|
||||
<button type="button" class="btn btn-danger" data-bind="click: history.emptyHistory" data-action="history-purgeremove-failed"><span class="glyphicon glyphicon-floppy-remove"></span> $T('purgeFailed-Files')</button><hr />
|
||||
<button type="button" class="btn btn-danger" data-bind="click: history.emptyHistory" data-action="history-purge-completed"><span class="glyphicon glyphicon-floppy-saved"></span> $T('purgeCompl')</button><hr />
|
||||
<button type="button" class="btn btn-danger" data-bind="click: history.emptyHistory" data-action="history-purge-page"><span class="glyphicon glyphicon-check"></span> $T('purgePage') <span class="label label-default" data-bind="text: history.historyItems().length"></span></button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -92,21 +92,21 @@
|
||||
</a>
|
||||
</td>
|
||||
<td class="name">
|
||||
<div class="row-wrap-text" data-bind="visible: !editingName()">
|
||||
<span data-bind="text: name, attr: { 'title': name() }"></span>
|
||||
<div class="row-wrap-text" data-bind="visible: !editingName(), css: { 'direct-unpack-text': direct_unpack }">
|
||||
<span data-bind="text: name, attr: { 'title': name_title }"></span>
|
||||
<!-- ko if: password() -->
|
||||
<small class="queue-item-password">
|
||||
<span class="glyphicon glyphicon-lock"></span>
|
||||
<span data-bind="text: password"></span>
|
||||
</small>
|
||||
<!-- /ko -->
|
||||
<div class="name-icons direct-unpack hover-button" data-bind="visible: direct_unpack" title="$T('opt-direct_unpack')">
|
||||
<span class="glyphicon glyphicon-compressed"></span> <span data-bind="text: direct_unpack"></span>
|
||||
</div>
|
||||
</div>
|
||||
<form data-bind="submit: editingNameSubmit">
|
||||
<input type="text" data-bind="value: nameForEdit, visible: editingName(), hasfocus: editingName" />
|
||||
</form>
|
||||
<div class="name-icons direct-unpack hover-button" data-bind="visible: direct_unpack">
|
||||
<span class="glyphicon glyphicon-compressed"></span> <span data-bind="text: direct_unpack"></span>
|
||||
</div>
|
||||
<div class="name-options" data-bind="visible: !editingName(), css: { disabled: isGrabbing() }">
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToTop" title="$T('Glitter-top')"><span class="glyphicon glyphicon-chevron-up"></span></a>
|
||||
<a href="#" data-bind="click: \$parent.queue.moveButton" class="hover-button buttonMoveToBottom" title="$T('Glitter-bottom')"><span class="glyphicon glyphicon-chevron-down"></span></a>
|
||||
@@ -133,8 +133,8 @@
|
||||
<label data-bind="visible: parent.isMultiEditing()">
|
||||
<input type="checkbox" name="multiedit" title="$T('Glitter-multiSelect')" data-bind="click: parent.addMultiEdit, attr: { 'id': 'multiedit_' + id } " />
|
||||
</label>
|
||||
<!-- ko if: !isGrabbing() -->
|
||||
<div class="dropdown" data-bind="visible: !isGrabbing() && !parent.isMultiEditing()">
|
||||
<!-- ko if: !isGrabbing() -->
|
||||
<div class="dropdown" data-bind="visible: !parent.isMultiEditing()">
|
||||
<a href="#" data-toggle="dropdown" data-bind="click: toggleDropdown">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
@@ -144,7 +144,7 @@
|
||||
<span class="glyphicon glyphicon-tag"></span>
|
||||
<select name="Category" class="form-control" data-bind="options: parent.categoriesList, optionsValue: 'catValue', optionsText: 'catText', value: category, event: { change: changeCat }"></select>
|
||||
</li>
|
||||
<!-- ko if: (status() != 'Fetching') -->
|
||||
<!-- ko if: !isFetchingBlocks -->
|
||||
<li title="$T('priority')" data-tooltip="true" data-placement="left">
|
||||
<span class="glyphicon glyphicon-sort-by-attributes-alt"></span>
|
||||
<select name="Priority" class="form-control" data-bind="options: parent.priorityOptions, optionsValue: 'value', optionsText: 'name', value: priority, event: { change: changePriority }"></select>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="./staticcfg/ico/apple-touch-icon-152x152-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./staticcfg/ico/apple-touch-icon-180x180-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./staticcfg/ico/android-192x192.png" />
|
||||
<link rel="mask-icon" href="./staticcfg/ico/safari-pinned-tab.svg" color="#383F45">
|
||||
<link rel="shortcut icon" type="image/ico" href="./staticcfg/ico/favicon.ico?v=$version" data-bind="attr: { 'href': SABIcon }" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./static/bootstrap/css/bootstrap.min.css?v=$version" />
|
||||
@@ -86,6 +87,7 @@
|
||||
glitterTranslate.moreText = "$T('Glitter-more')";
|
||||
|
||||
glitterTranslate.status = [];
|
||||
glitterTranslate.status['DirectUnpack'] = "$T('opt-direct_unpack')";
|
||||
glitterTranslate.status['Completed'] = "$T('post-Completed')";
|
||||
glitterTranslate.status['Failed'] = "$T('post-Failed')";
|
||||
glitterTranslate.status['Queued'] = "$T('post-Queued')";
|
||||
|
||||
@@ -134,7 +134,7 @@ function displayDateTime(inDate, outFormat, inFormat) {
|
||||
if(outFormat == 'fromNow') {
|
||||
return theMoment.fromNow()
|
||||
} else {
|
||||
return theMoment.format(outFormat)
|
||||
return theMoment.local().format(outFormat)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -785,15 +785,28 @@ function ViewModel() {
|
||||
}
|
||||
|
||||
// Update the servers
|
||||
if(self.statusInfo.servers().length == 0) {
|
||||
if(self.statusInfo.servers().length != data.status.servers.length) {
|
||||
// Only now we can subscribe to the log-level-changes! (only at start)
|
||||
if(self.statusInfo.servers().length == 0) {
|
||||
self.statusInfo.loglevel.subscribe(function(newValue) {
|
||||
// Update log-level
|
||||
callSpecialAPI('./status/change_loglevel/', {
|
||||
loglevel: newValue
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// Empty them, in case of update
|
||||
self.statusInfo.servers([])
|
||||
|
||||
// Initial add
|
||||
$.each(data.status.servers, function() {
|
||||
self.statusInfo.servers.push({
|
||||
'servername': this.servername,
|
||||
'serveroptional': this.serveroptional,
|
||||
'serverpriority': this.serverpriority,
|
||||
'servertotalconn': this.servertotalconn,
|
||||
'serverssl': this.serverssl,
|
||||
'servername': ko.observable(this.servername),
|
||||
'serveroptional': ko.observable(this.serveroptional),
|
||||
'serverpriority': ko.observable(this.serverpriority),
|
||||
'servertotalconn': ko.observable(this.servertotalconn),
|
||||
'serverssl': ko.observable(this.serverssl),
|
||||
'serversslinfo': ko.observable(this.serversslinfo),
|
||||
'serveractiveconn': ko.observable(this.serveractiveconn),
|
||||
'servererror': ko.observable(this.servererror),
|
||||
@@ -801,23 +814,20 @@ function ViewModel() {
|
||||
'serverconnections': ko.observableArray(this.serverconnections)
|
||||
})
|
||||
})
|
||||
|
||||
// Only now we can subscribe to the log-level-changes!
|
||||
self.statusInfo.loglevel.subscribe(function(newValue) {
|
||||
// Update log-level
|
||||
callSpecialAPI('./status/change_loglevel/', {
|
||||
loglevel: newValue
|
||||
});
|
||||
})
|
||||
} else {
|
||||
// Update
|
||||
$.each(data.status.servers, function(index) {
|
||||
var activeServer = self.statusInfo.servers()[index];
|
||||
activeServer.serveractiveconn(this.serveractiveconn)
|
||||
activeServer.servererror(this.servererror)
|
||||
activeServer.serveractive(this.serveractive)
|
||||
activeServer.servername(this.servername),
|
||||
activeServer.serveroptional(this.serveroptional),
|
||||
activeServer.serverpriority(this.serverpriority),
|
||||
activeServer.servertotalconn(this.servertotalconn),
|
||||
activeServer.serverssl(this.serverssl),
|
||||
activeServer.serversslinfo(this.serversslinfo),
|
||||
activeServer.serveractiveconn(this.serveractiveconn),
|
||||
activeServer.servererror(this.servererror),
|
||||
activeServer.serveractive(this.serveractive),
|
||||
activeServer.serverconnections(this.serverconnections)
|
||||
activeServer.serversslinfo(this.serversslinfo)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -479,6 +479,7 @@ function QueueModel(parent, data) {
|
||||
self.index = ko.observable(data.index);
|
||||
self.status = ko.observable(data.status);
|
||||
self.isGrabbing = ko.observable(data.status == 'Grabbing' || data.avg_age == '-')
|
||||
self.isFetchingBlocks = data.status == 'Fetching' || data.priority == 'Repair' // No need to update
|
||||
self.totalMB = ko.observable(parseFloat(data.mb));
|
||||
self.remainingMB = ko.observable(parseFloat(data.mbleft))
|
||||
self.missingMB = ko.observable(parseFloat(data.mbmissing))
|
||||
@@ -521,7 +522,14 @@ function QueueModel(parent, data) {
|
||||
})
|
||||
|
||||
// Texts
|
||||
self.missingText= ko.pureComputed(function() {
|
||||
self.name_title = ko.pureComputed(function() {
|
||||
// When hovering over the job
|
||||
if(self.direct_unpack()) {
|
||||
return self.name() + ' - ' + glitterTranslate.status['DirectUnpack'] + ': ' + self.direct_unpack()
|
||||
}
|
||||
return self.name()
|
||||
})
|
||||
self.missingText = ko.pureComputed(function() {
|
||||
// Check for missing data, the value is arbitrary! (1%)
|
||||
if(self.missingMB()/self.totalMB() > 0.01) {
|
||||
return self.missingMB().toFixed(0) + ' MB ' + glitterTranslate.misingArt
|
||||
@@ -692,7 +700,7 @@ function QueueModel(parent, data) {
|
||||
}
|
||||
self.changePriority = function(item, event) {
|
||||
// Not if we are fetching extra blocks for repair!
|
||||
if(item.status() == 'Fetching') return
|
||||
if(item.isFetchingBlocks) return
|
||||
callAPI({
|
||||
mode: 'queue',
|
||||
name: 'priority',
|
||||
|
||||
@@ -184,6 +184,7 @@ td.name .name-icons span,
|
||||
.navbar-nav .open .dropdown-menu>li>a,
|
||||
.dropdown-header,
|
||||
#modal-help small,
|
||||
.hover-button.glyphicon-forward,
|
||||
pre {
|
||||
color: #EBEBEB !important;
|
||||
opacity: 1 !important;
|
||||
|
||||
@@ -633,9 +633,17 @@ td.name .row-wrap-text {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.queue-table td.name .direct-unpack-text {
|
||||
max-width: calc(100% - 75px);
|
||||
}
|
||||
|
||||
.queue-table td.name:hover .row-wrap-text {
|
||||
max-width: calc(100% - 125px);
|
||||
/* Change for each size! */
|
||||
/* Change for each size! */
|
||||
}
|
||||
|
||||
.queue-table td.name:hover .direct-unpack {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.queue-table td.name:hover .name-options {
|
||||
@@ -1859,7 +1867,6 @@ input[name="nzbURL"] {
|
||||
td.name .name-icons {
|
||||
margin-left: 0px;
|
||||
margin-right: -5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
td.name .row-wrap-text {
|
||||
@@ -1887,7 +1894,6 @@ input[name="nzbURL"] {
|
||||
.history-queue-swicher .nav-tabs>li>a {
|
||||
border-bottom: inherit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
@@ -1899,7 +1905,6 @@ input[name="nzbURL"] {
|
||||
min-width: 715px;
|
||||
}
|
||||
|
||||
|
||||
.queue .sortable-placeholder td {
|
||||
padding: 9px 0px 8px !important;
|
||||
}
|
||||
|
||||
@@ -141,8 +141,12 @@ tr.queue-item>td:first-child>a {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.queue-table td.name .direct-unpack {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.queue-table td.name .name-options {
|
||||
display: block;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.queue-table td.name .name-options small {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="${path}staticcfg/ico/apple-touch-icon-152x152-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="${path}staticcfg/ico/apple-touch-icon-180x180-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="${path}staticcfg/ico/android-192x192.png" />
|
||||
<link rel="mask-icon" href="${path}staticcfg/ico/safari-pinned-tab.svg" color="#383F45">
|
||||
|
||||
<script type="text/javascript" src="${path}static/javascripts/lib.js?$version"></script>
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="./staticcfg/ico/apple-touch-icon-152x152-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="./staticcfg/ico/apple-touch-icon-180x180-precomposed.png" />
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./staticcfg/ico/android-192x192.png" />
|
||||
<link rel="mask-icon" href="./staticcfg/ico/safari-pinned-tab.svg" color="#383F45">
|
||||
|
||||
<script type="text/javascript" src="static/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="static/PlotKit/PlotKit.js"></script>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-2.3.0-develop\n"
|
||||
"Project-Id-Version: SABnzbd-2.4.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"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=ASCII\n"
|
||||
"Content-Transfer-Encoding: 7bit\n"
|
||||
"POT-Creation-Date: 2017-09-10 21:44+W. Europe Daylight Time\n"
|
||||
"POT-Creation-Date: 2017-10-21 16:01+W. Europe Daylight Time\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
@@ -372,10 +372,6 @@ msgstr ""
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr ""
|
||||
@@ -392,10 +388,6 @@ msgstr ""
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr ""
|
||||
@@ -447,10 +439,6 @@ msgstr ""
|
||||
msgid "Error removing %s"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/dirscanner.py [Error message]
|
||||
msgid "Error while adding %s, removing"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/dirscanner.py [Error message] # sabnzbd/dirscanner.py [Error message]
|
||||
msgid "Cannot read Watched Folder %s"
|
||||
msgstr ""
|
||||
@@ -680,6 +668,10 @@ msgstr ""
|
||||
msgid "Incorrect parameter"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid "Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
@@ -1059,7 +1051,7 @@ msgstr ""
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr ""
|
||||
|
||||
@@ -1396,7 +1388,7 @@ msgstr ""
|
||||
msgid "Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr ""
|
||||
|
||||
@@ -1416,6 +1408,10 @@ msgstr ""
|
||||
msgid "Completed Download Folder %s is on FAT file system, limiting maximum file size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid "Module subprocessww missing. Expect problems with Unicoded file and directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr ""
|
||||
@@ -3708,6 +3704,22 @@ msgstr ""
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr ""
|
||||
@@ -4108,6 +4120,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr ""
|
||||
@@ -4416,10 +4432,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2017-06-22 07:07+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-09-11 06:24+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:45+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -398,10 +398,6 @@ msgstr "Beskadigede historik database, skabte tom udskiftning"
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "SQL Kommando mislykkedes, se logg"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "SQL Commit mislykkedes, se logg"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Det lykkedes ikke at lukke databasen, se logg"
|
||||
@@ -418,10 +414,6 @@ msgstr "Afkodning af %s mislykkedes"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr "Dekoder fejl: Ikke mere hukommelse"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "CRC Fejl i %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Forkert udformet yEnc artikel i %s"
|
||||
@@ -739,6 +731,11 @@ msgstr "Udefineret server"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Fejl parameter"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Tilbage"
|
||||
@@ -1126,7 +1123,7 @@ msgstr "Kunne ikke sende Prowl besked"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Dårlig respons fra pushover (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Det lykkedes ikke at sende pushover besked"
|
||||
|
||||
@@ -1497,7 +1494,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Alvorlig fejl"
|
||||
|
||||
@@ -1519,6 +1516,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr "Overførslen kan mislykkes, kun %s af det krævede %s tilgængelig"
|
||||
@@ -3975,6 +3978,22 @@ msgstr "Enhed(er)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Enhed(er) som meddelelse skal sendes til"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4394,6 +4413,10 @@ msgstr "I tilfælde af SABnzbd genstart vil denne skærm forsvinde automatisk!"
|
||||
msgid "WARNING:"
|
||||
msgstr "ADVARSEL:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Hent"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Opdateringsfrekvens"
|
||||
@@ -4710,10 +4733,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Bloker genopfriskninger ved at hænge over"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Hent"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Upload"
|
||||
@@ -4978,6 +4997,12 @@ msgstr "URL hentning mislykkedes; %s"
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "Mappen \"%s\" findes ikke"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "SQL Commit mislykkedes, se logg"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "CRC Fejl i %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Error: No secondary interface defined."
|
||||
#~ msgstr "Fejl: Ingen sekundær bruger grænseflade defineret."
|
||||
|
||||
|
||||
@@ -7,19 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"PO-Revision-Date: 2017-08-24 15:39+0000\n"
|
||||
"Last-Translator: jcfp <Unknown>\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2017-10-10 19:03+0000\n"
|
||||
"Last-Translator: Robin Munkittrick <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-09-11 06:24+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "MultiPar binary... NOT found!"
|
||||
msgstr "MultiPar Programmdatei nicht gefunden!"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:45+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "MultiPar binary... NOT found!"
|
||||
@@ -420,10 +416,6 @@ msgstr "Verlaufsdatenbank geschädigt, eine leere neue wurde erstellt"
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "SQL-Befehl fehlgeschlagen. Beachten Sie das Nachrichtenprotokoll."
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "SQL-Commit fehlgeschlagen. Beachten Sie das Nachrichtenprotokoll."
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr ""
|
||||
@@ -441,10 +433,6 @@ msgstr "Fehler beim Dekodieren von %s."
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr "Decoder Fehler: Nicht genügend Speicher"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "CRC-Fehler in %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Ungültiger yEnc-Artikel in %s"
|
||||
@@ -767,6 +755,11 @@ msgstr "Undefinierter Server!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Fehlerhafter Parameter"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Zurück"
|
||||
@@ -1087,7 +1080,7 @@ msgstr "Überprüfen"
|
||||
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
|
||||
msgid "Checking extra files"
|
||||
msgstr ""
|
||||
msgstr "Überprüfe zusätzliche Dateien"
|
||||
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/newsunpack.py
|
||||
#: sabnzbd/newsunpack.py # sabnzbd/skintext.py [PP status]
|
||||
@@ -1096,7 +1089,7 @@ msgstr "Wird überprüft"
|
||||
|
||||
#: sabnzbd/newsunpack.py [Error message]
|
||||
msgid "Python script \"%s\" does not have execute (+x) permission set"
|
||||
msgstr "Dem Pythonskript \"%s\" fehlen die Ausführenrechte (+x)"
|
||||
msgstr "Dem Pythonskript \"%s\" fehlen die Ausführungsrechte (+x)"
|
||||
|
||||
#: sabnzbd/newswrapper.py
|
||||
msgid "This server does not allow SSL on this port"
|
||||
@@ -1168,7 +1161,7 @@ msgstr "Konnte Prowl-Nachricht nicht versenden"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Fehlerhafte Antwort von Pushbullet (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Konnte Pushover-Nachricht nicht versenden"
|
||||
|
||||
@@ -1553,7 +1546,7 @@ msgstr ""
|
||||
"Konnte nicht an Port %s auf %s starten. Eine andere Software nutzt diesen "
|
||||
"Port oder SABnzbd läuft bereits."
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Schwerwiegender Fehler"
|
||||
|
||||
@@ -1580,6 +1573,14 @@ msgstr ""
|
||||
"Download-Ordner %s für abgeschlossene Downloads auf FAT Dateisystem, ist "
|
||||
"auf maximale Dateigröße von 4GB begrenzt."
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
"Modul subprocessww fehlt. Fehler mit Unikodierter Datei und Verzeichnisnamen "
|
||||
"in den Downloads sind zu erwarten."
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr ""
|
||||
@@ -2808,6 +2809,8 @@ msgid ""
|
||||
"If the SABnzbd Host or Port is exposed to the internet, your current "
|
||||
"settings allow full external access to the SABnzbd interface."
|
||||
msgstr ""
|
||||
"Wenn der SABnzbd Host oder Port im Netz freigegeben ist, lassen die "
|
||||
"gegenwärtigen Einstellung vollen zugriff auf die SABnzbd Oberfläche zu."
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
msgid "Security"
|
||||
@@ -3880,7 +3883,7 @@ msgstr "Höchstens"
|
||||
|
||||
#: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Season/Episode"]
|
||||
msgid "From SxxEyy"
|
||||
msgstr "Von SxxExx"
|
||||
msgstr "Von SxxEyy"
|
||||
|
||||
#: sabnzbd/skintext.py [Config->RSS filter-type selection menu "From Show Season/Episode"]
|
||||
msgid "From Show SxxEyy"
|
||||
@@ -4084,6 +4087,22 @@ msgstr "Gerät(e)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Geräte, welche die Nachrichten empfangen sollen"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr "Wie oft die selbe benachrichtigung (in Sekunden) geschickt wird."
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4506,6 +4525,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "WARNUNG:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Abrufen"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Aktualisierungsrate"
|
||||
@@ -4822,10 +4845,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Aktualisierung durch Mauszeiger verhindern"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Abrufen"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Hochladen"
|
||||
@@ -5096,6 +5115,12 @@ msgstr "Abrufen der URL fehlgeschlagen; %s"
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "Ordner \"%s\" existiert nicht"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "SQL-Commit fehlgeschlagen. Beachten Sie das Nachrichtenprotokoll."
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "CRC-Fehler in %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Error: No secondary interface defined."
|
||||
#~ msgstr "Fehler: Keine sekundäre Oberfläche angegeben."
|
||||
|
||||
|
||||
@@ -117,3 +117,5 @@ msgstr "unrar binary... NOT found!"
|
||||
msgid "Downloads will not unpacked."
|
||||
msgstr "Downloads will not be unpacked."
|
||||
|
||||
msgid "Seperate multiple URLs by a comma"
|
||||
msgstr "Separate multiple URLs with a comma"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2017-06-22 07:07+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\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-09-11 06:25+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:46+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -399,10 +399,6 @@ msgstr ""
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "Comando SQL ha fallado, vea el registro"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "Compromiso SQL ha fallado, vea el registro"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "No se pudo cerrar el base de datos, vea el registro"
|
||||
@@ -419,10 +415,6 @@ msgstr "Descodificación %s fallo"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "Error CRC en %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Articulo yEnc corrupto en %s"
|
||||
@@ -741,6 +733,11 @@ msgstr "¡Servidor no definido!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Parámetro incorrecto"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Atrás"
|
||||
@@ -1134,7 +1131,7 @@ msgstr "No se pudo enviar el mensaje de Prowl"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Mala respuesta de Pushover (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "No se pudo enviar el mensaje de Pushover"
|
||||
|
||||
@@ -1513,7 +1510,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Error grave"
|
||||
|
||||
@@ -1536,6 +1533,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr "La descarga fallo, solo %s de los %s requeridos estan disponibles"
|
||||
@@ -4002,6 +4005,22 @@ msgstr "Dispositivo(s)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Dispositivo(s) a los que enviar el mensaje"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4418,6 +4437,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "AVISO:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Obtener"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Frecuencia de actualización"
|
||||
@@ -4735,10 +4758,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Bloquear actualizaciones al pasar por encima"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Obtener"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Subir"
|
||||
@@ -5017,9 +5036,15 @@ msgstr "Error al recuperar la URL; %s"
|
||||
#~ msgid "Try again"
|
||||
#~ msgstr "Inténtelo de nuevo"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "Compromiso SQL ha fallado, vea el registro"
|
||||
|
||||
#~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file"
|
||||
#~ msgstr "NOTICIA: Transferencia \"%s\" pausado por archivo cifrado"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "Error CRC en %s (%s -> %s)"
|
||||
|
||||
#~ msgid "No UNRAR program found, unpacking RAR files is not possible<br />"
|
||||
#~ msgstr ""
|
||||
#~ "Programa Unrar no encontrado, descomprimir de archivos RAR no posible<br />"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2017-06-22 07:07+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\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-09-11 06:24+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:45+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -398,10 +398,6 @@ msgstr ""
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "SQL komento epäonnistui, katso loki"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "SQL muutos epäonnistui, katso loki"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Tietokannan sulkeminen epäonnistui, katso loki"
|
||||
@@ -418,10 +414,6 @@ msgstr "Kohteen %s dekoodaus epäonnistui"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "CRC virhe tiedostossa %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Huonosti muotoiltu yEnc artikkeli %s"
|
||||
@@ -737,6 +729,11 @@ msgstr "Määrittämätön palvelin!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Virheellinen parametri"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Takaisin"
|
||||
@@ -1124,7 +1121,7 @@ msgstr "Prowl viestin lähetys epäonnistui"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Virheellinen vastaus Pushoverilta (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Pushover viestin lähetys epäonnistui"
|
||||
|
||||
@@ -1501,7 +1498,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Vakava virhe"
|
||||
|
||||
@@ -1523,6 +1520,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr "Lataaminen saattaa epäonnistua, vain %s osaa %s osasta saatavilla"
|
||||
@@ -3987,6 +3990,22 @@ msgstr "Laitteet"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Laitteet joihin viesti lähetetään"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4409,6 +4428,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "VAROITUS:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Nouda"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Päivitysväli"
|
||||
@@ -4725,10 +4748,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Estä päivitykset kun hiiri on päällä"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Nouda"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Lähetä"
|
||||
@@ -4991,6 +5010,9 @@ msgstr "NZB tiedostoa ei voida käyttää"
|
||||
msgid "URL Fetching failed; %s"
|
||||
msgstr "Osoitteen nouto epäonnistui; %s"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "CRC virhe tiedostossa %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "Kansiota \"%s\" ei ole olemassa"
|
||||
|
||||
@@ -5104,6 +5126,9 @@ msgstr "Osoitteen nouto epäonnistui; %s"
|
||||
#~ msgid "Remain/Total"
|
||||
#~ msgstr "Jäljellä/Yhteensä"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "SQL muutos epäonnistui, katso loki"
|
||||
|
||||
#~ msgid "No UNRAR program found, unpacking RAR files is not possible<br />"
|
||||
#~ msgstr ""
|
||||
#~ "UNRAR ohjelmaa ei löydy, RAR-tiedostojen purkaminen ei ole mahdollista<br />"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"PO-Revision-Date: 2017-09-12 18:26+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2017-10-05 18:52+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-09-13 05:28+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:45+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -419,10 +419,6 @@ msgstr ""
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "Echec de la commande SQL, voir le journal"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "Echec du commit SQL, voir le journal"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Impossible de fermer la base de données, voir le journal"
|
||||
@@ -439,10 +435,6 @@ msgstr "Échec du décodage de %s"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr "Échec du décodeur : mémoire insuffisante"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "Erreur CRC dans %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Article yEnc mal construit dans %s"
|
||||
@@ -767,6 +759,11 @@ msgstr "Serveur non défini !"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Paramètre incorrect"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Retour"
|
||||
@@ -1171,7 +1168,7 @@ msgstr "Echec d'envoi du message Prowl"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Mauvaise réponse de Pushover (%s) : %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Échec de l'envoi du message Pushover"
|
||||
|
||||
@@ -1554,7 +1551,7 @@ msgstr ""
|
||||
"Impossible de lier le port %s sur %s. Un autre logiciel utilise le port ou "
|
||||
"SABnzbd est déjà en cours d'exécution."
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Erreur fatale"
|
||||
|
||||
@@ -1579,6 +1576,14 @@ msgstr ""
|
||||
"Le système de fichiers du dossier de téléchargements terminés %s est au "
|
||||
"format FAT, limitant la taille maximale d'un fichier à 4 Go"
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
"Le module subprocessww est manquant. Attendez-vous à des problèmes avec les "
|
||||
"noms de fichiers et de répertoires Unicode dans les téléchargements."
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr ""
|
||||
@@ -4093,6 +4098,23 @@ msgstr "Appareil(s)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Appareil(s) auxquels doivent être envoyés les messages"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr "Nouvelle tentative d'urgence"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr "À quelle fréquence la même notification sera envoyée (en secondes)"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr "Expiration d'urgence"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
"Tenter à nouveau votre notification pendant combien de temps (en secondes)"
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4517,6 +4539,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "AVERTISSEMENT :"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Charger"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Taux de rafraîchissement"
|
||||
@@ -4835,10 +4861,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Bloquer rafraîchissements au survol"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Charger"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Envoyer"
|
||||
@@ -5104,6 +5126,9 @@ msgstr "Fichier NZB inutilisable"
|
||||
msgid "URL Fetching failed; %s"
|
||||
msgstr "Échec de récupération de l'URL ; %s"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "Erreur CRC dans %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Error: No secondary interface defined."
|
||||
#~ msgstr "Erreur : Pas d'interface secondaire définie."
|
||||
|
||||
@@ -5462,6 +5487,9 @@ msgstr "Échec de récupération de l'URL ; %s"
|
||||
#~ msgid "Show files"
|
||||
#~ msgstr "Afficher les fichiers"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "Echec du commit SQL, voir le journal"
|
||||
|
||||
#~ msgid "Downloaded so far"
|
||||
#~ msgstr "Téléchargé jusqu'à présent"
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"PO-Revision-Date: 2017-09-11 21:29+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2017-10-07 08:28+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-09-12 05:29+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:45+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -392,10 +392,6 @@ msgstr "מסד-נתונים היסטוריה פגום, נוצר תחליף רי
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "נכשלה, ראה יומן SQL פקודת"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "נכשל, ראה יומן SQL חיוב"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "נכשל בסגירת מסד-נתונים, ראה יומן"
|
||||
@@ -412,10 +408,6 @@ msgstr "נכשל %s פענוח"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr "כישלון מפענח: אין זיכרון"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "%s (%s -> %s)-ב CRC שגיאת"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "%s-נוצר באופן גרוע ב yEnc מאמר"
|
||||
@@ -444,7 +436,7 @@ msgstr "הושלם"
|
||||
|
||||
#: sabnzbd/directunpacker.py # sabnzbd/newsunpack.py
|
||||
msgid "Unpacked %s files/folders in %s"
|
||||
msgstr "%s-פורקו %s קבצים/תיקיות ב"
|
||||
msgstr "פורקו %s קבצים/תיקיות תוך %s"
|
||||
|
||||
#: sabnzbd/directunpacker.py [Warning message]
|
||||
msgid "Direct Unpack was automatically enabled."
|
||||
@@ -729,6 +721,11 @@ msgstr "!שרת בלתי מוגדר"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "משתנה לא נכון"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "הקודם"
|
||||
@@ -1119,7 +1116,7 @@ msgstr "Prowl נכשל בשליחת הודעת"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Pushover (%s): %s-תגובה רעה מ"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "pushover נכשל בשליחת הודעת"
|
||||
|
||||
@@ -1491,7 +1488,7 @@ msgstr ""
|
||||
".כבר רץ SABnzbd איזשהי תוכנה אחרת משתמשת בפתחה או %s לא היה ניתן לקשר את "
|
||||
"פתחה %s על"
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "שגיאה חמורה"
|
||||
|
||||
@@ -1515,6 +1512,13 @@ msgstr ""
|
||||
"המגבילה גודל מרבי של קובץ אל 4 ג\"ב ,FAT היא במערכת קבצים %s תיקיית ההורדות "
|
||||
"השלמות"
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
".של קבצים וספריות בהורדות Unicode חסר. צפה לבעיות עם שמות subprocessww פירקן"
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr "הורדה עשויה להיכשל, רק %s מתוך %s דרושים זמינים"
|
||||
@@ -2967,7 +2971,7 @@ msgid ""
|
||||
"<em>NOTE:</em> Folders will be created automatically when Saving. You may "
|
||||
"use absolute paths to save outside of the default folders."
|
||||
msgstr ""
|
||||
"<em>הערה:</em> .תיקיות יווצרו באופן אוטומטי בעת שמירה. אתה יכול להשתמש "
|
||||
"<em>הערה:</em> תיקיות יווצרו באופן אוטומטי בעת שמירה. אתה יכול להשתמש "
|
||||
"בנתיבים מוחלטים כדי לשמור מחוץ לתיקיות ברירת המחדל"
|
||||
|
||||
#: sabnzbd/skintext.py
|
||||
@@ -3951,6 +3955,22 @@ msgstr "התקן(ים)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "התקנים אליהם הודעה תישלח"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr "ניסיון חוזר חרום"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr "באיזו תדירות (בשניות) אותה ההתראה תישלח"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr "תפוגת חרום"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr "כמה שניות ההתראה שלך תמשיך להיות מנוסה שוב"
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4368,6 +4388,10 @@ msgstr "!המסך יעלם באופן אוטומטי SABnzbd במקרה של ה
|
||||
msgid "WARNING:"
|
||||
msgstr "אזהרה:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "משוך"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "קצב רענון"
|
||||
@@ -4682,10 +4706,6 @@ msgstr "זה ימנע רענון תוכן כשסמן העכבר שלך מרחף
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "חסום רענונים בריחוף"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "משוך"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "העלה"
|
||||
@@ -4991,5 +5011,11 @@ msgstr "%s ;משיכת כתובת נכשלה"
|
||||
#~ msgid "Invalid par2 files, cannot verify or repair"
|
||||
#~ msgstr "בלתי תקפים, לא יכול לוודא או לתקן par2 קבצי"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "%s (%s -> %s)-ב CRC שגיאת"
|
||||
|
||||
#~ msgid "It is likely that you are using ZoneAlarm on Vista.<br>"
|
||||
#~ msgstr ".Vista על ZoneAlarm-סביר להניח שאתה משתמש ב<br>"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "נכשל, ראה יומן SQL חיוב"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2017-09-03 14:07+0000\n"
|
||||
"Last-Translator: Steffen Bærø <steffen.baro@gmail.com>\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-09-11 06:25+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:46+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -394,10 +394,6 @@ msgstr "Skadet historikkdatabase, opprettet ny database"
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "SQL-kommando mislyktes, se logg"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "SQL Innsetting mislyktes, se logg"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Kunne ikke stenge databasen, se logg"
|
||||
@@ -414,10 +410,6 @@ msgstr "Dekoding av %s mislyktes"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "CRC-feil i %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Feilaktigt utformet yEnc artikkel i %s"
|
||||
@@ -733,6 +725,11 @@ msgstr "Udefinert server!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Feil parameter"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Tilbake"
|
||||
@@ -1120,7 +1117,7 @@ msgstr "Klarte ikke å sende Prowl melding"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Ukorrekt svar fra Pushover (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Klarte ikke å sende pushover-melding"
|
||||
|
||||
@@ -1493,7 +1490,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Kritisk feil"
|
||||
|
||||
@@ -1515,6 +1512,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr "Nedlasting kan feile, kun %s av kravet på %s tilgjengelig"
|
||||
@@ -3947,6 +3950,22 @@ msgstr "Enhet(er)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Enhet(er) som meldingen skal sendes til"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4364,6 +4383,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "ADVARSEL:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Hent"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Oppdateringsfrekvens"
|
||||
@@ -4676,10 +4699,6 @@ msgstr "Dette vil hindre oppfrisking av innhold når muspekeren er over køen"
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Blokker oppfrisking når musen svever over"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Hent"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Last Opp"
|
||||
@@ -4946,6 +4965,9 @@ msgstr "URL henting mislyktes; %s"
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "Mappen \"%s\" finnes ikke"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "SQL Innsetting mislyktes, se logg"
|
||||
|
||||
#~ msgid "No UNRAR program found, unpacking RAR files is not possible<br />"
|
||||
#~ msgstr "Kunne ikke finne noen UNRAR program, utpakking er ikke mulig<br />"
|
||||
|
||||
@@ -5322,6 +5344,9 @@ msgstr "URL henting mislyktes; %s"
|
||||
#~ msgid "WARNING: Paused job \"%s\" because of encrypted RAR file"
|
||||
#~ msgstr "ADVARSEL: Jobb \"%s\" satt på pause pga. kryptert RAR-fil"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "CRC-feil i %s (%s -> %s)"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Your UNRAR version is not recommended, get it from "
|
||||
#~ "http://www.rarlab.com/rar_add.htm<br />"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"PO-Revision-Date: 2017-09-11 07:07+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2017-10-20 09:43+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-09-12 05:29+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:45+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -412,10 +412,6 @@ msgstr ""
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "SQL-commando mislukt, zie logbestand"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "SQL-opslagopdracht mislukt, zie logbestand"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Het lukt niet om de database te sluiten, zie log"
|
||||
@@ -432,10 +428,6 @@ msgstr "Decoderen van %s mislukt"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr "Decoder fout: onvoldoende geheugen"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "CRC-fout in %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Slecht opgemaakt yEnc-artikel in %s"
|
||||
@@ -756,6 +748,11 @@ msgstr "Onbekende server."
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Incorrecte parameter"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Terug"
|
||||
@@ -1150,7 +1147,7 @@ msgstr "Verzenden van Prowl-bericht mislukt"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Slecht antwoord van Pushover (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Pushover-bericht sturen mislukt"
|
||||
|
||||
@@ -1525,7 +1522,7 @@ msgstr ""
|
||||
"Kan niet binden aan poort %s van %s. Andere software gebruikt deze poort of "
|
||||
"SABnzbd is al actief."
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Fatale fout"
|
||||
|
||||
@@ -1549,6 +1546,14 @@ msgstr ""
|
||||
"De map voor voltooide downloads %s staat op een FAT systeem, de maximale "
|
||||
"file omvang is dan maar 4G"
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
"De module subprocessww ontbreekt. Je kunt problemen krijgen met Unicode "
|
||||
"namen van bestanden en mappen."
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr ""
|
||||
@@ -4040,6 +4045,22 @@ msgstr "Apparaten"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Apparaat of apparaten die het bericht moeten ontvangen"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr "Noodgeval herhaling"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr "Hoevaak moet de notification herhaald worden (in seconden)"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr "Einde van noodgeval"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr "Hoeveel seconden moet de notificatie herhaald worden"
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4461,6 +4482,10 @@ msgstr "Wanneer SABnzbd opnieuw is gestart, gaat dit venster vanzelf weg!"
|
||||
msgid "WARNING:"
|
||||
msgstr "WAARSCHUWING:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Ophalen"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Ververssnelheid"
|
||||
@@ -4776,10 +4801,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Geen verversing bij popups"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Ophalen"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Ophalen"
|
||||
@@ -5571,6 +5592,12 @@ msgstr "URL ophalen mislukt; %s"
|
||||
#~ msgstr ""
|
||||
#~ "WAARSCHUWING: Taak '%s' is afgebroken vanwege een versleuteld RAR-bestand"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "CRC-fout in %s (%s -> %s)"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "SQL-opslagopdracht mislukt, zie logbestand"
|
||||
|
||||
#~ msgid "No UNRAR program found, unpacking RAR files is not possible<br />"
|
||||
#~ msgstr ""
|
||||
#~ "Geen UNRAR-programma gevonden, uitpakken van RAR-bestanden niet mogelijk<br "
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2015-12-28 10:22+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.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-09-11 06:25+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:46+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -394,10 +394,6 @@ msgstr "Uszkodzona baza danych historii, utworzono w jej miejscu nową, pustą"
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "Błąd polecenia SQL, sprawdź logi"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "Błąd wykonania polecenia SQL, sprawdź logi"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Błąd zamykania bazy danych, sprawdź logi"
|
||||
@@ -414,10 +410,6 @@ msgstr "Błąd dekodowania %s"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "Błąd CRC w %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Źle zbudowany artykuł yEnc w %s"
|
||||
@@ -736,6 +728,11 @@ msgstr "Niezdefiniowany serwer!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Błędny parametr"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Powrót"
|
||||
@@ -1125,7 +1122,7 @@ msgstr "Błąd wysyłania wiadomości Prowl"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Zła odpowiedź od Pushover (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Nie udało się wysłać wiadomości Pushover"
|
||||
|
||||
@@ -1499,7 +1496,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Błąd krytyczny"
|
||||
|
||||
@@ -1522,6 +1519,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr "Pobieranie może się nie udać, dostępne jedynie %s z wymaganych %s"
|
||||
@@ -3965,6 +3968,22 @@ msgstr "Urządzenie(-a)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Urządzenie(-a), do którego(-ych) mają być wysyłane powiadomienia"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4382,6 +4401,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "UWAGA:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Pobierz"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Częstotliwość odświeżania"
|
||||
@@ -4694,10 +4717,6 @@ msgstr "Blokuje odświeżanie zawartości po najechaniu kursorem na kolejkę"
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Zablokuj odświeżanie podczas wskazywania"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Pobierz"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Wczytaj"
|
||||
@@ -4959,6 +4978,9 @@ msgstr "Bezużyteczny plik NZB"
|
||||
msgid "URL Fetching failed; %s"
|
||||
msgstr "Pobieranie URL nie powiodło się; %s"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "Błąd CRC w %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "Folder \"%s\" nie istnieje"
|
||||
|
||||
@@ -4975,6 +4997,9 @@ msgstr "Pobieranie URL nie powiodło się; %s"
|
||||
#~ msgid "Downloaded so far"
|
||||
#~ msgstr "Dotychczas pobrano"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "Błąd wykonania polecenia SQL, sprawdź logi"
|
||||
|
||||
#~ msgid "Not matched"
|
||||
#~ msgstr "Nie dopasowano"
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2016-01-01 22:58+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-09-11 06:25+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:46+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -396,10 +396,6 @@ msgstr "Dados de histórico danificados, criado um substituto vazio"
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "O comando SQL falhou. Consulte o log"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "O commit do SQL falhou. Consulte o log"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Falha ao fechar o banco de dados. Consulte o log"
|
||||
@@ -416,10 +412,6 @@ msgstr "Falha ao decodificar %s"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "Erro de CRC em %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Artigo yEnc mal formado em %s"
|
||||
@@ -736,6 +728,11 @@ msgstr "Servidor não definido!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Parâmetro incorreto"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Voltar"
|
||||
@@ -1122,7 +1119,7 @@ msgstr "Falha ao enviar mensagem Prowl"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Resposta incorreta do Pushover (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Falha ao enviar mensagem pushover"
|
||||
|
||||
@@ -1498,7 +1495,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Erro fatal"
|
||||
|
||||
@@ -1520,6 +1517,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr ""
|
||||
@@ -3963,6 +3966,22 @@ msgstr "Dispositivo(s)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Dispositivo(s) para qual a mensagem deve ser enviada"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4380,6 +4399,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "AVISO:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Obter"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Taxa de atualização"
|
||||
@@ -4694,10 +4717,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Impedir Atualizações no Foco"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Obter"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Enviar"
|
||||
@@ -4964,9 +4983,15 @@ msgstr "A busca da URL falhou; %s"
|
||||
#~ msgstr ""
|
||||
#~ "ATENÇÃO: Tarefa \"%s\" em pausa por causa de arquivo RAR criptografado"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "Erro de CRC em %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "A pasta \"%s\" não existe"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "O commit do SQL falhou. Consulte o log"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Your UNRAR version is not recommended, get it from "
|
||||
#~ "http://www.rarlab.com/rar_add.htm<br />"
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2016-07-29 16:20+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-09-11 06:25+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:46+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -398,10 +398,6 @@ msgstr "Bază de date Istoric coruptă, creat un nou fişier gol"
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "Comandă SQL Nereuşită, vedeţi jurnal"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "Modificare SQL Nereuşită, vedeţi jurnal"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Închidere bază de date nereuşită, vedeţi jurnal"
|
||||
@@ -418,10 +414,6 @@ msgstr "Decodarea %s nereuşită"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "Eroare CRC în %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Articoul yEnc invalid în %s"
|
||||
@@ -739,6 +731,11 @@ msgstr "Server nedefinit!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Parametru Incorect"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Înapoi"
|
||||
@@ -1126,7 +1123,7 @@ msgstr "Nu am putu trimite mesajul Prowl"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Răspuns greșit de la Pushover (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Nu am putut trimite mesajul de pushover"
|
||||
|
||||
@@ -1505,7 +1502,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Eroare fatală"
|
||||
|
||||
@@ -1527,6 +1524,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr "Descărcarea ar putea eşua, doar %s din %s disponibil"
|
||||
@@ -3968,6 +3971,22 @@ msgstr "Dispozitiv(e)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Dispozitiv(e) la care să se trimită mesajul"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4383,6 +4402,10 @@ msgstr "În cazul repornirii SABnzbd acest ecran va dispărea în mod automat!"
|
||||
msgid "WARNING:"
|
||||
msgstr "ATENŢIE:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Descarcă"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Rată actualizare"
|
||||
@@ -4699,10 +4722,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Blochează Reîmprospătarea Hover"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Descarcă"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Încarcă"
|
||||
@@ -4969,9 +4988,15 @@ msgstr "Descărcare URL nereuşită; %s"
|
||||
#~ msgstr ""
|
||||
#~ "ATENŢIE: Sarcina \"%s\" întreruptă din cauza fişierelor RAR encriptate"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "Eroare CRC în %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "Dosarul \"%s\" nu există"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "Modificare SQL Nereuşită, vedeţi jurnal"
|
||||
|
||||
#~ msgid "No UNRAR program found, unpacking RAR files is not possible<br />"
|
||||
#~ msgstr ""
|
||||
#~ "Nici un program UNRAR găsit, dezarhivarea fişierelor RAR imposibilă<br />"
|
||||
|
||||
@@ -2,15 +2,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: SABnzbd-0.7.x\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2013-05-05 14:50+0000\n"
|
||||
"Last-Translator: Pavel Maryanov <Unknown>\n"
|
||||
"Language-Team: Russian <gmu@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-09-11 06:25+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:46+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
@@ -387,10 +387,6 @@ msgstr ""
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "Ошибка команды SQL (см. журнал)"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "Ошибка фиксации SQL (см. журнал)"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Не удалось закрыть базу данных (см. журнал)"
|
||||
@@ -407,10 +403,6 @@ msgstr "Ошибка декодирования %s"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "Ошибка CRC в %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Неверно сформированная статья yEnc в %s"
|
||||
@@ -726,6 +718,11 @@ msgstr ""
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Неправильный параметр"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Назад"
|
||||
@@ -1114,7 +1111,7 @@ msgstr ""
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr ""
|
||||
|
||||
@@ -1491,7 +1488,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Критическая ошибка"
|
||||
|
||||
@@ -1513,6 +1510,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr ""
|
||||
@@ -3946,6 +3949,22 @@ msgstr ""
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr ""
|
||||
@@ -4361,6 +4380,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "ПРЕДУПРЕЖДЕНИЕ"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Загрузить"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Частота обновления"
|
||||
@@ -4675,10 +4698,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Блокировать обновление при наведении мыши"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Загрузить"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Отправить"
|
||||
@@ -4950,6 +4969,12 @@ msgstr "Не удалось загрузить URL: %s"
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "Папка «%s» не существует"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "Ошибка фиксации SQL (см. журнал)"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "Ошибка CRC в %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Error: No secondary interface defined."
|
||||
#~ msgstr "Ошибка: дополнительный интерфейс не определён."
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: ОZZII <ozzii.translate@gmail.com>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2015-12-28 10:25+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\n"
|
||||
"Language-Team: Serbian <sr@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-09-11 06:25+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:46+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -391,10 +391,6 @@ msgstr "Baza dnevnika je oštećena, kreirana prazna zamena"
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "Neuspešna SQL komanda, videti izveštaj"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "Погрешно SQL извршавање, видети извештај"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Неуспешно затварање базе, видети извештај"
|
||||
@@ -411,10 +407,6 @@ msgstr "Dešifrovanje %s neuspešno"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "CRC грешка у %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Лоше формиран yEnc артикал у %s"
|
||||
@@ -728,6 +720,11 @@ msgstr "Server nije definisan!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Погрешан параметар"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Назад"
|
||||
@@ -1115,7 +1112,7 @@ msgstr "Неуспешно слање Prowl поруке"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Neodgovarajući odgovor od strane Pushover (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Neuspešno slanje Pushover poruke"
|
||||
|
||||
@@ -1485,7 +1482,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Фатална грешка"
|
||||
|
||||
@@ -1507,6 +1504,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr "Преузимање је можда погрешно. има %s од потребних %s"
|
||||
@@ -3932,6 +3935,22 @@ msgstr "Uređaj(i)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Uređaj(i) na koje bi poruke trebale biti poslate"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4348,6 +4367,10 @@ msgstr ""
|
||||
msgid "WARNING:"
|
||||
msgstr "ПАЖЊА:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Преузми"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Брзина освежавања"
|
||||
@@ -4660,10 +4683,6 @@ msgstr "При прелазу миша преко рада, зауставља
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Блокирати обнове на прелаз миша"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Преузми"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Слање"
|
||||
@@ -5198,6 +5217,12 @@ msgstr "Погрешно учитавање УРЛ-а; %s"
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "фасцикла \"%s\" не постоји"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "Погрешно SQL извршавање, видети извештај"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "CRC грешка у %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Not matched"
|
||||
#~ msgstr "Не одговара"
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2016-02-20 20:34+0000\n"
|
||||
"Last-Translator: shypike <Unknown>\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-09-11 06:25+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:46+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -392,10 +392,6 @@ msgstr "Skadad hitsotrikdatabas, skapade en tom ersättare"
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "SQL Kommando misslyckades, se logg"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "SQL Commit misslyckades, se logg"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "Det gick inte att stänga databasen, se logg"
|
||||
@@ -412,10 +408,6 @@ msgstr "Avkodning av %s misslyckades"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "CRC Fel i %s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "Felaktigt utformad yEnc artikel i %s"
|
||||
@@ -732,6 +724,11 @@ msgstr "Odefinerad server!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "Fel parameter"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "Bakåt"
|
||||
@@ -1120,7 +1117,7 @@ msgstr "Misslyckades att skicka Prowlmeddelande"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Dålig respons från Pushover (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "Misslyckades att skicka pushovermeddelande"
|
||||
|
||||
@@ -1495,7 +1492,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "Allvarligt fel"
|
||||
|
||||
@@ -1517,6 +1514,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr ""
|
||||
@@ -3947,6 +3950,22 @@ msgstr "Enhet(er)"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "Enhet(er) där medellandet skall skickas"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4362,6 +4381,10 @@ msgstr "Om SABnzbd startar om kommer denna skärm att försvinna automatiskt!"
|
||||
msgid "WARNING:"
|
||||
msgstr "VARNING:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Hämta"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "Uppdateringsfrekvens"
|
||||
@@ -4676,10 +4699,6 @@ msgstr ""
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "Block uppdaterar vid svävande"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "Hämta"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "Ladda upp"
|
||||
@@ -4947,6 +4966,12 @@ msgstr "URL hämtning misslyckades; %s"
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "Mappen \"%s\" finns inte"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "SQL Commit misslyckades, se logg"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "CRC Fel i %s (%s -> %s)"
|
||||
|
||||
#~ msgid "Error: No secondary interface defined."
|
||||
#~ msgstr "Fel: Inget andrainterface definierat."
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: sabnzbd\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2017-09-10 20:30+0000\n"
|
||||
"POT-Creation-Date: 2017-10-25 23:30+0000\n"
|
||||
"PO-Revision-Date: 2017-06-22 07:06+0000\n"
|
||||
"Last-Translator: Safihre <safihre@sabnzbd.org>\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-09-11 06:25+0000\n"
|
||||
"X-Generator: Launchpad (build 18449)\n"
|
||||
"X-Launchpad-Export-Date: 2017-10-26 05:47+0000\n"
|
||||
"X-Generator: Launchpad (build 18484)\n"
|
||||
|
||||
#: SABnzbd.py [Error message]
|
||||
msgid "Failed to start web-interface"
|
||||
@@ -386,10 +386,6 @@ msgstr "“历史记录”数据库已损坏,已创建空数据库代替"
|
||||
msgid "SQL Command Failed, see log"
|
||||
msgstr "SQL 命令执行失败,参见日志"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "SQL Commit Failed, see log"
|
||||
msgstr "SQL 保存失败,参见日志"
|
||||
|
||||
#: sabnzbd/database.py [Error message]
|
||||
msgid "Failed to close database, see log"
|
||||
msgstr "无法关闭数据库,参见日志"
|
||||
@@ -406,10 +402,6 @@ msgstr "%s 解码失败"
|
||||
msgid "Decoder failure: Out of memory"
|
||||
msgstr "解码器失败:内存不足"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "CRC Error in %s (%s -> %s)"
|
||||
msgstr "CRC 错误:%s (%s -> %s)"
|
||||
|
||||
#: sabnzbd/decoder.py
|
||||
msgid "Badly formed yEnc article in %s"
|
||||
msgstr "yEnc 文章格式错误:%s"
|
||||
@@ -715,6 +707,11 @@ msgstr "未定义服务器!"
|
||||
msgid "Incorrect parameter"
|
||||
msgstr "参数不正确"
|
||||
|
||||
#: sabnzbd/interface.py
|
||||
msgid ""
|
||||
"Category folder cannot be a subfolder of the Temporary Download Folder."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/interface.py # sabnzbd/interface.py
|
||||
msgid "Back"
|
||||
msgstr "返回"
|
||||
@@ -1100,7 +1097,7 @@ msgstr "无法发送 Prowl 消息"
|
||||
msgid "Bad response from Pushover (%s): %s"
|
||||
msgstr "Pushover 响应异常 (%s): %s"
|
||||
|
||||
#: sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
#: sabnzbd/notifier.py # sabnzbd/notifier.py [Warning message] # sabnzbd/notifier.py
|
||||
msgid "Failed to send pushover message"
|
||||
msgstr "无法发送 pushover 信息"
|
||||
|
||||
@@ -1469,7 +1466,7 @@ msgid ""
|
||||
"SABnzbd is already running."
|
||||
msgstr "绑定端口 %s 在 %s 上失败。其它的程序正在使用此端口或者说 SABnzbd 正在运行。"
|
||||
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py
|
||||
#: sabnzbd/panic.py # sabnzbd/panic.py # sabnzbd/panic.py
|
||||
msgid "Fatal error"
|
||||
msgstr "致命错误"
|
||||
|
||||
@@ -1491,6 +1488,12 @@ msgid ""
|
||||
"size to 4GB"
|
||||
msgstr "已完成文件夹 %s 位于 FAT 文件系统上,这样会有最大文件为 4GB 的限制。"
|
||||
|
||||
#: sabnzbd/postproc.py [Warning message]
|
||||
msgid ""
|
||||
"Module subprocessww missing. Expect problems with Unicoded file and "
|
||||
"directory names in downloads."
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/postproc.py
|
||||
msgid "Download might fail, only %s of required %s available"
|
||||
msgstr "下载可能会失败,只有 %s 块 (需要 %s) 可用"
|
||||
@@ -3874,6 +3877,22 @@ msgstr "设备"
|
||||
msgid "Device(s) to which message should be sent"
|
||||
msgstr "信息发送的目标设备"
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency retry"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How often (in seconds) the same notification will be sent"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "Emergency expire"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Pushover settings]
|
||||
msgid "How many seconds your notification will continue to be retried"
|
||||
msgstr ""
|
||||
|
||||
#: sabnzbd/skintext.py [Header for Pushbullet notification section]
|
||||
msgid "Pushbullet"
|
||||
msgstr "Pushbullet"
|
||||
@@ -4288,6 +4307,10 @@ msgstr "SABnzbd 重启后本画面将自动消失!"
|
||||
msgid "WARNING:"
|
||||
msgstr "警告:"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "装取"
|
||||
|
||||
#: sabnzbd/skintext.py # sabnzbd/skintext.py
|
||||
msgid "Refresh rate"
|
||||
msgstr "刷新频率"
|
||||
@@ -4600,10 +4623,6 @@ msgstr "这将在您的鼠标指针处于队列上方时阻止内容刷新。"
|
||||
msgid "Block Refreshes on Hover"
|
||||
msgstr "指向时停止刷新"
|
||||
|
||||
#: sabnzbd/skintext.py [Fetch from URL button in "Add NZB" dialog box]
|
||||
msgid "Fetch"
|
||||
msgstr "装取"
|
||||
|
||||
#: sabnzbd/skintext.py [Upload button in "Add NZB" dialog box]
|
||||
msgid "Upload"
|
||||
msgstr "上传"
|
||||
@@ -4865,6 +4884,12 @@ msgstr "URL 装取失败; %s"
|
||||
#~ msgid "Folder \"%s\" does not exist"
|
||||
#~ msgstr "文件夹 \"%s\" 不存在"
|
||||
|
||||
#~ msgid "SQL Commit Failed, see log"
|
||||
#~ msgstr "SQL 保存失败,参见日志"
|
||||
|
||||
#~ msgid "CRC Error in %s (%s -> %s)"
|
||||
#~ msgstr "CRC 错误:%s (%s -> %s)"
|
||||
|
||||
#~ msgid "Error: No secondary interface defined."
|
||||
#~ msgstr "错误: 未定义第二界面。"
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ import sabnzbd.lang as lang
|
||||
import sabnzbd.par2file as par2file
|
||||
import sabnzbd.api
|
||||
import sabnzbd.directunpacker as directunpacker
|
||||
from sabnzbd.decorators import synchronized, notify_downloader
|
||||
from sabnzbd.decorators import synchronized
|
||||
from sabnzbd.constants import NORMAL_PRIORITY, VALID_ARCHIVES, \
|
||||
REPAIR_REQUEST, QUEUE_FILE_NAME, QUEUE_VERSION, QUEUE_FILE_TMPL
|
||||
import sabnzbd.getipaddress as getipaddress
|
||||
@@ -874,7 +874,7 @@ def get_new_id(prefix, folder, check_list=None):
|
||||
def save_data(data, _id, path, do_pickle=True, silent=False):
|
||||
""" Save data to a diskfile """
|
||||
if not silent:
|
||||
logging.debug("Saving data for %s in %s", _id, path)
|
||||
logging.debug('[%s] Saving data for %s in %s', misc.caller_name(), _id, path)
|
||||
path = os.path.join(path, _id)
|
||||
|
||||
# We try 3 times, to avoid any dict or access problems
|
||||
@@ -906,11 +906,11 @@ def load_data(_id, path, remove=True, do_pickle=True, silent=False):
|
||||
path = os.path.join(path, _id)
|
||||
|
||||
if not os.path.exists(path):
|
||||
logging.info("%s missing", path)
|
||||
logging.info("[%s] %s missing", misc.caller_name(), path)
|
||||
return None
|
||||
|
||||
if not silent:
|
||||
logging.debug("Loading data for %s from %s", _id, path)
|
||||
logging.debug("[%s] Loading data for %s from %s", misc.caller_name(), _id, path)
|
||||
|
||||
try:
|
||||
with open(path, 'rb') as data_file:
|
||||
@@ -923,7 +923,7 @@ def load_data(_id, path, remove=True, do_pickle=True, silent=False):
|
||||
data = data_file.read()
|
||||
|
||||
if remove:
|
||||
os.remove(path)
|
||||
misc.remove_file(path)
|
||||
except:
|
||||
logging.error(T('Loading %s failed'), path)
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
@@ -937,8 +937,7 @@ def remove_data(_id, path):
|
||||
path = os.path.join(path, _id)
|
||||
try:
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
logging.info("%s removed", path)
|
||||
misc.remove_file(path)
|
||||
except:
|
||||
logging.debug("Failed to remove %s", path)
|
||||
|
||||
@@ -946,7 +945,7 @@ def remove_data(_id, path):
|
||||
def save_admin(data, _id):
|
||||
""" Save data in admin folder in specified format """
|
||||
path = os.path.join(cfg.admin_dir.get_path(), _id)
|
||||
logging.info("Saving data for %s in %s", _id, path)
|
||||
logging.debug("[%s] Saving data for %s in %s", misc.caller_name(), _id, path)
|
||||
|
||||
# We try 3 times, to avoid any dict or access problems
|
||||
for t in xrange(3):
|
||||
@@ -969,10 +968,10 @@ def save_admin(data, _id):
|
||||
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)
|
||||
logging.info("Loading data for %s from %s", _id, path)
|
||||
logging.debug("[%s] Loading data for %s from %s", misc.caller_name(), _id, path)
|
||||
|
||||
if not os.path.exists(path):
|
||||
logging.info("%s missing", path)
|
||||
logging.info("[%s] %s missing", misc.caller_name(), path)
|
||||
return None
|
||||
|
||||
try:
|
||||
@@ -982,7 +981,7 @@ def load_admin(_id, remove=False, silent=False):
|
||||
else:
|
||||
data = cPickle.load(data_file)
|
||||
if remove:
|
||||
os.remove(path)
|
||||
misc.remove_file(path)
|
||||
except:
|
||||
if not silent:
|
||||
excepterror = str(sys.exc_info()[0])
|
||||
@@ -1036,7 +1035,7 @@ def check_repair_request():
|
||||
path = os.path.join(cfg.admin_dir.get_path(), REPAIR_REQUEST)
|
||||
if os.path.exists(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
misc.remove_file(path)
|
||||
except:
|
||||
pass
|
||||
return True
|
||||
@@ -1107,7 +1106,7 @@ def pid_file(pid_path=None, pid_file=None, port=0):
|
||||
f.write('%d\n' % os.getpid())
|
||||
f.close()
|
||||
else:
|
||||
os.remove(DIR_PID)
|
||||
misc.remove_file(DIR_PID)
|
||||
except:
|
||||
logging.warning('Cannot access PID file %s', DIR_PID)
|
||||
|
||||
|
||||
@@ -1358,7 +1358,7 @@ def build_queue(start=0, limit=0, trans=False, output=None, search=None):
|
||||
slot['status'] = "%s" % (status)
|
||||
|
||||
if (Downloader.do.paused or Downloader.do.postproc or is_propagating or \
|
||||
status not in (Status.DOWNLOADING, Status.QUEUED)) and priority != TOP_PRIORITY:
|
||||
status not in (Status.DOWNLOADING, Status.FETCHING, Status.QUEUED)) and priority != TOP_PRIORITY:
|
||||
slot['timeleft'] = '0:00:00'
|
||||
slot['eta'] = 'unknown'
|
||||
else:
|
||||
|
||||
@@ -22,6 +22,7 @@ sabnzbd.articlecache - Article cache handling
|
||||
import sys
|
||||
import logging
|
||||
import threading
|
||||
import struct
|
||||
|
||||
import sabnzbd
|
||||
from sabnzbd.decorators import synchronized
|
||||
@@ -40,6 +41,13 @@ class ArticleCache(object):
|
||||
self.__cache_size = 0
|
||||
self.__article_list = [] # List of buffered articles
|
||||
self.__article_table = {} # Dict of buffered articles
|
||||
|
||||
# On 32 bit we only allow the user to set 1GB
|
||||
# For 64 bit we allow up to 4GB, in case somebody wants that
|
||||
self.__cache_upper_limit = GIGI
|
||||
if sabnzbd.DARWIN or sabnzbd.WIN64 or (struct.calcsize("P") * 8) == 64:
|
||||
self.__cache_upper_limit = 4*GIGI
|
||||
|
||||
ArticleCache.do = self
|
||||
|
||||
@synchronized(ARTICLE_LOCK)
|
||||
@@ -51,9 +59,9 @@ class ArticleCache(object):
|
||||
""" Called when cache limit changes """
|
||||
self.__cache_limit_org = limit
|
||||
if limit < 0:
|
||||
self.__cache_limit = GIGI
|
||||
self.__cache_limit = self.__cache_upper_limit
|
||||
else:
|
||||
self.__cache_limit = min(limit, GIGI)
|
||||
self.__cache_limit = min(limit, self.__cache_upper_limit)
|
||||
|
||||
@synchronized(ARTICLE_LOCK)
|
||||
def reserve_space(self, data):
|
||||
|
||||
@@ -38,7 +38,7 @@ from sabnzbd.postproc import PostProcessor
|
||||
import sabnzbd.downloader
|
||||
import sabnzbd.par2file as par2file
|
||||
import sabnzbd.utils.rarfile as rarfile
|
||||
from sabnzbd.encoding import unicoder, is_utf8
|
||||
from sabnzbd.encoding import unicoder
|
||||
from sabnzbd.rating import Rating
|
||||
|
||||
|
||||
@@ -97,13 +97,15 @@ class Assembler(Thread):
|
||||
try:
|
||||
filepath = self.assemble(nzf, filepath)
|
||||
except IOError, (errno, strerror):
|
||||
# If job was deleted, ignore error
|
||||
if not nzo.is_gone():
|
||||
# If job was deleted or in active post-processing, ignore error
|
||||
if not nzo.is_gone() and not nzo.pp_active:
|
||||
# 28 == disk full => pause downloader
|
||||
if errno == 28:
|
||||
logging.error(T('Disk full! Forcing Pause'))
|
||||
else:
|
||||
logging.error(T('Disk error on creating file %s'), clip_path(filepath))
|
||||
# Log traceback
|
||||
logging.info('Traceback: ', exc_info=True)
|
||||
# Pause without saving
|
||||
sabnzbd.downloader.Downloader.do.pause(save=False)
|
||||
continue
|
||||
@@ -318,7 +320,8 @@ def check_encrypted_and_unwanted_files(nzo, filepath):
|
||||
zf.close()
|
||||
del zf
|
||||
except:
|
||||
logging.info('Error during inspection of RAR-file %s', filepath, exc_info=True)
|
||||
logging.info('Error during inspection of RAR-file %s', filepath)
|
||||
logging.debug('Traceback: ', exc_info=True)
|
||||
|
||||
return encrypted, unwanted
|
||||
|
||||
|
||||
@@ -261,6 +261,7 @@ fixed_ports = OptionBool('misc', 'fixed_ports', False)
|
||||
api_warnings = OptionBool('misc', 'api_warnings', True, protect=True)
|
||||
disable_key = OptionBool('misc', 'disable_api_key', False, protect=True)
|
||||
no_penalties = OptionBool('misc', 'no_penalties', False)
|
||||
debug_log_decoding = OptionBool('misc', 'debug_log_decoding', False)
|
||||
|
||||
# Text values
|
||||
rss_odd_titles = OptionList('misc', 'rss_odd_titles', ['nzbindex.nl/', 'nzbindex.com/', 'nzbclub.com/'])
|
||||
@@ -374,6 +375,8 @@ prowl_prio_other = OptionNumber('prowl', 'prowl_prio_other', -3)
|
||||
pushover_token = OptionStr('pushover', 'pushover_token')
|
||||
pushover_userkey = OptionStr('pushover', 'pushover_userkey')
|
||||
pushover_device = OptionStr('pushover', 'pushover_device')
|
||||
pushover_emergency_expire = OptionNumber('pushover', 'pushover_emergency_expire', 3600)
|
||||
pushover_emergency_retry = OptionNumber('pushover', 'pushover_emergency_retry', 60)
|
||||
pushover_enable = OptionBool('pushover', 'pushover_enable')
|
||||
pushover_cats = OptionList('pushover', 'pushover_cats', ['*'])
|
||||
pushover_prio_startup = OptionNumber('pushover', 'pushover_prio_startup', -3)
|
||||
|
||||
@@ -385,7 +385,7 @@ class ConfigServer(object):
|
||||
self.displayname = OptionStr(name, 'displayname', '', add=False)
|
||||
self.host = OptionStr(name, 'host', '', add=False)
|
||||
self.port = OptionNumber(name, 'port', 119, 0, 2 ** 16 - 1, add=False)
|
||||
self.timeout = OptionNumber(name, 'timeout', 120, 30, 240, add=False)
|
||||
self.timeout = OptionNumber(name, 'timeout', 60, 20, 240, add=False)
|
||||
self.username = OptionStr(name, 'username', '', add=False)
|
||||
self.password = OptionPassword(name, 'password', '', add=False)
|
||||
self.connections = OptionNumber(name, 'connections', 1, 0, 100, add=False)
|
||||
@@ -395,7 +395,7 @@ class ConfigServer(object):
|
||||
self.optional = OptionBool(name, 'optional', False, add=False)
|
||||
self.retention = OptionNumber(name, 'retention', add=False)
|
||||
self.send_group = OptionBool(name, 'send_group', False, add=False)
|
||||
self.priority = OptionNumber(name, 'priority', 0, 0, 100, add=False)
|
||||
self.priority = OptionNumber(name, 'priority', 0, 0, 99, add=False)
|
||||
# 'fillserver' field only here in order to set a proper priority when converting
|
||||
self.fillserver = OptionBool(name, 'fillserver', False, add=False)
|
||||
self.notes = OptionStr(name, 'notes', '', add=False)
|
||||
@@ -859,7 +859,7 @@ def save_config(force=False):
|
||||
logging.error(T('Cannot write to INI file %s'), filename)
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
try:
|
||||
os.remove(filename)
|
||||
sabnzbd.misc.remove_file(filename)
|
||||
except:
|
||||
pass
|
||||
# Restore INI file from backup
|
||||
|
||||
@@ -40,7 +40,7 @@ from sabnzbd.constants import DB_HISTORY_NAME, STAGES
|
||||
from sabnzbd.encoding import unicoder
|
||||
from sabnzbd.bpsmeter import this_week, this_month
|
||||
from sabnzbd.decorators import synchronized
|
||||
from sabnzbd.misc import get_all_passwords, int_conv
|
||||
from sabnzbd.misc import get_all_passwords, int_conv, remove_file, caller_name
|
||||
|
||||
DB_LOCK = threading.RLock()
|
||||
|
||||
@@ -143,7 +143,7 @@ class HistoryDB(object):
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
self.close()
|
||||
try:
|
||||
os.remove(HistoryDB.db_path)
|
||||
remove_file(HistoryDB.db_path)
|
||||
except:
|
||||
pass
|
||||
self.connect()
|
||||
@@ -236,7 +236,7 @@ class HistoryDB(object):
|
||||
|
||||
for job in jobs:
|
||||
self.execute("""DELETE FROM history WHERE nzo_id=?""", (job,), save=True)
|
||||
logging.info('Removing job %s from history', job)
|
||||
logging.info('[%s] Removing job %s from history', caller_name(), job)
|
||||
|
||||
def auto_history_purge(self):
|
||||
""" Remove history items based on the configured history-retention """
|
||||
|
||||
@@ -31,6 +31,7 @@ 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
|
||||
|
||||
@@ -79,6 +80,7 @@ class Decoder(Thread):
|
||||
|
||||
self.queue = queue
|
||||
self.servers = servers
|
||||
self.__log_decoding = cfg.debug_log_decoding()
|
||||
|
||||
def stop(self):
|
||||
# Put multiple to stop all decoders
|
||||
@@ -115,7 +117,9 @@ class Decoder(Thread):
|
||||
if nzo.precheck:
|
||||
raise BadYenc
|
||||
register = True
|
||||
logging.debug("Decoding %s", art_id)
|
||||
|
||||
if self.__log_decoding:
|
||||
logging.debug("Decoding %s", art_id)
|
||||
|
||||
data = self.decode(article, lines, raw_data)
|
||||
nzf.article_count += 1
|
||||
@@ -144,7 +148,7 @@ class Decoder(Thread):
|
||||
register = False
|
||||
|
||||
except CrcError, e:
|
||||
logme = T('CRC Error in %s') % art_id
|
||||
logme = 'CRC Error in %s' % art_id
|
||||
logging.info(logme)
|
||||
|
||||
data = e.data
|
||||
|
||||
@@ -20,21 +20,27 @@
|
||||
##############################################################################
|
||||
from threading import RLock, Condition
|
||||
|
||||
DOWNLOADER_CV = Condition(RLock())
|
||||
|
||||
# All operations that modify the queue need to happen in a lock
|
||||
# Also used when importing NZBs to prevent IO-race conditions
|
||||
# Names of wrapper-functions should be the same in misc.caller_name
|
||||
# The NzbQueueLocker both locks and notifies the Downloader
|
||||
NZBQUEUE_LOCK = RLock()
|
||||
DOWNLOADER_CV = Condition(NZBQUEUE_LOCK)
|
||||
|
||||
def synchronized(lock):
|
||||
def wrap(f):
|
||||
def newFunction(*args, **kw):
|
||||
def call_func(*args, **kw):
|
||||
lock.acquire()
|
||||
try:
|
||||
return f(*args, **kw)
|
||||
finally:
|
||||
lock.release()
|
||||
return newFunction
|
||||
return call_func
|
||||
return wrap
|
||||
|
||||
|
||||
def notify_downloader(func):
|
||||
def NzbQueueLocker(func):
|
||||
global DOWNLOADER_CV
|
||||
def call_func(*params, **kparams):
|
||||
DOWNLOADER_CV.acquire()
|
||||
|
||||
@@ -28,19 +28,23 @@ import logging
|
||||
|
||||
import sabnzbd
|
||||
import sabnzbd.cfg as cfg
|
||||
from sabnzbd.misc import int_conv, clip_path, remove_all, globber, format_time_string, has_win_device
|
||||
from sabnzbd.misc import int_conv, clip_path, long_path, remove_all, globber, \
|
||||
format_time_string, has_win_device, real_path, remove_file
|
||||
from sabnzbd.encoding import TRANS, unicoder
|
||||
from sabnzbd.newsunpack import build_command, EXTRACTFROM_RE, rar_volumelist
|
||||
from sabnzbd.newsunpack import build_command, EXTRACTFROM_RE, EXTRACTED_RE, rar_volumelist
|
||||
from sabnzbd.postproc import prepare_extraction_path
|
||||
from sabnzbd.utils.rarfile import RarFile
|
||||
from sabnzbd.utils.diskspeed import diskspeedmeasure
|
||||
|
||||
if sabnzbd.WIN32:
|
||||
# Load the POpen from the fixed unicode-subprocess
|
||||
from sabnzbd.utils.subprocess_fix import Popen
|
||||
else:
|
||||
# Load the regular POpen
|
||||
from subprocess import Popen
|
||||
try:
|
||||
# Use patched version of subprocess module for Unicode on Windows
|
||||
import subprocessww
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Load the regular POpen (which is now patched on Windows)
|
||||
from subprocess import Popen
|
||||
|
||||
MAX_ACTIVE_UNPACKERS = 10
|
||||
ACTIVE_UNPACKERS = []
|
||||
@@ -150,6 +154,7 @@ class DirectUnpacker(threading.Thread):
|
||||
last_volume_linebuf = ''
|
||||
unrar_log = []
|
||||
rarfiles = []
|
||||
extracted = []
|
||||
start_time = time.time()
|
||||
|
||||
# Need to read char-by-char because there's no newline after new-disk message
|
||||
@@ -172,10 +177,21 @@ class DirectUnpacker(threading.Thread):
|
||||
logging.info('Error in DirectUnpack of %s', self.cur_setname)
|
||||
self.abort()
|
||||
|
||||
if linebuf.startswith('Extracting from') and linebuf.endswith('\n'):
|
||||
filename = TRANS((re.search(EXTRACTFROM_RE, linebuf.strip()).group(1)))
|
||||
if filename not in rarfiles:
|
||||
rarfiles.append(filename)
|
||||
if linebuf.endswith('\n'):
|
||||
# List files we used
|
||||
if linebuf.startswith('Extracting from'):
|
||||
filename = TRANS((re.search(EXTRACTFROM_RE, linebuf.strip()).group(1)))
|
||||
if filename not in rarfiles:
|
||||
rarfiles.append(filename)
|
||||
|
||||
# List files we extracted
|
||||
m = re.search(EXTRACTED_RE, linebuf)
|
||||
if m:
|
||||
# In case of flat-unpack, UnRar still prints the whole path (?!)
|
||||
unpacked_file = TRANS(m.group(2))
|
||||
if cfg.flat_unpack():
|
||||
unpacked_file = os.path.basename(unpacked_file)
|
||||
extracted.append(real_path(self.unpack_dir_info[0], unpacked_file))
|
||||
|
||||
# Did we reach the end?
|
||||
if linebuf.endswith('All OK'):
|
||||
@@ -185,16 +201,23 @@ class DirectUnpacker(threading.Thread):
|
||||
|
||||
# Add to success
|
||||
rarfile_path = os.path.join(self.nzo.downpath, self.rarfile_nzf.filename)
|
||||
self.success_sets[self.cur_setname] = rar_volumelist(rarfile_path, self.nzo.password, rarfiles)
|
||||
self.success_sets[self.cur_setname] = (rar_volumelist(rarfile_path, self.nzo.password, rarfiles), extracted)
|
||||
logging.info('DirectUnpack completed for %s', self.cur_setname)
|
||||
self.nzo.set_action_line(T('Direct Unpack'), T('Completed'))
|
||||
|
||||
# List success in history-info
|
||||
msg = T('Unpacked %s files/folders in %s') % (len(extracted), format_time_string(self.unpack_time))
|
||||
msg = '%s - %s' % (T('Direct Unpack'), msg)
|
||||
self.nzo.set_unpack_info('Unpack', '[%s] %s' % (unicoder(self.cur_setname), msg))
|
||||
|
||||
# Write current log and clear
|
||||
unrar_log.append(linebuf.strip())
|
||||
linebuf = ''
|
||||
last_volume_linebuf = ''
|
||||
logging.debug('DirectUnpack Unrar output %s', '\n'.join(unrar_log))
|
||||
unrar_log = []
|
||||
rarfiles = []
|
||||
extracted = []
|
||||
|
||||
# Are there more files left?
|
||||
while self.nzo.files and not self.next_sets:
|
||||
@@ -224,10 +247,15 @@ class DirectUnpacker(threading.Thread):
|
||||
|
||||
# Possible that the instance was deleted while locked
|
||||
if not self.killed:
|
||||
# Give unrar some time to do it's thing
|
||||
self.active_instance.stdin.write('\n')
|
||||
start_time = time.time()
|
||||
time.sleep(0.1)
|
||||
# If unrar stopped or is killed somehow, writing will cause a crash
|
||||
try:
|
||||
# Give unrar some time to do it's thing
|
||||
self.active_instance.stdin.write('C\n')
|
||||
start_time = time.time()
|
||||
time.sleep(0.1)
|
||||
except IOError:
|
||||
self.abort()
|
||||
break
|
||||
|
||||
# Did we unpack a new volume? Sometimes UnRar hangs on 1 volume
|
||||
if not last_volume_linebuf or last_volume_linebuf != linebuf:
|
||||
@@ -237,9 +265,12 @@ class DirectUnpacker(threading.Thread):
|
||||
logging.info('DirectUnpacked volume %s for %s', self.cur_volume, self.cur_setname)
|
||||
|
||||
# If lines did not change and we don't have the next volume, this download is missing files!
|
||||
if last_volume_linebuf == linebuf and not self.have_next_volume():
|
||||
logging.info('DirectUnpack failed due to missing files %s', self.cur_setname)
|
||||
self.abort()
|
||||
if last_volume_linebuf == linebuf:
|
||||
if not self.have_next_volume():
|
||||
logging.info('DirectUnpack failed due to missing files %s', self.cur_setname)
|
||||
self.abort()
|
||||
else:
|
||||
logging.debug('Duplicate output line detected: "%s"', last_volume_linebuf)
|
||||
|
||||
last_volume_linebuf = linebuf
|
||||
|
||||
@@ -252,14 +283,6 @@ class DirectUnpacker(threading.Thread):
|
||||
unrar_log.append(linebuf.strip())
|
||||
logging.debug('DirectUnpack Unrar output %s', '\n'.join(unrar_log))
|
||||
|
||||
# Save information if success
|
||||
if self.success_sets:
|
||||
# The number is wrong if one_folder, just leave empty
|
||||
nr_files = '' if self.unpack_dir_info[3] else len(globber(self.unpack_dir_info[0]))
|
||||
msg = T('Unpacked %s files/folders in %s') % (nr_files, format_time_string(self.unpack_time))
|
||||
msg = '%s - %s' % (T('Direct Unpack'), msg)
|
||||
self.nzo.set_unpack_info('Unpack', '[%s] %s' % (unicoder(self.cur_setname), msg))
|
||||
|
||||
# Make more space
|
||||
self.reset_active()
|
||||
if self in ACTIVE_UNPACKERS:
|
||||
@@ -290,7 +313,14 @@ class DirectUnpacker(threading.Thread):
|
||||
""" Start the unrar instance using the user's options """
|
||||
# Generate extraction path and save for post-proc
|
||||
if not self.unpack_dir_info:
|
||||
self.unpack_dir_info = prepare_extraction_path(self.nzo)
|
||||
try:
|
||||
self.unpack_dir_info = prepare_extraction_path(self.nzo)
|
||||
except:
|
||||
# Prevent fatal crash if directory creation fails
|
||||
self.abort()
|
||||
return
|
||||
|
||||
# Get the information
|
||||
extraction_path, _, _, one_folder, _ = self.unpack_dir_info
|
||||
|
||||
# Set options
|
||||
@@ -310,13 +340,11 @@ class DirectUnpacker(threading.Thread):
|
||||
# Generate command
|
||||
rarfile_path = os.path.join(self.nzo.downpath, self.rarfile_nzf.filename)
|
||||
if sabnzbd.WIN32:
|
||||
if not has_win_device(rarfile_path):
|
||||
command = ['%s' % sabnzbd.newsunpack.RAR_COMMAND, action, '-vp', '-idp', '-o+', '-ai', password_command,
|
||||
'%s' % clip_path(rarfile_path), clip_path(extraction_path)]
|
||||
else:
|
||||
# Need long-path notation in case of forbidden-names
|
||||
command = ['%s' % sabnzbd.newsunpack.RAR_COMMAND, action, '-vp', '-idp', '-o+', '-ai', password_command,
|
||||
'%s' % clip_path(rarfile_path), '%s\\' % extraction_path]
|
||||
# For Unrar to support long-path, we need to cricumvent Python's list2cmdline
|
||||
# See: https://github.com/sabnzbd/sabnzbd/issues/1043
|
||||
command = ['%s' % sabnzbd.newsunpack.RAR_COMMAND, action, '-vp', '-idp', '-o+', '-ai', password_command,
|
||||
'%s' % clip_path(rarfile_path), '%s\\' % long_path(extraction_path)]
|
||||
|
||||
else:
|
||||
# Don't use "-ai" (not needed for non-Windows)
|
||||
command = ['%s' % sabnzbd.newsunpack.RAR_COMMAND, action, '-vp', '-idp', '-o+', password_command,
|
||||
@@ -327,9 +355,9 @@ class DirectUnpacker(threading.Thread):
|
||||
|
||||
# Let's start from the first one!
|
||||
self.cur_volume = 1
|
||||
stup, need_shell, command, creationflags = build_command(command)
|
||||
stup, need_shell, command, creationflags = build_command(command, flatten_command=True)
|
||||
logging.debug('Running unrar for DirectUnpack %s', command)
|
||||
self.active_instance = Popen(command, shell=need_shell, stdin=subprocess.PIPE,
|
||||
self.active_instance = Popen(command, shell=False, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
startupinfo=stup, creationflags=creationflags)
|
||||
# Add to runners
|
||||
@@ -372,8 +400,7 @@ class DirectUnpacker(threading.Thread):
|
||||
for rm_file in rar_contents:
|
||||
# Flat-unpack, so remove foldername from RarFile output
|
||||
f = os.path.join(extraction_path, os.path.basename(rm_file))
|
||||
logging.debug('Removing file %s', f)
|
||||
os.remove(f)
|
||||
remove_file(f)
|
||||
except:
|
||||
# The user will have to remove it themselves
|
||||
logging.info('Failed to clean Direct Unpack after aborting %s', rarfile_nzf.filename, exc_info=True)
|
||||
|
||||
@@ -31,6 +31,7 @@ import sabnzbd
|
||||
from sabnzbd.constants import SCAN_FILE_NAME, VALID_ARCHIVES
|
||||
import sabnzbd.utils.rarfile as rarfile
|
||||
from sabnzbd.encoding import platform_encode
|
||||
from sabnzbd.decorators import NzbQueueLocker
|
||||
from sabnzbd.newsunpack import is_sevenfile, SevenZip
|
||||
import sabnzbd.nzbstuff as nzbstuff
|
||||
import sabnzbd.misc as misc
|
||||
@@ -96,6 +97,7 @@ def is_archive(path):
|
||||
return 1, None, ''
|
||||
|
||||
|
||||
@NzbQueueLocker
|
||||
def ProcessArchiveFile(filename, path, pp=None, script=None, cat=None, catdir=None, keep=False,
|
||||
priority=None, url='', nzbname=None, password=None, nzo_id=None):
|
||||
""" Analyse ZIP file and create job(s).
|
||||
@@ -160,7 +162,7 @@ def ProcessArchiveFile(filename, path, pp=None, script=None, cat=None, catdir=No
|
||||
zf.close()
|
||||
try:
|
||||
if not keep:
|
||||
os.remove(path)
|
||||
misc.remove_file(path)
|
||||
except:
|
||||
logging.error(T('Error removing %s'), misc.clip_path(path))
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
@@ -172,6 +174,7 @@ def ProcessArchiveFile(filename, path, pp=None, script=None, cat=None, catdir=No
|
||||
return status, nzo_ids
|
||||
|
||||
|
||||
@NzbQueueLocker
|
||||
def ProcessSingleFile(filename, path, pp=None, script=None, cat=None, catdir=None, keep=False,
|
||||
priority=None, nzbname=None, reuse=False, nzo_info=None, dup_check=True, url='',
|
||||
password=None, nzo_id=None):
|
||||
@@ -246,7 +249,7 @@ def ProcessSingleFile(filename, path, pp=None, script=None, cat=None, catdir=Non
|
||||
nzo.update_rating()
|
||||
try:
|
||||
if not keep:
|
||||
os.remove(path)
|
||||
misc.remove_file(path)
|
||||
except:
|
||||
logging.error(T('Error removing %s'), misc.clip_path(path))
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
|
||||
@@ -30,7 +30,7 @@ import sys
|
||||
import Queue
|
||||
|
||||
import sabnzbd
|
||||
from sabnzbd.decorators import synchronized, notify_downloader, DOWNLOADER_CV
|
||||
from sabnzbd.decorators import synchronized, NzbQueueLocker, 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
|
||||
@@ -256,12 +256,12 @@ class Downloader(Thread):
|
||||
|
||||
return
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def set_paused_state(self, state):
|
||||
""" Set downloader to specified paused state """
|
||||
self.paused = state
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def resume(self):
|
||||
# Do not notify when SABnzbd is still starting
|
||||
if self.paused and sabnzbd.WEB_DIR:
|
||||
@@ -269,7 +269,7 @@ class Downloader(Thread):
|
||||
notifier.send_notification("SABnzbd", T('Resuming'), 'download')
|
||||
self.paused = False
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def pause(self, save=True):
|
||||
""" Pause the downloader, optionally saving admin """
|
||||
if not self.paused:
|
||||
@@ -287,7 +287,7 @@ class Downloader(Thread):
|
||||
logging.debug("Delaying")
|
||||
self.delayed = True
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def undelay(self):
|
||||
logging.debug("Undelaying")
|
||||
self.delayed = False
|
||||
@@ -296,7 +296,7 @@ class Downloader(Thread):
|
||||
logging.info("Waiting for post-processing to finish")
|
||||
self.postproc = True
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def resume_from_postproc(self):
|
||||
logging.info("Post-processing finished, resuming download")
|
||||
self.postproc = False
|
||||
@@ -540,7 +540,7 @@ class Downloader(Thread):
|
||||
# Check 10 seconds after enabling slowdown
|
||||
if self.can_be_slowed_timer and time.time() > self.can_be_slowed_timer + 10:
|
||||
# Now let's check if it was stable in the last 10 seconds
|
||||
self.can_be_slowed = (BPSMeter.do.get_stable_speed(timespan=10) > 0)
|
||||
self.can_be_slowed = BPSMeter.do.get_stable_speed(timespan=10)
|
||||
self.can_be_slowed_timer = 0
|
||||
logging.debug('Downloader-slowdown: %r', self.can_be_slowed)
|
||||
|
||||
@@ -863,7 +863,7 @@ class Downloader(Thread):
|
||||
del self._timers[server_id]
|
||||
self.init_server(server_id, server_id)
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
@synchronized(TIMER_LOCK)
|
||||
def unblock(self, server_id):
|
||||
# Remove timer
|
||||
@@ -882,7 +882,7 @@ class Downloader(Thread):
|
||||
for server_id in self._timers.keys():
|
||||
self.unblock(server_id)
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
@synchronized(TIMER_LOCK)
|
||||
def check_timers(self):
|
||||
""" Make sure every server without a non-expired timer is active """
|
||||
@@ -905,7 +905,7 @@ class Downloader(Thread):
|
||||
def update_server(self, oldserver, newserver):
|
||||
self.init_server(oldserver, newserver)
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def wakeup(self):
|
||||
""" Just rattle the semaphore """
|
||||
pass
|
||||
|
||||
@@ -149,6 +149,8 @@ def send(message, email_to, test=None):
|
||||
else:
|
||||
logging.info("Notification e-mail successfully sent")
|
||||
return T('Email succeeded')
|
||||
else:
|
||||
return T('Cannot send, missing required data')
|
||||
|
||||
|
||||
def get_email_date():
|
||||
@@ -218,7 +220,7 @@ def send_with_template(prefix, parm, test=None):
|
||||
def endjob(filename, cat, status, path, bytes, fail_msg, stages, script, script_output, script_ret, test=None):
|
||||
""" Send end-of-job email """
|
||||
# Is it allowed?
|
||||
if not check_cat('email', cat):
|
||||
if not check_cat('misc', cat, keyword='email') and not test:
|
||||
return None
|
||||
|
||||
# Translate the stage names
|
||||
|
||||
@@ -70,19 +70,6 @@ def yenc_name_fixer(p):
|
||||
return p.decode('cp1252', errors='replace').replace('?', '!')
|
||||
|
||||
|
||||
def is_utf8(p):
|
||||
""" Return True when p is UTF-8 or plain ASCII """
|
||||
utf8 = True
|
||||
try:
|
||||
p.decode('ascii')
|
||||
except:
|
||||
try:
|
||||
p.decode('utf-8')
|
||||
except:
|
||||
utf8 = False
|
||||
return utf8
|
||||
|
||||
|
||||
def special_fixer(p):
|
||||
""" Return string appropriate for the platform.
|
||||
Also takes care of the situation where a non-Windows/UTF-8 system
|
||||
@@ -218,7 +205,11 @@ def TRANS(p):
|
||||
"""
|
||||
global gTABLE_850_LATIN
|
||||
if sabnzbd.WIN32:
|
||||
return p.translate(gTABLE_850_LATIN).decode('cp1252', 'replace')
|
||||
if p:
|
||||
return p.translate(gTABLE_850_LATIN).decode('cp1252', 'replace')
|
||||
else:
|
||||
# translate() fails on empty or None strings
|
||||
return ''
|
||||
else:
|
||||
return unicoder(p)
|
||||
|
||||
@@ -229,7 +220,11 @@ def UNTRANS(p):
|
||||
"""
|
||||
global gTABLE_LATIN_850
|
||||
if sabnzbd.WIN32:
|
||||
return p.encode('cp1252', 'replace').translate(gTABLE_LATIN_850)
|
||||
if p:
|
||||
return p.encode('cp1252', 'replace').translate(gTABLE_LATIN_850)
|
||||
else:
|
||||
# translate() fails on empty or None strings
|
||||
return ''
|
||||
else:
|
||||
return p
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ import sabnzbd.scheduler as scheduler
|
||||
|
||||
from Cheetah.Template import Template
|
||||
from sabnzbd.misc import real_path, to_units, from_units, \
|
||||
time_format, long_path, calc_age, \
|
||||
time_format, long_path, calc_age, same_file, \
|
||||
cat_to_opts, int_conv, globber, globber_full, remove_all, get_base_url
|
||||
from sabnzbd.newswrapper import GetServerParms
|
||||
from sabnzbd.rating import Rating
|
||||
@@ -1373,7 +1373,7 @@ class ConfigSwitches(object):
|
||||
SPECIAL_BOOL_LIST = \
|
||||
('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', 'ignore_unrar_dates',
|
||||
'enable_filejoin', 'enable_tsjoin', 'ignore_unrar_dates', 'debug_log_decoding',
|
||||
'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', 'reject_duplicate_files', 'warn_dupl_jobs',
|
||||
@@ -2349,12 +2349,17 @@ class ConfigCats(object):
|
||||
else:
|
||||
newname = re.sub('"', '', kwargs.get('newname', ''))
|
||||
if newname:
|
||||
if name:
|
||||
config.delete('categories', name)
|
||||
name = newname.lower()
|
||||
if kwargs.get('dir'):
|
||||
kwargs['dir'] = platform_encode(kwargs['dir'])
|
||||
config.ConfigCat(name, kwargs)
|
||||
|
||||
# Check if this cat-dir is not sub-folder of incomplete
|
||||
if same_file(cfg.download_dir.get_path(), real_path(cfg.complete_dir.get_path(), kwargs['dir'])):
|
||||
return T('Category folder cannot be a subfolder of the Temporary Download Folder.')
|
||||
|
||||
# Delete current one and replace with new one
|
||||
if name:
|
||||
config.delete('categories', name)
|
||||
config.ConfigCat(newname.lower(), kwargs)
|
||||
|
||||
config.save_config()
|
||||
raise Raiser(self.__root)
|
||||
@@ -2734,7 +2739,7 @@ LIST_PROWL = ('prowl_enable', 'prowl_cats', 'prowl_apikey',
|
||||
LIST_PUSHOVER = ('pushover_enable', 'pushover_cats', 'pushover_token', 'pushover_userkey', 'pushover_device',
|
||||
'pushover_prio_startup', 'pushover_prio_download', 'pushover_prio_pp', 'pushover_prio_complete', 'pushover_prio_failed',
|
||||
'pushover_prio_disk_full', 'pushover_prio_warning', 'pushover_prio_error', 'pushover_prio_queue_done', 'pushover_prio_other',
|
||||
'pushover_prio_new_login')
|
||||
'pushover_prio_new_login', 'pushover_emergency_retry', 'pushover_emergency_expire')
|
||||
LIST_PUSHBULLET = ('pushbullet_enable', 'pushbullet_cats', 'pushbullet_apikey', 'pushbullet_device',
|
||||
'pushbullet_prio_startup', 'pushbullet_prio_download', 'pushbullet_prio_pp', 'pushbullet_prio_complete', 'pushbullet_prio_failed',
|
||||
'pushbullet_prio_disk_full', 'pushbullet_prio_warning', 'pushbullet_prio_error', 'pushbullet_prio_queue_done', 'pushbullet_prio_other',
|
||||
|
||||
@@ -29,10 +29,11 @@ import threading
|
||||
import subprocess
|
||||
import socket
|
||||
import time
|
||||
import calendar
|
||||
import datetime
|
||||
import fnmatch
|
||||
import stat
|
||||
import inspect
|
||||
import urllib2
|
||||
from urlparse import urlparse
|
||||
|
||||
import sabnzbd
|
||||
@@ -167,7 +168,7 @@ def cat_to_opts(cat, pp=None, script=None, priority=None):
|
||||
if safe_lower(script) in ('', 'default'):
|
||||
script = def_cat.script()
|
||||
|
||||
if priority is None or priority == DEFAULT_PRIORITY:
|
||||
if priority is None or priority == '' or priority == DEFAULT_PRIORITY:
|
||||
priority = my_cat.priority()
|
||||
if priority == DEFAULT_PRIORITY:
|
||||
priority = def_cat.priority()
|
||||
@@ -770,6 +771,31 @@ def to_units(val, spaces=0, dec_limit=2, postfix=''):
|
||||
return fmt % (sign, val, unit, postfix)
|
||||
|
||||
|
||||
def caller_name(skip=2):
|
||||
"""Get a name of a caller in the format module.method
|
||||
Originally used: https://gist.github.com/techtonik/2151727
|
||||
Adapted for speed by using sys calls directly
|
||||
"""
|
||||
# Only do the tracing on Debug (function is always called)
|
||||
if cfg.log_level() != 2:
|
||||
return 'N/A'
|
||||
|
||||
parentframe = sys._getframe(skip)
|
||||
function_name = parentframe.f_code.co_name
|
||||
|
||||
# Modulename not available in the binaries, we can use the filename instead
|
||||
if getattr(sys, 'frozen', None):
|
||||
module_name = inspect.getfile(parentframe)
|
||||
else:
|
||||
module_name = inspect.getmodule(parentframe).__name__
|
||||
|
||||
# For decorated functions we have to go deeper
|
||||
if function_name in ('call_func', 'wrap') and skip == 2:
|
||||
return caller_name(4)
|
||||
|
||||
return ".".join([module_name, function_name])
|
||||
|
||||
|
||||
def same_file(a, b):
|
||||
""" Return 0 if A and B have nothing in common
|
||||
return 1 if A and B are actually the same path
|
||||
@@ -820,6 +846,14 @@ def split_host(srv):
|
||||
return (host, port)
|
||||
|
||||
|
||||
def get_from_url(url):
|
||||
""" Retrieve URL and return content """
|
||||
try:
|
||||
return urllib2.urlopen(url).read()
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def check_mount(path):
|
||||
""" Return False if volume isn't mounted on Linux or OSX
|
||||
Retry 6 times with an interval of 1 sec.
|
||||
@@ -923,7 +957,7 @@ def move_to_path(path, new_path):
|
||||
new_path = os.path.abspath(new_path)
|
||||
if overwrite and os.path.exists(new_path):
|
||||
try:
|
||||
os.remove(new_path)
|
||||
remove_file(new_path)
|
||||
except:
|
||||
overwrite = False
|
||||
if not overwrite:
|
||||
@@ -941,7 +975,7 @@ def move_to_path(path, new_path):
|
||||
if not os.path.exists(os.path.dirname(new_path)):
|
||||
create_dirs(os.path.dirname(new_path))
|
||||
shutil.copyfile(path, new_path)
|
||||
os.remove(path)
|
||||
remove_file(path)
|
||||
except:
|
||||
# Check if the old-file actually exists (possible delete-delays)
|
||||
if not os.path.exists(path):
|
||||
@@ -1056,12 +1090,11 @@ def renamer(old, new):
|
||||
@synchronized(DIR_LOCK)
|
||||
def remove_dir(path):
|
||||
""" Remove directory with retries for Win32 """
|
||||
logging.debug('Removing dir %s', path)
|
||||
if sabnzbd.WIN32:
|
||||
retries = 15
|
||||
while retries > 0:
|
||||
try:
|
||||
os.rmdir(path)
|
||||
remove_dir(path)
|
||||
return
|
||||
except WindowsError, err:
|
||||
if err[0] == 32:
|
||||
@@ -1072,7 +1105,7 @@ def remove_dir(path):
|
||||
time.sleep(3)
|
||||
raise WindowsError(err)
|
||||
else:
|
||||
os.rmdir(path)
|
||||
remove_dir(path)
|
||||
|
||||
|
||||
@synchronized(DIR_LOCK)
|
||||
@@ -1086,20 +1119,30 @@ 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)
|
||||
remove_file(f)
|
||||
except:
|
||||
logging.info('Cannot remove file %s', f)
|
||||
elif recursive:
|
||||
remove_all(f, pattern, False, True)
|
||||
if not keep_folder:
|
||||
try:
|
||||
logging.debug('Removing dir %s', path)
|
||||
os.rmdir(path)
|
||||
remove_dir(path)
|
||||
except:
|
||||
logging.info('Cannot remove folder %s', path)
|
||||
|
||||
|
||||
def remove_file(path):
|
||||
""" Wrapper function so any file removal is logged """
|
||||
logging.debug('[%s] Deleting file %s', caller_name(), path)
|
||||
os.remove(path)
|
||||
|
||||
|
||||
def remove_dir(dir):
|
||||
""" Wrapper function so any dir removal is logged """
|
||||
logging.debug('[%s] Deleting dir %s', caller_name(), dir)
|
||||
os.rmdir(dir)
|
||||
|
||||
|
||||
def trim_win_path(path):
|
||||
""" Make sure Windows path stays below 70 by trimming last part """
|
||||
if sabnzbd.WIN32 and len(path) > 69:
|
||||
|
||||
@@ -33,7 +33,7 @@ from sabnzbd.encoding import TRANS, UNTRANS, unicoder, platform_encode, deunicod
|
||||
import sabnzbd.utils.rarfile as rarfile
|
||||
from sabnzbd.misc import format_time_string, find_on_path, make_script_path, int_conv, \
|
||||
real_path, globber, globber_full, get_all_passwords, renamer, clip_path, \
|
||||
has_win_device, calc_age, long_path
|
||||
has_win_device, calc_age, long_path, remove_file
|
||||
from sabnzbd.tvsort import SeriesSorter
|
||||
import sabnzbd.cfg as cfg
|
||||
from sabnzbd.constants import Status
|
||||
@@ -43,10 +43,11 @@ if sabnzbd.WIN32:
|
||||
import win32api
|
||||
from win32con import SW_HIDE
|
||||
from win32process import STARTF_USESHOWWINDOW, IDLE_PRIORITY_CLASS
|
||||
|
||||
# Use patched version of subprocess module for Unicode on Windows
|
||||
import subprocessww
|
||||
except ImportError:
|
||||
pass
|
||||
# Load the POpen from the fixed unicode-subprocess
|
||||
from sabnzbd.utils.subprocess_fix import Popen
|
||||
else:
|
||||
# Define dummy WindowsError for non-Windows
|
||||
class WindowsError(Exception):
|
||||
@@ -55,8 +56,9 @@ else:
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.parameter)
|
||||
# Load the regular POpen
|
||||
from subprocess import Popen
|
||||
|
||||
# Load the regular POpen (which is now patched on Windows)
|
||||
from subprocess import Popen
|
||||
|
||||
# Regex globals
|
||||
RAR_RE = re.compile(r'\.(?P<ext>part\d*\.rar|rar|r\d\d|s\d\d|t\d\d|u\d\d|v\d\d|\d\d\d)$', re.I)
|
||||
@@ -65,6 +67,7 @@ RAR_RE_V3 = re.compile(r'\.(?P<ext>part\d*)$', re.I)
|
||||
LOADING_RE = re.compile(r'^Loading "(.+)"')
|
||||
TARGET_RE = re.compile(r'^(?:File|Target): "(.+)" -')
|
||||
EXTRACTFROM_RE = re.compile(r'^Extracting\sfrom\s(.+)')
|
||||
EXTRACTED_RE = re.compile(r'^(Extracting|Creating|...)\s+(.*?)\s+OK\s*$')
|
||||
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)
|
||||
@@ -139,12 +142,12 @@ ENV_NZO_FIELDS = ['bytes', 'bytes_downloaded', 'bytes_tried', 'cat', 'duplicate'
|
||||
|
||||
def external_processing(extern_proc, nzo, complete_dir, nicename, status):
|
||||
""" Run a user postproc script, return console output and exit value """
|
||||
command = [str(extern_proc), str(complete_dir), str(nzo.filename),
|
||||
str(nicename), '', str(nzo.cat), str(nzo.group), str(status)]
|
||||
|
||||
failure_url = nzo.nzo_info.get('failure', '')
|
||||
if failure_url:
|
||||
command.append(str(failure_url))
|
||||
command = [str(extern_proc), str(complete_dir), str(nzo.filename), str(nicename), '',
|
||||
str(nzo.cat), str(nzo.group), str(status), str(failure_url)]
|
||||
|
||||
# Add path to original NZB
|
||||
nzb_paths = globber_full(nzo.workpath, '*.gz')
|
||||
|
||||
# Fields not in the NZO directly
|
||||
extra_env_fields = {'failure_url': failure_url,
|
||||
@@ -153,6 +156,13 @@ def external_processing(extern_proc, nzo, complete_dir, nicename, status):
|
||||
'download_time': nzo.nzo_info.get('download_time', ''),
|
||||
'avg_bps': int(nzo.avg_bps_total / nzo.avg_bps_freq) if nzo.avg_bps_freq else 0,
|
||||
'age': calc_age(nzo.avg_date),
|
||||
'orig_nzb_gz': clip_path(nzb_paths[0]) if nzb_paths else '',
|
||||
'program_dir': sabnzbd.DIR_PROG,
|
||||
'par2_command': sabnzbd.newsunpack.PAR2_COMMAND,
|
||||
'multipar_command': sabnzbd.newsunpack.MULTIPAR_COMMAND,
|
||||
'rar_command': sabnzbd.newsunpack.RAR_COMMAND,
|
||||
'zip_command': sabnzbd.newsunpack.ZIP_COMMAND,
|
||||
'7zip_command': sabnzbd.newsunpack.SEVEN_COMMAND,
|
||||
'version': sabnzbd.__version__}
|
||||
|
||||
try:
|
||||
@@ -178,6 +188,9 @@ def external_processing(extern_proc, nzo, complete_dir, nicename, status):
|
||||
line = line.strip()
|
||||
lines.append(line)
|
||||
|
||||
# Show current line in history
|
||||
nzo.set_action_line(T('Running script'), unicoder(line))
|
||||
|
||||
# Check if we should still continue
|
||||
if not nzo.pp_active:
|
||||
p.kill()
|
||||
@@ -330,16 +343,14 @@ def clean_up_joinables(names):
|
||||
""" Remove joinable files and their .1 backups """
|
||||
for name in names:
|
||||
if os.path.exists(name):
|
||||
logging.debug("Deleting %s", name)
|
||||
try:
|
||||
os.remove(name)
|
||||
remove_file(name)
|
||||
except:
|
||||
pass
|
||||
name1 = name + ".1"
|
||||
if os.path.exists(name1):
|
||||
logging.debug("Deleting %s", name1)
|
||||
try:
|
||||
os.remove(name1)
|
||||
remove_file(name1)
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -415,8 +426,7 @@ def file_join(nzo, workdir, workdir_complete, delete, joinables):
|
||||
shutil.copyfileobj(f, joined_file, bufsize)
|
||||
f.close()
|
||||
if delete:
|
||||
logging.debug("Deleting %s", joinable)
|
||||
os.remove(joinable)
|
||||
remove_file(joinable)
|
||||
n += 1
|
||||
|
||||
# Remove any remaining .1 files
|
||||
@@ -480,20 +490,30 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, one_folder, rars):
|
||||
|
||||
# Is the direct-unpacker still running? We wait for it
|
||||
if nzo.direct_unpacker:
|
||||
wait_count = 0
|
||||
last_stats = nzo.direct_unpacker.get_formatted_stats()
|
||||
while nzo.direct_unpacker.is_alive():
|
||||
logging.debug('DirectUnpacker still alive for %s', nzo)
|
||||
logging.debug('DirectUnpacker still alive for %s: %s', nzo.work_name, last_stats)
|
||||
|
||||
# Bump the file-lock in case it's stuck
|
||||
with nzo.direct_unpacker.next_file_lock:
|
||||
nzo.direct_unpacker.next_file_lock.notify()
|
||||
time.sleep(2)
|
||||
|
||||
# Did something change? Might be stuck
|
||||
if last_stats == nzo.direct_unpacker.get_formatted_stats():
|
||||
wait_count += 1
|
||||
if wait_count > 60:
|
||||
# We abort after 2 minutes of no changes
|
||||
nzo.direct_unpacker.abort()
|
||||
last_stats = nzo.direct_unpacker.get_formatted_stats()
|
||||
|
||||
# Did we already direct-unpack it? Not when recursive-unpacking
|
||||
if nzo.direct_unpacker and rar_set in nzo.direct_unpacker.success_sets:
|
||||
logging.info("Set %s completed by DirectUnpack", rar_set)
|
||||
fail = False
|
||||
success = True
|
||||
rars = nzo.direct_unpacker.success_sets.pop(rar_set)
|
||||
newfiles = globber(extraction_path)
|
||||
rars, newfiles = nzo.direct_unpacker.success_sets.pop(rar_set)
|
||||
else:
|
||||
logging.info("Extracting rarfile %s (belonging to %s) to %s",
|
||||
rarpath, rar_set, extraction_path)
|
||||
@@ -541,9 +561,8 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, one_folder, rars):
|
||||
# Delete the old files if we have to
|
||||
if success and delete and newfiles:
|
||||
for rar in rars:
|
||||
logging.info("Deleting %s", rar)
|
||||
try:
|
||||
os.remove(rar)
|
||||
remove_file(rar)
|
||||
except OSError:
|
||||
if os.path.exists(rar):
|
||||
logging.warning(T('Deleting %s failed!'), rar)
|
||||
@@ -553,7 +572,7 @@ def rar_unpack(nzo, workdir, workdir_complete, delete, one_folder, rars):
|
||||
if os.path.exists(brokenrar):
|
||||
logging.info("Deleting %s", brokenrar)
|
||||
try:
|
||||
os.remove(brokenrar)
|
||||
remove_file(brokenrar)
|
||||
except OSError:
|
||||
if os.path.exists(brokenrar):
|
||||
logging.warning(T('Deleting %s failed!'), brokenrar)
|
||||
@@ -613,18 +632,10 @@ def rar_extract_core(rarfile_path, numrars, one_folder, nzo, setname, extraction
|
||||
rename = '-or' # Auto renaming
|
||||
|
||||
if sabnzbd.WIN32:
|
||||
# Use all flags
|
||||
if not has_win_device(rarfile_path):
|
||||
command = ['%s' % RAR_COMMAND, action, '-idp', overwrite, rename, '-ai', password_command,
|
||||
'%s' % clip_path(rarfile_path), clip_path(extraction_path)]
|
||||
else:
|
||||
# Need long-path notation in case of forbidden-names
|
||||
command = ['%s' % RAR_COMMAND, action, '-idp', overwrite, rename, '-ai', password_command,
|
||||
'%s' % clip_path(rarfile_path), '%s\\' % extraction_path]
|
||||
|
||||
# The subprocess_fix requires time to clear the buffers to work,
|
||||
# otherwise the inputs get send incorrectly and unrar breaks
|
||||
time.sleep(0.5)
|
||||
# For Unrar to support long-path, we need to cricumvent Python's list2cmdline
|
||||
# See: https://github.com/sabnzbd/sabnzbd/issues/1043
|
||||
command = ['%s' % RAR_COMMAND, action, '-idp', overwrite, rename, '-ai', password_command,
|
||||
'%s' % clip_path(rarfile_path), '%s\\' % long_path(extraction_path)]
|
||||
|
||||
elif RAR_PROBLEM:
|
||||
# Use only oldest options (specifically no "-or")
|
||||
@@ -638,7 +649,7 @@ def rar_extract_core(rarfile_path, numrars, one_folder, nzo, setname, extraction
|
||||
if cfg.ignore_unrar_dates():
|
||||
command.insert(3, '-tsm-')
|
||||
|
||||
stup, need_shell, command, creationflags = build_command(command)
|
||||
stup, need_shell, command, creationflags = build_command(command, flatten_command=True)
|
||||
|
||||
# Get list of all the volumes part of this set
|
||||
logging.debug("Analyzing rar file ... %s found", rarfile.is_rarfile(rarfile_path))
|
||||
@@ -791,9 +802,13 @@ def rar_extract_core(rarfile_path, numrars, one_folder, nzo, setname, extraction
|
||||
fail = 3
|
||||
|
||||
else:
|
||||
m = re.search(r'^(Extracting|Creating|...)\s+(.*?)\s+OK\s*$', line)
|
||||
m = re.search(EXTRACTED_RE, line)
|
||||
if m:
|
||||
extracted.append(real_path(extraction_path, TRANS(m.group(2))))
|
||||
# In case of flat-unpack, UnRar still prints the whole path (?!)
|
||||
unpacked_file = TRANS(m.group(2))
|
||||
if cfg.flat_unpack():
|
||||
unpacked_file = os.path.basename(unpacked_file)
|
||||
extracted.append(real_path(extraction_path, unpacked_file))
|
||||
|
||||
if fail:
|
||||
if proc:
|
||||
@@ -853,9 +868,8 @@ def unzip(nzo, workdir, workdir_complete, delete, one_folder, zips):
|
||||
i = 0
|
||||
|
||||
for _zip in zips:
|
||||
logging.info("Deleting %s", _zip)
|
||||
try:
|
||||
os.remove(_zip)
|
||||
remove_file(_zip)
|
||||
i += 1
|
||||
except OSError:
|
||||
logging.warning(T('Deleting %s failed!'), _zip)
|
||||
@@ -863,9 +877,8 @@ def unzip(nzo, workdir, workdir_complete, delete, one_folder, zips):
|
||||
brokenzip = '%s.1' % _zip
|
||||
|
||||
if os.path.exists(brokenzip):
|
||||
logging.info("Deleting %s", brokenzip)
|
||||
try:
|
||||
os.remove(brokenzip)
|
||||
remove_file(brokenzip)
|
||||
i += 1
|
||||
except OSError:
|
||||
logging.warning(T('Deleting %s failed!'), brokenzip)
|
||||
@@ -1024,12 +1037,12 @@ def seven_extract_core(sevenset, extensions, extraction_path, one_folder, delete
|
||||
for ext in extensions:
|
||||
path = '%s.%s' % (sevenset, ext)
|
||||
try:
|
||||
os.remove(path)
|
||||
remove_file(path)
|
||||
except:
|
||||
logging.warning(T('Deleting %s failed!'), path)
|
||||
else:
|
||||
try:
|
||||
os.remove(sevenset)
|
||||
remove_file(sevenset)
|
||||
except:
|
||||
logging.warning(T('Deleting %s failed!'), sevenset)
|
||||
|
||||
@@ -1146,9 +1159,8 @@ def par2_repair(parfile_nzf, nzo, workdir, setname, single):
|
||||
if filepath in joinables:
|
||||
joinables.remove(filepath)
|
||||
if os.path.exists(filepath):
|
||||
logging.info("Deleting %s", filepath)
|
||||
try:
|
||||
os.remove(filepath)
|
||||
remove_file(filepath)
|
||||
except OSError:
|
||||
logging.warning(T('Deleting %s failed!'), filepath)
|
||||
except:
|
||||
@@ -1331,7 +1343,6 @@ def PAR_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=False):
|
||||
if added_blocks:
|
||||
msg = T('Fetching %s blocks...') % str(added_blocks)
|
||||
nzo.set_action_line(T('Fetching'), msg)
|
||||
nzo.status = Status.FETCHING
|
||||
readd = True
|
||||
else:
|
||||
# Failed
|
||||
@@ -1503,6 +1514,11 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=False)
|
||||
# But not really required due to prospective-par2
|
||||
command = [str(MULTIPAR_COMMAND), 'r', '-vs2', '-vd%s' % parfolder, parfile]
|
||||
|
||||
# Check if there are maybe par2cmdline/par2tbb commands supplied
|
||||
if '-t' in cfg.par_option() or '-p' in cfg.par_option():
|
||||
logging.info('Removing old par2cmdline/par2tbb options for MultiPar')
|
||||
cfg.par_option.set('')
|
||||
|
||||
# Only add user-options if supplied
|
||||
options = cfg.par_option().strip()
|
||||
if options:
|
||||
@@ -1753,7 +1769,6 @@ def MultiPar_Verify(parfile, parfile_nzf, nzo, setname, joinables, single=False)
|
||||
if added_blocks:
|
||||
msg = T('Fetching %s blocks...') % str(added_blocks)
|
||||
nzo.set_action_line(T('Fetching'), msg)
|
||||
nzo.status = Status.FETCHING
|
||||
readd = True
|
||||
else:
|
||||
# Failed
|
||||
@@ -1854,6 +1869,7 @@ def create_env(nzo=None, extra_env_fields=None):
|
||||
|
||||
# Are we adding things?
|
||||
if nzo:
|
||||
# Add basic info
|
||||
for field in ENV_NZO_FIELDS:
|
||||
try:
|
||||
field_value = getattr(nzo, field)
|
||||
@@ -1863,14 +1879,18 @@ def create_env(nzo=None, extra_env_fields=None):
|
||||
elif isinstance(field_value, bool):
|
||||
env['SAB_' + field.upper()] = str(field_value*1)
|
||||
else:
|
||||
env['SAB_' + field.upper()] = str(deunicode(field_value))
|
||||
env['SAB_' + field.upper()] = str(field_value)
|
||||
except:
|
||||
# Catch key/unicode errors
|
||||
pass
|
||||
|
||||
# Add extra fields
|
||||
for field in extra_env_fields:
|
||||
try:
|
||||
env['SAB_' + field.upper()] = str(deunicode(extra_env_fields[field]))
|
||||
if extra_env_fields[field] is not None:
|
||||
env['SAB_' + field.upper()] = str(extra_env_fields[field])
|
||||
else:
|
||||
env['SAB_' + field.upper()] = ''
|
||||
except:
|
||||
# Catch key/unicode errors
|
||||
pass
|
||||
@@ -1883,6 +1903,9 @@ def create_env(nzo=None, extra_env_fields=None):
|
||||
elif not nzo:
|
||||
# No modification
|
||||
return None
|
||||
|
||||
# Have to make sure no Unicode slipped in somehow
|
||||
env = { deunicode(k): deunicode(v) for k, v in env.iteritems() }
|
||||
return env
|
||||
|
||||
|
||||
@@ -1900,8 +1923,10 @@ def userxbit(filename):
|
||||
return xbitset
|
||||
|
||||
|
||||
def build_command(command):
|
||||
""" Prepare list from running an external program """
|
||||
def build_command(command, flatten_command=False):
|
||||
""" Prepare list from running an external program
|
||||
On Windows we need to run our own list2cmdline for Unrar
|
||||
"""
|
||||
if not sabnzbd.WIN32:
|
||||
if command[0].endswith('.py'):
|
||||
with open(command[0], 'r') as script_file:
|
||||
@@ -1945,7 +1970,7 @@ def build_command(command):
|
||||
if need_shell and ' ' in command[0]:
|
||||
command[0] = win32api.GetShortPathName(command[0])
|
||||
|
||||
if need_shell:
|
||||
if need_shell or flatten_command:
|
||||
command = list2cmdline(command)
|
||||
|
||||
return stup, need_shell, command, creationflags
|
||||
@@ -1956,16 +1981,20 @@ def rar_volumelist(rarfile_path, password, known_volumes):
|
||||
and merge them with existing list, removing duplicates
|
||||
"""
|
||||
# UnRar is required to read some RAR files
|
||||
rarfile.UNRAR_TOOL = RAR_COMMAND
|
||||
zf = rarfile.RarFile(rarfile_path)
|
||||
# RarFile can fail in special cases
|
||||
try:
|
||||
rarfile.UNRAR_TOOL = RAR_COMMAND
|
||||
zf = rarfile.RarFile(rarfile_path)
|
||||
|
||||
# setpassword can fail due to bugs in RarFile
|
||||
if password:
|
||||
try:
|
||||
zf.setpassword(password)
|
||||
except:
|
||||
pass
|
||||
zf_volumes = zf.volumelist()
|
||||
# setpassword can fail due to bugs in RarFile
|
||||
if password:
|
||||
try:
|
||||
zf.setpassword(password)
|
||||
except:
|
||||
pass
|
||||
zf_volumes = zf.volumelist()
|
||||
except:
|
||||
zf_volumes = []
|
||||
|
||||
# Remove duplicates
|
||||
known_volumes_base = [os.path.basename(vol) for vol in known_volumes]
|
||||
@@ -2280,17 +2309,6 @@ def list2cmdline(lst):
|
||||
return ' '.join(nlst)
|
||||
|
||||
|
||||
def get_from_url(url):
|
||||
""" Retrieve URL and return content
|
||||
`timeout` sets non-standard timeout
|
||||
"""
|
||||
import urllib2
|
||||
try:
|
||||
return urllib2.urlopen(url).read()
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def is_sevenfile(path):
|
||||
""" Return True if path has proper extension and 7Zip is installed """
|
||||
return SEVEN_COMMAND and os.path.splitext(path)[1].lower() == '.7z'
|
||||
|
||||
@@ -27,7 +27,6 @@ import socket
|
||||
import urllib2
|
||||
import httplib
|
||||
import urllib
|
||||
import time
|
||||
import subprocess
|
||||
import json
|
||||
from threading import Thread
|
||||
@@ -134,12 +133,14 @@ def get_prio(gtype, section):
|
||||
return -1000
|
||||
|
||||
|
||||
def check_cat(section, job_cat):
|
||||
def check_cat(section, job_cat, keyword=None):
|
||||
""" Check if `job_cat` is enabled in `section`. * = All """
|
||||
if not job_cat:
|
||||
return True
|
||||
try:
|
||||
section_cats = sabnzbd.config.get_config(section, '%s_cats' % section)()
|
||||
if not keyword:
|
||||
keyword = section
|
||||
section_cats = sabnzbd.config.get_config(section, '%s_cats' % keyword)()
|
||||
return ('*' in section_cats or job_cat in section_cats)
|
||||
except TypeError:
|
||||
logging.debug('Incorrect Notify option %s:%s_cats', section, section)
|
||||
@@ -164,31 +165,26 @@ def send_notification(title, msg, gtype, job_cat=None):
|
||||
return send_local_growl(title, msg, gtype)
|
||||
else:
|
||||
Thread(target=send_growl, args=(title, msg, gtype)).start()
|
||||
time.sleep(0.5)
|
||||
|
||||
# Prowl
|
||||
if sabnzbd.cfg.prowl_enable() and check_cat('prowl', job_cat):
|
||||
if sabnzbd.cfg.prowl_apikey():
|
||||
Thread(target=send_prowl, args=(title, msg, gtype)).start()
|
||||
time.sleep(0.5)
|
||||
|
||||
# Pushover
|
||||
if sabnzbd.cfg.pushover_enable() and check_cat('pushover', job_cat):
|
||||
if sabnzbd.cfg.pushover_token():
|
||||
Thread(target=send_pushover, args=(title, msg, gtype)).start()
|
||||
time.sleep(0.5)
|
||||
|
||||
# Pushbullet
|
||||
if sabnzbd.cfg.pushbullet_enable() and check_cat('pushbullet', job_cat):
|
||||
if sabnzbd.cfg.pushbullet_apikey() and check_classes(gtype, 'pushbullet'):
|
||||
Thread(target=send_pushbullet, args=(title, msg, gtype)).start()
|
||||
time.sleep(0.5)
|
||||
|
||||
# Notification script.
|
||||
if sabnzbd.cfg.nscript_enable() and check_cat('nscript', job_cat):
|
||||
if sabnzbd.cfg.nscript_script():
|
||||
Thread(target=send_nscript, args=(title, msg, gtype)).start()
|
||||
time.sleep(0.5)
|
||||
|
||||
# NTFOSD
|
||||
if have_ntfosd() and sabnzbd.cfg.ntfosd_enable():
|
||||
@@ -443,6 +439,8 @@ def send_pushover(title, msg, gtype, force=False, test=None):
|
||||
apikey = sabnzbd.cfg.pushover_token()
|
||||
userkey = sabnzbd.cfg.pushover_userkey()
|
||||
device = sabnzbd.cfg.pushover_device()
|
||||
emergency_retry = sabnzbd.cfg.pushover_emergency_retry()
|
||||
emergency_expire = sabnzbd.cfg.pushover_emergency_expire()
|
||||
if not apikey or not userkey:
|
||||
return T('Cannot send, missing required data')
|
||||
|
||||
@@ -452,27 +450,42 @@ def send_pushover(title, msg, gtype, force=False, test=None):
|
||||
if force:
|
||||
prio = 1
|
||||
|
||||
if prio > -3:
|
||||
try:
|
||||
conn = httplib.HTTPSConnection("api.pushover.net:443")
|
||||
conn.request("POST", "/1/messages.json", urllib.urlencode({
|
||||
"token": apikey,
|
||||
"user": userkey,
|
||||
"device": device,
|
||||
"title": title,
|
||||
"message": msg,
|
||||
"priority": prio
|
||||
}), {"Content-type": "application/x-www-form-urlencoded"})
|
||||
res = conn.getresponse()
|
||||
if res.status != 200:
|
||||
logging.error(T('Bad response from Pushover (%s): %s'), res.status, res.read())
|
||||
if prio == 2:
|
||||
body = { "token": apikey,
|
||||
"user": userkey,
|
||||
"device": device,
|
||||
"title": title,
|
||||
"message": msg,
|
||||
"priority": prio,
|
||||
"retry": emergency_retry,
|
||||
"expire": emergency_expire
|
||||
}
|
||||
return do_send_pushover(body)
|
||||
if prio > -3 and prio < 2:
|
||||
body = { "token": apikey,
|
||||
"user": userkey,
|
||||
"device": device,
|
||||
"title": title,
|
||||
"message": msg,
|
||||
"priority": prio,
|
||||
}
|
||||
return do_send_pushover(body)
|
||||
|
||||
except:
|
||||
logging.warning(T('Failed to send pushover message'))
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
def do_send_pushover(body):
|
||||
try:
|
||||
conn = httplib.HTTPSConnection("api.pushover.net:443")
|
||||
conn.request("POST", "/1/messages.json", urllib.urlencode(body),
|
||||
{"Content-type": "application/x-www-form-urlencoded"})
|
||||
res = conn.getresponse()
|
||||
if res.status != 200:
|
||||
logging.error(T('Bad response from Pushover (%s): %s'), res.status, res.read())
|
||||
return T('Failed to send pushover message')
|
||||
return ''
|
||||
|
||||
else:
|
||||
return ''
|
||||
except:
|
||||
logging.warning(T('Failed to send pushover message'))
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
return T('Failed to send pushover message')
|
||||
|
||||
def send_pushbullet(title, msg, gtype, force=False, test=None):
|
||||
""" Send message to Pushbullet """
|
||||
|
||||
@@ -26,11 +26,11 @@ import datetime
|
||||
|
||||
import sabnzbd
|
||||
from sabnzbd.nzbstuff import NzbObject
|
||||
from sabnzbd.misc import exit_sab, cat_to_opts, \
|
||||
get_admin_path, remove_all, globber_full, int_conv
|
||||
from sabnzbd.misc import exit_sab, cat_to_opts, remove_file, \
|
||||
get_admin_path, remove_all, globber_full, int_conv, caller_name
|
||||
from sabnzbd.panic import panic_queue
|
||||
import sabnzbd.database as database
|
||||
from sabnzbd.decorators import notify_downloader
|
||||
from sabnzbd.decorators import NzbQueueLocker
|
||||
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, \
|
||||
@@ -43,6 +43,7 @@ from sabnzbd.assembler import Assembler, file_has_articles
|
||||
import sabnzbd.notifier as notifier
|
||||
from sabnzbd.encoding import platform_encode
|
||||
from sabnzbd.bpsmeter import BPSMeter
|
||||
from sabnzbd.dirscanner import ProcessSingleFile
|
||||
|
||||
|
||||
class NzbQueue(object):
|
||||
@@ -99,7 +100,7 @@ class NzbQueue(object):
|
||||
self.add(nzo, save=True)
|
||||
else:
|
||||
try:
|
||||
os.remove(item)
|
||||
remove_file(item)
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -139,7 +140,7 @@ class NzbQueue(object):
|
||||
|
||||
# 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)
|
||||
remove_file(item)
|
||||
|
||||
# Done converting
|
||||
cfg.converted_nzo_pickles.set(True)
|
||||
@@ -147,6 +148,7 @@ class NzbQueue(object):
|
||||
nzo_ids = []
|
||||
return nzo_ids
|
||||
|
||||
@NzbQueueLocker
|
||||
def scan_jobs(self, all=False, action=True):
|
||||
""" Scan "incomplete" for missing folders,
|
||||
'all' is True: Include active folders
|
||||
@@ -230,7 +232,6 @@ class NzbQueue(object):
|
||||
|
||||
return nzo_id
|
||||
|
||||
@notify_downloader
|
||||
def send_back(self, nzo):
|
||||
""" Send back job to queue after successful pre-check """
|
||||
try:
|
||||
@@ -238,13 +239,14 @@ class NzbQueue(object):
|
||||
except:
|
||||
logging.debug('Failed to find NZB file after pre-check (%s)', nzo.nzo_id)
|
||||
return
|
||||
from sabnzbd.dirscanner import ProcessSingleFile
|
||||
|
||||
res, nzo_ids = ProcessSingleFile(nzo.work_name + '.nzb', nzb_path, keep=True, reuse=True)
|
||||
if res == 0 and nzo_ids:
|
||||
nzo = self.replace_in_q(nzo, nzo_ids[0])
|
||||
# Reset reuse flag to make pause/abort on encryption possible
|
||||
nzo.reuse = False
|
||||
|
||||
@NzbQueueLocker
|
||||
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
|
||||
@@ -269,6 +271,7 @@ class NzbQueue(object):
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
return nzo
|
||||
|
||||
@NzbQueueLocker
|
||||
def save(self, save_nzo=None):
|
||||
""" Save queue, all nzo's or just the specified one """
|
||||
logging.info("Saving queue")
|
||||
@@ -350,7 +353,7 @@ class NzbQueue(object):
|
||||
else:
|
||||
return None
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def add(self, nzo, save=True, quiet=False):
|
||||
if not nzo.nzo_id:
|
||||
nzo.nzo_id = sabnzbd.get_new_id('nzo', nzo.workpath, self.__nzo_table)
|
||||
@@ -406,6 +409,7 @@ class NzbQueue(object):
|
||||
self.sort_by_avg_age()
|
||||
return nzo.nzo_id
|
||||
|
||||
@NzbQueueLocker
|
||||
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)
|
||||
@@ -427,7 +431,7 @@ class NzbQueue(object):
|
||||
self.cleanup_nzo(nzo, keep_basic, del_files)
|
||||
|
||||
sabnzbd.remove_data(nzo_id, nzo.workpath)
|
||||
logging.info('Removed job %s', nzo.final_name)
|
||||
logging.info('[%s] Removed job %s', caller_name(), nzo.final_name)
|
||||
if save:
|
||||
self.save(nzo)
|
||||
else:
|
||||
@@ -449,6 +453,7 @@ class NzbQueue(object):
|
||||
|
||||
return removed
|
||||
|
||||
@NzbQueueLocker
|
||||
def remove_all(self, search=None):
|
||||
if search:
|
||||
search = search.lower()
|
||||
@@ -511,7 +516,7 @@ class NzbQueue(object):
|
||||
handled.append(nzo_id)
|
||||
return handled
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def resume_nzo(self, nzo_id):
|
||||
handled = []
|
||||
if nzo_id in self.__nzo_table:
|
||||
@@ -522,6 +527,7 @@ class NzbQueue(object):
|
||||
handled.append(nzo_id)
|
||||
return handled
|
||||
|
||||
@NzbQueueLocker
|
||||
def switch(self, item_id_1, item_id_2):
|
||||
try:
|
||||
# Allow an index as second parameter, easier for some skins
|
||||
@@ -570,32 +576,39 @@ class NzbQueue(object):
|
||||
# If moving failed/no movement took place
|
||||
return (-1, nzo1.priority)
|
||||
|
||||
@NzbQueueLocker
|
||||
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)
|
||||
|
||||
@NzbQueueLocker
|
||||
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)
|
||||
|
||||
@NzbQueueLocker
|
||||
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)
|
||||
|
||||
@NzbQueueLocker
|
||||
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)
|
||||
|
||||
@NzbQueueLocker
|
||||
def sort_by_avg_age(self, reverse=False):
|
||||
logging.info("Sorting by average date... (reversed:%s)", reverse)
|
||||
self.__nzo_list = sort_queue_function(self.__nzo_list, _nzo_date_cmp, reverse)
|
||||
|
||||
@NzbQueueLocker
|
||||
def sort_by_name(self, reverse=False):
|
||||
logging.info("Sorting by name... (reversed:%s)", reverse)
|
||||
self.__nzo_list = sort_queue_function(self.__nzo_list, _nzo_name_cmp, reverse)
|
||||
|
||||
@NzbQueueLocker
|
||||
def sort_by_size(self, reverse=False):
|
||||
logging.info("Sorting by size... (reversed:%s)", reverse)
|
||||
self.__nzo_list = sort_queue_function(self.__nzo_list, _nzo_size_cmp, reverse)
|
||||
@@ -617,6 +630,7 @@ class NzbQueue(object):
|
||||
else:
|
||||
logging.debug("Sort: %s not recognized", field)
|
||||
|
||||
@NzbQueueLocker
|
||||
def __set_priority(self, nzo_id, priority):
|
||||
""" Sets the priority on the nzo and places it in the queue at the appropriate position """
|
||||
try:
|
||||
@@ -689,7 +703,7 @@ class NzbQueue(object):
|
||||
except:
|
||||
return -1
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def set_priority(self, nzo_ids, priority):
|
||||
try:
|
||||
n = -1
|
||||
@@ -719,6 +733,9 @@ class NzbQueue(object):
|
||||
return False
|
||||
|
||||
def get_article(self, server, servers):
|
||||
""" Get next article for jobs in the queue
|
||||
Not locked for performance, since it only reads the queue
|
||||
"""
|
||||
for nzo in self.__nzo_list:
|
||||
# Not when queue paused and not a forced item
|
||||
if nzo.status not in (Status.PAUSED, Status.GRABBING) or nzo.priority == TOP_PRIORITY:
|
||||
@@ -733,6 +750,9 @@ class NzbQueue(object):
|
||||
return
|
||||
|
||||
def register_article(self, article, found=True):
|
||||
""" Register the articles we tried
|
||||
Not locked for performance, since it only modifies individual NZOs
|
||||
"""
|
||||
nzf = article.nzf
|
||||
nzo = nzf.nzo
|
||||
|
||||
@@ -773,7 +793,7 @@ class NzbQueue(object):
|
||||
|
||||
def end_job(self, nzo):
|
||||
""" Send NZO to the post-processing queue """
|
||||
logging.info('Ending job %s', nzo.final_name)
|
||||
logging.info('[%s] Ending job %s', caller_name(), nzo.final_name)
|
||||
|
||||
# Notify assembler to call postprocessor
|
||||
if not nzo.deleted:
|
||||
@@ -793,7 +813,9 @@ class NzbQueue(object):
|
||||
Assembler.do.process((nzo, None))
|
||||
|
||||
def actives(self, grabs=True):
|
||||
""" Return amount of non-paused jobs, optionally with 'grabbing' items """
|
||||
""" Return amount of non-paused jobs, optionally with 'grabbing' items
|
||||
Not locked for performance, only reads the queue
|
||||
"""
|
||||
n = 0
|
||||
for nzo in self.__nzo_list:
|
||||
# Ignore any items that are paused
|
||||
@@ -806,6 +828,7 @@ class NzbQueue(object):
|
||||
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.
|
||||
Not locked for performance, only reads the queue
|
||||
"""
|
||||
if search:
|
||||
search = search.lower()
|
||||
@@ -836,7 +859,9 @@ class NzbQueue(object):
|
||||
return QNFO(bytes_total, bytes_left, bytes_left_previous_page, pnfo_list, q_size, n)
|
||||
|
||||
def remaining(self):
|
||||
""" Return bytes left in the queue by non-paused items """
|
||||
""" Return bytes left in the queue by non-paused items
|
||||
Not locked for performance, only reads the queue
|
||||
"""
|
||||
bytes_left = 0
|
||||
for nzo in self.__nzo_list:
|
||||
if nzo.status != 'Paused':
|
||||
@@ -862,6 +887,7 @@ class NzbQueue(object):
|
||||
empty = []
|
||||
for nzo in self.__nzo_list:
|
||||
if not nzo.futuretype and not nzo.files and nzo.status not in (Status.PAUSED, Status.GRABBING):
|
||||
logging.info('Found idle job %s', nzo.final_name)
|
||||
empty.append(nzo)
|
||||
|
||||
# Stall prevention by checking if all servers are in the trylist
|
||||
@@ -871,8 +897,11 @@ class NzbQueue(object):
|
||||
for nzf in nzo.files:
|
||||
if len(nzf.try_list) == sabnzbd.downloader.Downloader.do.server_nr:
|
||||
# We do not want to reset all article trylists, they are good
|
||||
logging.info('Resetting bad trylist for file %s in job %s', nzf.filename, nzo.final_name)
|
||||
nzf.reset_try_list()
|
||||
|
||||
# Reset main trylist, minimal performance impact
|
||||
logging.info('Resetting bad trylist for job %s', nzo.final_name)
|
||||
nzo.reset_try_list()
|
||||
|
||||
for nzo in empty:
|
||||
@@ -883,7 +912,7 @@ class NzbQueue(object):
|
||||
if nzo.priority == priority:
|
||||
nzo.pause()
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def resume_on_prio(self, priority):
|
||||
for nzo in self.__nzo_list:
|
||||
if nzo.priority == priority:
|
||||
@@ -895,7 +924,7 @@ class NzbQueue(object):
|
||||
if nzo.cat == cat:
|
||||
nzo.pause()
|
||||
|
||||
@notify_downloader
|
||||
@NzbQueueLocker
|
||||
def resume_on_cat(self, cat):
|
||||
for nzo in self.__nzo_list:
|
||||
if nzo.cat == cat:
|
||||
|
||||
@@ -47,7 +47,7 @@ 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, \
|
||||
int_conv, set_permissions, format_time_string, long_path, trim_win_path, \
|
||||
fix_unix_encoding, calc_age, is_obfuscated_filename, get_ext, get_filename, \
|
||||
get_unique_filename, renamer
|
||||
get_unique_filename, renamer, remove_file, remove_dir
|
||||
from sabnzbd.decorators import synchronized
|
||||
import sabnzbd.config as config
|
||||
import sabnzbd.cfg as cfg
|
||||
@@ -289,10 +289,10 @@ class NzbFile(TryList):
|
||||
elif not self.nzo.is_gone():
|
||||
# TEMPORARY ERRORS
|
||||
if not os.path.exists(os.path.join(self.nzf_id, self.nzo.workpath)):
|
||||
logging.warning('Article DB file not found %s', self)
|
||||
logging.warning('Article DB file not found %s: %s', self.nzf_id, self)
|
||||
else:
|
||||
# It was there, but empty
|
||||
logging.warning('Article DB empty %s', self)
|
||||
logging.warning('Article DB empty %s: %s', self.nzf_id, self)
|
||||
|
||||
def remove_article(self, article, found):
|
||||
""" Handle completed article, possibly end of file """
|
||||
@@ -337,7 +337,8 @@ class NzbFile(TryList):
|
||||
def remove_admin(self):
|
||||
""" Remove article database from disk (sabnzbd_nzf_<id>)"""
|
||||
try:
|
||||
os.remove(os.path.join(self.nzo.workpath, self.nzf_id))
|
||||
logging.debug('Removing article database for %s', self.nzf_id)
|
||||
remove_file(os.path.join(self.nzo.workpath, self.nzf_id))
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -511,7 +512,7 @@ class NzbParser(xml.sax.handler.ContentHandler):
|
||||
self.nzf_list.remove(nzo_matches[0])
|
||||
|
||||
if nzf.valid and nzf.nzf_id:
|
||||
logging.info('File %s added to queue', self.filename)
|
||||
logging.info('File %s - %s added to queue', nzf.filename, nzf.nzf_id)
|
||||
self.nzo.files.append(nzf)
|
||||
self.nzo.files_table[nzf.nzf_id] = nzf
|
||||
self.nzo.bytes += nzf.bytes
|
||||
@@ -571,7 +572,6 @@ NZO_LOCK = threading.RLock()
|
||||
|
||||
class NzbObject(TryList):
|
||||
|
||||
@synchronized(NZO_LOCK)
|
||||
def __init__(self, filename, pp, script, nzb=None,
|
||||
futuretype=False, cat=None, url=None,
|
||||
priority=NORMAL_PRIORITY, nzbname=None, status="Queued", nzo_info=None,
|
||||
@@ -606,8 +606,9 @@ class NzbObject(TryList):
|
||||
# In case only /password was entered for nzbname
|
||||
work_name = filename
|
||||
|
||||
self.work_name = work_name
|
||||
self.final_name = work_name
|
||||
# Remove trailing .nzb and .par(2)
|
||||
self.work_name = create_work_name(work_name)
|
||||
self.final_name = create_work_name(work_name)
|
||||
|
||||
self.meta = {}
|
||||
self.servercount = {} # Dict to keep bytes per server
|
||||
@@ -618,7 +619,7 @@ class NzbObject(TryList):
|
||||
self.bytes_tried = 0 # Which bytes did we try
|
||||
self.bytes_missing = 0 # Bytes missing
|
||||
self.bad_articles = 0 # How many bad (non-recoverable) articles
|
||||
self.set_priority(priority) # Parse priority
|
||||
self.set_priority(priority) # Parse priority of input
|
||||
self.repair = r # True if we want to repair this set
|
||||
self.unpack = u # True if we want to unpack this set
|
||||
self.delete = d # True if we want to delete this set
|
||||
@@ -692,9 +693,6 @@ class NzbObject(TryList):
|
||||
self.pp_active = False # Signals active post-processing (not saved)
|
||||
self.md5sum = None
|
||||
|
||||
# Remove trailing .nzb and .par(2)
|
||||
self.work_name = create_work_name(self.work_name)
|
||||
|
||||
if nzb is None:
|
||||
# This is a slot for a future NZB, ready now
|
||||
return
|
||||
@@ -807,7 +805,7 @@ class NzbObject(TryList):
|
||||
self.repair, self.unpack, self.delete = sabnzbd.pp_to_opts(pp_tmp)
|
||||
|
||||
# Run user pre-queue script if needed
|
||||
if not reuse:
|
||||
if not reuse and cfg.pre_script():
|
||||
accept, name, pp, cat, script, priority, group = \
|
||||
sabnzbd.newsunpack.pre_queue(self.final_name_pw_clean, pp, cat, script,
|
||||
priority, self.bytes, self.groups)
|
||||
@@ -816,6 +814,10 @@ class NzbObject(TryList):
|
||||
pp = int(pp)
|
||||
except:
|
||||
pp = None
|
||||
try:
|
||||
priority = int(priority)
|
||||
except:
|
||||
priority = DEFAULT_PRIORITY
|
||||
if accept < 1:
|
||||
self.purge_data()
|
||||
raise TypeError
|
||||
@@ -827,7 +829,7 @@ class NzbObject(TryList):
|
||||
self.fail_msg = T('Pre-queue script marked job as failed')
|
||||
|
||||
# Re-evaluate results from pre-queue script
|
||||
self.cat, pp, self.script, priority = cat_to_opts(cat, pp, script, int_conv(priority))
|
||||
self.cat, pp, self.script, priority = cat_to_opts(cat, pp, script, priority)
|
||||
self.set_priority(priority)
|
||||
self.repair, self.unpack, self.delete = sabnzbd.pp_to_opts(pp)
|
||||
else:
|
||||
@@ -1228,10 +1230,20 @@ class NzbObject(TryList):
|
||||
|
||||
def set_priority(self, value):
|
||||
""" Check if this is a valid priority """
|
||||
# When unknown (0 is a known one), set to DEFAULT
|
||||
if value == '' or value is None:
|
||||
self.priority = DEFAULT_PRIORITY
|
||||
return
|
||||
|
||||
# Convert input
|
||||
value = int_conv(value)
|
||||
if value in (REPAIR_PRIORITY, TOP_PRIORITY, HIGH_PRIORITY, NORMAL_PRIORITY, \
|
||||
LOW_PRIORITY, DEFAULT_PRIORITY, PAUSED_PRIORITY, DUP_PRIORITY, STOP_PRIORITY):
|
||||
self.priority = value
|
||||
return
|
||||
|
||||
# Invalid value, set to normal priority
|
||||
self.priority = NORMAL_PRIORITY
|
||||
|
||||
@property
|
||||
def final_name_labeled(self):
|
||||
@@ -1461,7 +1473,7 @@ class NzbObject(TryList):
|
||||
if not nzf.import_finished and not self.is_gone():
|
||||
logging.error(T('Error importing %s'), nzf)
|
||||
nzf_remove_list.append(nzf)
|
||||
nzf.nzo.pause()
|
||||
nzf.nzo.status = Status.PAUSED
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
@@ -1473,8 +1485,8 @@ 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:
|
||||
sabnzbd.NzbQueue.do.end_job(self)
|
||||
@@ -1655,14 +1667,14 @@ class NzbObject(TryList):
|
||||
remove_all(wpath, 'SABnzbd_nz?_*', keep_folder=True)
|
||||
remove_all(wpath, 'SABnzbd_article_*', keep_folder=True)
|
||||
# We save the renames file
|
||||
sabnzbd.save_data(self.renames, RENAMES_FILE, self.workpath)
|
||||
sabnzbd.save_data(self.renames, RENAMES_FILE, self.workpath, silent=True)
|
||||
else:
|
||||
remove_all(wpath, recursive=True)
|
||||
if del_files:
|
||||
remove_all(self.downpath, recursive=True)
|
||||
else:
|
||||
try:
|
||||
os.rmdir(self.downpath)
|
||||
remove_dir(self.downpath)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ sabnzbd.panic - Send panic message to the browser
|
||||
import os
|
||||
import logging
|
||||
import tempfile
|
||||
import ctypes
|
||||
try:
|
||||
import webbrowser
|
||||
except ImportError:
|
||||
@@ -29,6 +30,7 @@ except ImportError:
|
||||
|
||||
import sabnzbd
|
||||
import sabnzbd.cfg as cfg
|
||||
from sabnzbd.encoding import unicoder
|
||||
|
||||
PANIC_PORT = 1
|
||||
PANIC_TEMPL = 2
|
||||
@@ -164,7 +166,7 @@ def panic_message(panic, a=None, b=None):
|
||||
|
||||
|
||||
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))
|
||||
show_error_dialog("\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))
|
||||
|
||||
|
||||
@@ -185,7 +187,7 @@ def panic_sqlite(name):
|
||||
|
||||
|
||||
def panic(reason, remedy=""):
|
||||
print "\n%s:\n %s\n%s" % (T('Fatal error'), reason, remedy)
|
||||
show_error_dialog("\n%s:\n %s\n%s" % (T('Fatal error'), reason, remedy))
|
||||
launch_a_browser(panic_message(PANIC_OTHER, reason, remedy))
|
||||
|
||||
|
||||
@@ -217,6 +219,15 @@ def launch_a_browser(url, force=False):
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
|
||||
|
||||
def show_error_dialog(msg):
|
||||
""" Show a pop-up when program cannot start
|
||||
Windows-only, otherwise only print to console
|
||||
"""
|
||||
if sabnzbd.WIN32:
|
||||
ctypes.windll.user32.MessageBoxW(0, unicoder(msg), T('Fatal error'), 0)
|
||||
print msg
|
||||
|
||||
|
||||
def error_page_401(status, message, traceback, version):
|
||||
""" Custom handler for 401 error """
|
||||
title = T('Access denied')
|
||||
|
||||
@@ -24,7 +24,6 @@ import Queue
|
||||
import logging
|
||||
import sabnzbd
|
||||
import xml.sax.saxutils
|
||||
import xml.etree.ElementTree
|
||||
import time
|
||||
import re
|
||||
|
||||
@@ -35,7 +34,7 @@ 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, fix_unix_encoding, \
|
||||
sanitize_and_trim_path, sanitize_files_in_folder
|
||||
sanitize_and_trim_path, sanitize_files_in_folder, remove_file
|
||||
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
|
||||
@@ -168,6 +167,13 @@ class PostProcessor(Thread):
|
||||
else:
|
||||
logging.info("Completed Download Folder %s is not on FAT", complete_dir)
|
||||
|
||||
# Check on Windows if we have unicode-subprocess
|
||||
if sabnzbd.WIN32:
|
||||
try:
|
||||
import subprocessww
|
||||
except ImportError:
|
||||
logging.warning(T('Module subprocessww missing. Expect problems with Unicoded file and directory names in downloads.'))
|
||||
|
||||
# Start looping
|
||||
check_eoq = False
|
||||
while not self.__stop:
|
||||
@@ -213,6 +219,9 @@ class PostProcessor(Thread):
|
||||
history_db.close()
|
||||
nzo.purge_data(keep_basic=False, del_files=True)
|
||||
|
||||
# Processing done
|
||||
nzo.pp_active = False
|
||||
|
||||
self.remove(nzo)
|
||||
check_eoq = True
|
||||
|
||||
@@ -563,7 +572,7 @@ def process_job(nzo):
|
||||
def prepare_extraction_path(nzo):
|
||||
""" Based on the information that we have, generate
|
||||
the extraction path and create the directory.
|
||||
Seperated so it can be called from DirectUnpacker
|
||||
Separated so it can be called from DirectUnpacker
|
||||
"""
|
||||
one_folder = False
|
||||
marker_file = None
|
||||
@@ -668,6 +677,7 @@ def parring(nzo, workdir):
|
||||
logging.info('Re-added %s to queue', filename)
|
||||
if nzo.priority != TOP_PRIORITY:
|
||||
nzo.priority = REPAIR_PRIORITY
|
||||
nzo.status = Status.FETCHING
|
||||
sabnzbd.nzbqueue.NzbQueue.do.add(nzo)
|
||||
sabnzbd.downloader.Downloader.do.resume_from_postproc()
|
||||
|
||||
@@ -796,7 +806,7 @@ def cleanup_list(wdir, skip_nzb):
|
||||
if on_cleanup_list(filename, skip_nzb):
|
||||
try:
|
||||
logging.info("Removing unwanted file %s", path)
|
||||
os.remove(path)
|
||||
remove_file(path)
|
||||
except:
|
||||
logging.error(T('Removing %s failed'), clip_path(path))
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
@@ -876,7 +886,7 @@ def remove_samples(path):
|
||||
path = os.path.join(root, file_)
|
||||
try:
|
||||
logging.info("Removing unwanted sample file %s", path)
|
||||
os.remove(path)
|
||||
remove_file(path)
|
||||
except:
|
||||
logging.error(T('Removing %s failed'), clip_path(path))
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
@@ -929,7 +939,7 @@ def del_marker(path):
|
||||
if path and os.path.exists(path):
|
||||
logging.debug('Removing marker file %s', path)
|
||||
try:
|
||||
os.remove(path)
|
||||
remove_file(path)
|
||||
except:
|
||||
logging.info('Cannot remove marker file %s', path)
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
|
||||
@@ -384,8 +384,6 @@ class RSSQueue(object):
|
||||
n = 0
|
||||
if ('F' in reTypes or 'S' in reTypes) and (not season or not episode):
|
||||
season, episode = sabnzbd.newsunpack.analyse_show(title)[1:3]
|
||||
season = int_conv(season)
|
||||
episode = int_conv(episode)
|
||||
|
||||
# Match against all filters until an positive or negative match
|
||||
logging.debug('Size %s', size)
|
||||
@@ -717,8 +715,11 @@ def ep_match(season, episode, expr, title=None):
|
||||
"""
|
||||
m = _RE_SP.search(expr)
|
||||
if m:
|
||||
# Make sure they are all integers for comparison
|
||||
req_season = int(m.group(1))
|
||||
req_episode = int(m.group(2))
|
||||
season = int_conv(season)
|
||||
episode = int_conv(episode)
|
||||
if season > req_season or (season == req_season and episode >= req_episode):
|
||||
if title:
|
||||
show = expr[:m.start()].replace('.', ' ').replace('_', ' ').strip()
|
||||
|
||||
@@ -110,6 +110,14 @@ class SABTrayThread(SysTrayIconThread):
|
||||
self.refresh_icon()
|
||||
self.counter = 0
|
||||
|
||||
# left-click handler
|
||||
def click(self, *args):
|
||||
# Make sure to stop the timer
|
||||
self.stop_click_timer()
|
||||
# Pause/resume and force update of icon/text
|
||||
self.pauseresume(None)
|
||||
self.counter = 11
|
||||
|
||||
# menu handler
|
||||
def opencomplete(self, icon):
|
||||
try:
|
||||
|
||||
@@ -666,6 +666,10 @@ SKIN_TEXT = {
|
||||
'explain-pushover_userkey' : TT('User Key (required)'), #: Pushover settings
|
||||
'opt-pushover_device' : TT('Device(s)'), #: Pushover settings
|
||||
'explain-pushover_device' : TT('Device(s) to which message should be sent'), #: Pushover settings
|
||||
'opt-pushover_emergency_retry' : TT('Emergency retry'), #: Pushover settings
|
||||
'explain-pushover_emergency_retry' : TT('How often (in seconds) the same notification will be sent'), #: Pushover settings
|
||||
'opt-pushover_emergency_expire' : TT('Emergency expire'), #: Pushover settings
|
||||
'explain-pushover_emergency_expire' : TT('How many seconds your notification will continue to be retried'), #: Pushover settings
|
||||
'section-Pushbullet' : TT('Pushbullet'), #: Header for Pushbullet notification section
|
||||
'opt-pushbullet_enable' : TT('Enable Pushbullet notifications'), #: Pushbullet settings
|
||||
'explain-pushbullet_enable' : TT('Requires a Pushbullet account'), #: Pushbulletsettings
|
||||
|
||||
@@ -38,7 +38,7 @@ RE_SAMPLE = re.compile(sample_match, re.I)
|
||||
EXCLUDED_FILE_EXTS = ('.vob', '.bin')
|
||||
|
||||
LOWERCASE = ('the', 'of', 'and', 'at', 'vs', 'a', 'an', 'but', 'nor', 'for', 'on',
|
||||
'so', 'yet')
|
||||
'so', 'yet', 'with')
|
||||
UPPERCASE = ('III', 'II', 'IV')
|
||||
|
||||
REPLACE_AFTER = {
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
## Fixing python 2.7 windows unicode issue with ``subprocess.Popen``.
|
||||
|
||||
## Copied from
|
||||
## http://vaab.blog.kal.fr/2017/03/16/fixing-windows-python-2-7-unicode-issue-with-subprocesss-popen/
|
||||
## https://gist.github.com/vaab/2ad7051fc193167f15f85ef573e54eb9
|
||||
|
||||
## issue: https://bugs.python.org/issue19264
|
||||
import os
|
||||
import time
|
||||
import ctypes
|
||||
import subprocess
|
||||
import _subprocess
|
||||
from ctypes import byref, windll, c_char_p, c_wchar_p, c_void_p, \
|
||||
Structure, sizeof, c_wchar, WinError
|
||||
from ctypes.wintypes import BYTE, WORD, LPWSTR, BOOL, DWORD, LPVOID, \
|
||||
HANDLE
|
||||
|
||||
|
||||
##
|
||||
## Special counter because this function cannot
|
||||
## be called within 1 second from each other!
|
||||
##
|
||||
_NEXT_PROCESS_START = 0.0
|
||||
|
||||
|
||||
##
|
||||
## Types
|
||||
##
|
||||
|
||||
CREATE_UNICODE_ENVIRONMENT = 0x00000400
|
||||
LPCTSTR = c_char_p
|
||||
LPTSTR = c_wchar_p
|
||||
LPSECURITY_ATTRIBUTES = c_void_p
|
||||
LPBYTE = ctypes.POINTER(BYTE)
|
||||
|
||||
class STARTUPINFOW(Structure):
|
||||
_fields_ = [
|
||||
("cb", DWORD), ("lpReserved", LPWSTR),
|
||||
("lpDesktop", LPWSTR), ("lpTitle", LPWSTR),
|
||||
("dwX", DWORD), ("dwY", DWORD),
|
||||
("dwXSize", DWORD), ("dwYSize", DWORD),
|
||||
("dwXCountChars", DWORD), ("dwYCountChars", DWORD),
|
||||
("dwFillAtrribute", DWORD), ("dwFlags", DWORD),
|
||||
("wShowWindow", WORD), ("cbReserved2", WORD),
|
||||
("lpReserved2", LPBYTE), ("hStdInput", HANDLE),
|
||||
("hStdOutput", HANDLE), ("hStdError", HANDLE),
|
||||
]
|
||||
|
||||
LPSTARTUPINFOW = ctypes.POINTER(STARTUPINFOW)
|
||||
|
||||
|
||||
class PROCESS_INFORMATION(Structure):
|
||||
_fields_ = [
|
||||
("hProcess", HANDLE), ("hThread", HANDLE),
|
||||
("dwProcessId", DWORD), ("dwThreadId", DWORD),
|
||||
]
|
||||
|
||||
LPPROCESS_INFORMATION = ctypes.POINTER(PROCESS_INFORMATION)
|
||||
|
||||
|
||||
class DUMMY_HANDLE(ctypes.c_void_p):
|
||||
|
||||
def __init__(self, *a, **kw):
|
||||
super(DUMMY_HANDLE, self).__init__(*a, **kw)
|
||||
self.closed = False
|
||||
|
||||
def Close(self):
|
||||
if not self.closed:
|
||||
windll.kernel32.CloseHandle(self)
|
||||
self.closed = True
|
||||
|
||||
def __int__(self):
|
||||
return self.value
|
||||
|
||||
|
||||
CreateProcessW = windll.kernel32.CreateProcessW
|
||||
CreateProcessW.argtypes = [
|
||||
LPCTSTR, LPTSTR, LPSECURITY_ATTRIBUTES,
|
||||
LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCTSTR,
|
||||
LPSTARTUPINFOW, LPPROCESS_INFORMATION,
|
||||
]
|
||||
CreateProcessW.restype = BOOL
|
||||
|
||||
|
||||
##
|
||||
## Patched functions/classes
|
||||
##
|
||||
|
||||
def CreateProcess(executable, args, _p_attr, _t_attr,
|
||||
inherit_handles, creation_flags, env, cwd,
|
||||
startup_info):
|
||||
"""Create a process supporting unicode executable and args for win32
|
||||
|
||||
Python implementation of CreateProcess using CreateProcessW for Win32
|
||||
|
||||
"""
|
||||
# Do we need to delay?
|
||||
global _NEXT_PROCESS_START
|
||||
diff_start = _NEXT_PROCESS_START - time.time()
|
||||
if(diff_start > 0.0):
|
||||
# Wait ourselves and make sure others also wait
|
||||
_NEXT_PROCESS_START += 1.0
|
||||
time.sleep(diff_start)
|
||||
else:
|
||||
_NEXT_PROCESS_START = time.time() + 1.0
|
||||
|
||||
si = STARTUPINFOW(
|
||||
dwFlags=startup_info.dwFlags,
|
||||
wShowWindow=startup_info.wShowWindow,
|
||||
cb=sizeof(STARTUPINFOW),
|
||||
)
|
||||
|
||||
# Only cast to ints when it's given
|
||||
if startup_info.hStdInput:
|
||||
si.hStdInput = int(startup_info.hStdInput)
|
||||
if startup_info.hStdOutput:
|
||||
si.hStdOutput = int(startup_info.hStdOutput)
|
||||
if startup_info.hStdError:
|
||||
si.hStdError = int(startup_info.hStdError)
|
||||
|
||||
wenv = None
|
||||
if env is not None:
|
||||
## LPCWSTR seems to be c_wchar_p, so let's say CWSTR is c_wchar
|
||||
env = (unicode("").join([
|
||||
unicode("%s=%s\0") % (k, v)
|
||||
for k, v in env.items()])) + unicode("\0")
|
||||
wenv = (c_wchar * len(env))()
|
||||
wenv.value = env
|
||||
|
||||
pi = PROCESS_INFORMATION()
|
||||
creation_flags |= CREATE_UNICODE_ENVIRONMENT
|
||||
|
||||
if CreateProcessW(executable, args, None, None,
|
||||
inherit_handles, creation_flags,
|
||||
wenv, cwd, byref(si), byref(pi)):
|
||||
return (DUMMY_HANDLE(pi.hProcess), DUMMY_HANDLE(pi.hThread),
|
||||
pi.dwProcessId, pi.dwThreadId)
|
||||
raise WinError()
|
||||
|
||||
|
||||
class Popen(subprocess.Popen):
|
||||
"""This superseeds Popen and corrects a bug in cPython 2.7 implem"""
|
||||
|
||||
def _execute_child(self, args, executable, preexec_fn, close_fds,
|
||||
cwd, env, universal_newlines,
|
||||
startupinfo, creationflags, shell, to_close,
|
||||
p2cread, p2cwrite,
|
||||
c2pread, c2pwrite,
|
||||
errread, errwrite):
|
||||
"""Code from part of _execute_child from Python 2.7 (9fbb65e)
|
||||
|
||||
There are only 2 little changes concerning the construction of
|
||||
the the final string in shell mode: we preempt the creation of
|
||||
the command string when shell is True, because original function
|
||||
will try to encode unicode args which we want to avoid to be able to
|
||||
sending it as-is to ``CreateProcess``.
|
||||
|
||||
"""
|
||||
if not isinstance(args, subprocess.types.StringTypes):
|
||||
args = subprocess.list2cmdline(args)
|
||||
|
||||
if startupinfo is None:
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
if shell:
|
||||
startupinfo.dwFlags |= _subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = _subprocess.SW_HIDE
|
||||
comspec = os.environ.get("COMSPEC", unicode("cmd.exe"))
|
||||
args = unicode('{} /c "{}"').format(comspec, args)
|
||||
if (_subprocess.GetVersion() >= 0x80000000 or
|
||||
os.path.basename(comspec).lower() == "command.com"):
|
||||
w9xpopen = self._find_w9xpopen()
|
||||
args = unicode('"%s" %s') % (w9xpopen, args)
|
||||
creationflags |= _subprocess.CREATE_NEW_CONSOLE
|
||||
|
||||
super(Popen, self)._execute_child(args, executable,
|
||||
preexec_fn, close_fds, cwd, env, universal_newlines,
|
||||
startupinfo, creationflags, False, to_close, p2cread,
|
||||
p2cwrite, c2pread, c2pwrite, errread, errwrite)
|
||||
|
||||
_subprocess.CreateProcess = CreateProcess
|
||||
@@ -4,12 +4,14 @@
|
||||
# http://www.brunningonline.net/simon/blog/archives/SysTrayIcon.py.html
|
||||
# modified on 2011-10-04 by Jan Schejbal to support threading and preload icons
|
||||
# override doUpdates to perform actions inside the icon thread
|
||||
# override click to perform actions when left-clicking the icon
|
||||
|
||||
import os
|
||||
import pywintypes
|
||||
import win32api
|
||||
import win32con
|
||||
import win32gui_struct
|
||||
import timer
|
||||
try:
|
||||
import winxpgui as win32gui
|
||||
except ImportError:
|
||||
@@ -45,6 +47,7 @@ class SysTrayIconThread(Thread):
|
||||
self.menu_actions_by_id = dict(self.menu_actions_by_id)
|
||||
del self._next_action_id
|
||||
|
||||
self.click_timer = None
|
||||
self.default_menu_index = (default_menu_index or 0)
|
||||
self.window_class_name = window_class_name or "SysTrayIconPy"
|
||||
|
||||
@@ -89,7 +92,7 @@ class SysTrayIconThread(Thread):
|
||||
sleep(0.100)
|
||||
win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, (self.hwnd, 0))
|
||||
|
||||
# override this
|
||||
# Override this
|
||||
def doUpdates(self):
|
||||
pass
|
||||
|
||||
@@ -175,12 +178,18 @@ class SysTrayIconThread(Thread):
|
||||
win32gui.PostQuitMessage(0) # Terminate the app.
|
||||
|
||||
def notify(self, hwnd, msg, wparam, lparam):
|
||||
# Double click is actually 1 single click followed
|
||||
# by a double-click event, no way to differentiate
|
||||
# So we need a timed callback to cancel
|
||||
if lparam == win32con.WM_LBUTTONDBLCLK:
|
||||
self.execute_menu_option(self.default_menu_index + self.FIRST_ID)
|
||||
self.stop_click_timer()
|
||||
elif lparam == win32con.WM_RBUTTONUP:
|
||||
self.show_menu()
|
||||
elif lparam == win32con.WM_LBUTTONUP:
|
||||
pass
|
||||
elif lparam == win32con.WM_LBUTTONDOWN:
|
||||
# Wrapper of win32api, timeout is in ms
|
||||
# We need to wait at least untill what user has defined as double click
|
||||
self.click_timer = timer.set_timer(win32gui.GetDoubleClickTime(), self.click)
|
||||
return True
|
||||
|
||||
def show_menu(self):
|
||||
@@ -204,6 +213,17 @@ class SysTrayIconThread(Thread):
|
||||
# Weird PyWin/win32gui bug, just ignore it for now
|
||||
pass
|
||||
|
||||
# Override this for left-click action
|
||||
# Need to call the stop-timer in that function!
|
||||
def click(self, *args):
|
||||
pass
|
||||
|
||||
def stop_click_timer(self):
|
||||
# Stop the timer
|
||||
if self.click_timer:
|
||||
timer.kill_timer(self.click_timer)
|
||||
self.click_timer = None
|
||||
|
||||
def create_menu(self, menu, menu_options):
|
||||
for option_text, option_icon, option_action, option_id in menu_options[::-1]:
|
||||
if option_icon:
|
||||
|
||||
@@ -24,7 +24,7 @@ import logging
|
||||
import os
|
||||
from sabnzbd.encoding import unicoder
|
||||
import sabnzbd.cfg as cfg
|
||||
from sabnzbd.misc import get_ext, get_filename
|
||||
from sabnzbd.misc import get_ext, get_filename, get_from_url
|
||||
import sabnzbd.newsunpack
|
||||
from sabnzbd.constants import VALID_ARCHIVES
|
||||
|
||||
@@ -47,7 +47,7 @@ def upload_file(url, fp):
|
||||
password = cfg.password()
|
||||
if username and password:
|
||||
url = '%s&ma_username=%s&ma_password=%s' % (url, username, password)
|
||||
sabnzbd.newsunpack.get_from_url(url)
|
||||
get_from_url(url)
|
||||
except:
|
||||
logging.error("Failed to upload file: %s", fp)
|
||||
logging.info("Traceback: ", exc_info=True)
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
|
||||
# You MUST use double quotes (so " and not ')
|
||||
|
||||
__version__ = "2.3.0"
|
||||
__baseline__ = "ba7d906beaff948ba7870903f3dbaa1dd31e2e80"
|
||||
__version__ = "2.3.1"
|
||||
__baseline__ = "f1695ec8753fbdb07bd67bdce25eeb3ebe70b972"
|
||||
|
||||
160
scripts/Deobfuscate.py
Normal file
160
scripts/Deobfuscate.py
Normal file
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/python -OO
|
||||
# Copyright 2008-2017 The SABnzbd-Team <team@sabnzbd.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
"""
|
||||
|
||||
Deobfuscation post-processing script:
|
||||
|
||||
Will check in the completed job folder if maybe there are par2 files,
|
||||
for example "rename.par2", and use those to rename the files.
|
||||
If there is no "rename.par2" available, it will rename the largest
|
||||
file to the job-name in the queue.
|
||||
|
||||
NOTES:
|
||||
1) To use this script you need Python installed on your system and
|
||||
select "Add to path" during its installation. Select this folder in
|
||||
Config > Folders > Scripts Folder and select this script for each job
|
||||
you want it sued for, or link it to a category in Config > Categories.
|
||||
2) Beware that files on the 'Cleanup List' are removed before
|
||||
scripts are called and if any of them happen to be required by
|
||||
the found par2 file, it will fail.
|
||||
3) If there are multiple larger (>40MB) files, then the script will not
|
||||
rename anything, since it could be a multi-pack.
|
||||
4) If you want to modify this script, make sure to copy it out
|
||||
of this directory, or it will be overwritten when SABnzbd is updated.
|
||||
5) Feedback or bugs in this script can be reported in on our forum:
|
||||
https://forums.sabnzbd.org/viewforum.php?f=9
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import fnmatch
|
||||
import subprocess
|
||||
|
||||
# Files to exclude and minimal file size for renaming
|
||||
EXCLUDED_FILE_EXTS = ('.vob', '.bin')
|
||||
MIN_FILE_SIZE = 40*1024*1024
|
||||
|
||||
# Are we being called from SABnzbd?
|
||||
if not os.environ.get('SAB_VERSION'):
|
||||
print "This script needs to be called from SABnzbd as post-processing script."
|
||||
sys.exit(1)
|
||||
|
||||
def print_splitter():
|
||||
""" Simple helper function """
|
||||
print '\n------------------------\n'
|
||||
|
||||
# Windows or others?
|
||||
par2_command = os.environ['SAB_PAR2_COMMAND']
|
||||
if os.environ['SAB_MULTIPAR_COMMAND']:
|
||||
par2_command = os.environ['SAB_MULTIPAR_COMMAND']
|
||||
|
||||
# Diagnostic info
|
||||
print_splitter()
|
||||
print 'SABnzbd version: ', os.environ['SAB_VERSION']
|
||||
print 'Job location: ', os.environ['SAB_COMPLETE_DIR']
|
||||
print 'Par2-command: ', par2_command
|
||||
print_splitter()
|
||||
|
||||
# Search for par2 files
|
||||
matches = []
|
||||
for root, dirnames, filenames in os.walk(os.environ['SAB_COMPLETE_DIR']):
|
||||
for filename in fnmatch.filter(filenames, '*.par2'):
|
||||
matches.append(os.path.join(root, filename))
|
||||
print 'Found file:', os.path.join(root, filename)
|
||||
|
||||
# Found any par2 files we can use?
|
||||
run_renamer = True
|
||||
if not matches:
|
||||
print "No par2 files found to process."
|
||||
|
||||
# Run par2 from SABnzbd on them
|
||||
for par2_file in matches:
|
||||
# Build command, make it check the whole directory
|
||||
wildcard = os.path.join(os.environ['SAB_COMPLETE_DIR'], '*')
|
||||
command = [str(par2_command), 'r', par2_file, wildcard]
|
||||
|
||||
# Start command
|
||||
print_splitter()
|
||||
print 'Starting command: ', repr(command)
|
||||
try:
|
||||
result = subprocess.check_output(command)
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Multipar also gives non-zero in case of succes
|
||||
result = e.output
|
||||
|
||||
# Show output
|
||||
print_splitter()
|
||||
print result
|
||||
print_splitter()
|
||||
|
||||
# Last status-line for the History
|
||||
# Check if the magic words are there
|
||||
if 'Repaired successfully' in result or 'All files are correct' in result or \
|
||||
'Repair complete' in result or 'All Files Complete' in result or 'PAR File(s) Incomplete' in result:
|
||||
print 'Recursive repair/verify finished.'
|
||||
run_renamer = False
|
||||
else:
|
||||
print 'Recursive repair/verify did not complete!'
|
||||
|
||||
|
||||
# No matches? Then we try to rename the largest file to the job-name
|
||||
if run_renamer:
|
||||
print_splitter()
|
||||
print 'Trying to see if there are large files to rename'
|
||||
print_splitter()
|
||||
|
||||
# If there are more larger files, we don't rename
|
||||
largest_file = None
|
||||
for root, dirnames, filenames in os.walk(os.environ['SAB_COMPLETE_DIR']):
|
||||
for filename in filenames:
|
||||
full_path = os.path.join(root, filename)
|
||||
file_size = os.path.getsize(full_path)
|
||||
# Do we count this file?
|
||||
if file_size > MIN_FILE_SIZE and os.path.splitext(filename)[1].lower() not in EXCLUDED_FILE_EXTS:
|
||||
# Did we already found one?
|
||||
if largest_file:
|
||||
print 'Found:', largest_file
|
||||
print 'Found:', full_path
|
||||
print_splitter()
|
||||
print 'Found multiple larger files, aborting.'
|
||||
largest_file = None
|
||||
break
|
||||
largest_file = full_path
|
||||
|
||||
# Found something large enough?
|
||||
if largest_file:
|
||||
# We don't need to do any cleaning of dir-names
|
||||
# since SABnzbd already did that!
|
||||
new_name = '%s%s' % (os.path.join(os.environ['SAB_COMPLETE_DIR'], os.environ['SAB_FINAL_NAME']), os.path.splitext(largest_file)[1].lower())
|
||||
print 'Renaming %s to %s' % (largest_file, new_name)
|
||||
|
||||
# With retries for Windows
|
||||
for r in range(3):
|
||||
try:
|
||||
os.rename(largest_file, new_name)
|
||||
print 'Renaming done!'
|
||||
break
|
||||
except:
|
||||
time.sleep(1)
|
||||
else:
|
||||
print 'No par2 files or large files found'
|
||||
|
||||
# Always exit with succes-code
|
||||
sys.exit(0)
|
||||
44
scripts/Sample-PostProc.py
Executable file
44
scripts/Sample-PostProc.py
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python
|
||||
# Example Post-Processing Script for SABnzbd (2.3.1 and higher), written in Python.
|
||||
# For Linux, MacOS, Windows and any other platform with Python
|
||||
# See https://sabnzbd.org/wiki/scripts/post-processing-scripts for details
|
||||
#
|
||||
# Example test run on Linux:
|
||||
# env SAB_VERSION=X.Y SAB_AVG_BPS=666 python ./Sample-PostProc.py somedir222 nzbname CleanJobName123 Index12 Cat88 MyGroup PP0 https://example.com/
|
||||
|
||||
import sys, os
|
||||
|
||||
# Raw parsing of input parameters en SABnzbd environment variables
|
||||
counter = 0
|
||||
print "\nINPUT from argv:\n"
|
||||
for item in sys.argv:
|
||||
print "Argument", counter, ":", item
|
||||
counter += 1
|
||||
|
||||
print "\nINPUT from environment variables (only SAB specifics):\n"
|
||||
for item in os.environ:
|
||||
if item.find("SAB_") == 0:
|
||||
print item, os.environ[item]
|
||||
|
||||
# More intelligent parsing:
|
||||
try:
|
||||
(scriptname,directory,orgnzbname,jobname,reportnumber,category,group,postprocstatus,url) = sys.argv
|
||||
except:
|
||||
print "No SAB compliant number of commandline parameters found (should be 8):", len(sys.argv)-1
|
||||
sys.exit(1) # non-zero return code
|
||||
|
||||
# Some examples:
|
||||
print "\nExamples of some specific values:\n"
|
||||
print "jobname is", jobname
|
||||
try:
|
||||
sabversion = os.environ['SAB_VERSION']
|
||||
print "sabversion is", sabversion
|
||||
except:
|
||||
pass
|
||||
|
||||
''' your code here '''
|
||||
|
||||
# We're done:
|
||||
print "\nScript done. All OK." # the last line will appear in the SABnzb History GUI
|
||||
sys.exit(0) # The result code towards SABnzbd
|
||||
|
||||
Reference in New Issue
Block a user