Compare commits

...

103 Commits

Author SHA1 Message Date
Safihre
521b97b7b7 Update text files for 4.2.0RC2 2023-12-14 21:48:18 +01:00
SABnzbd Automation
58c8601067 Update translatable texts
[skip ci]
2023-12-14 20:38:57 +00:00
Safihre
36609376e8 Add button to macOS notification
Closes #2749
2023-12-14 21:36:55 +01:00
Safihre
32a1c8264e Add buttons to Windows Notifications
Closes #2641
2023-12-14 21:36:13 +01:00
Safihre
06754f4ef1 Mark second test_download_sorting_single as xfail on macOS and Windows 2023-12-13 14:40:02 +01:00
Safihre
99d9b3bf94 "Disk Full" notification type was not actually used 2023-12-13 14:18:53 +01:00
Safihre
ec71d20d37 Remove alternative IPv6-address mapping
Due to provider concerns
2023-12-13 11:16:51 +01:00
Safihre
2d1e88bb39 Ignore warning about old SSL/TLS settings in test_newswrapper 2023-12-12 14:28:05 +01:00
Safihre
c9d30bb422 Update sabnews for current asyncio behaviour 2023-12-12 14:28:05 +01:00
SABnzbd Automation
cd448082e3 Update translatable texts
[skip ci]
2023-12-12 11:00:30 +00:00
Safihre
46239dddac Update code for deprection warnings 2023-12-12 11:59:43 +01:00
SABnzbd Automation
81177fda35 Update translatable texts
[skip ci]
2023-12-11 20:35:26 +00:00
Michael Nightingale
983d623d7f Fix dirscanner async tests (#2748)
* Fix dirscanner async tests

* Use root of fake filesystem to test dirscanner

* Revert minor change
2023-12-11 21:34:42 +01:00
Safihre
bdda8f4abf Correct Direct Unpack unrar output logging 2023-12-11 13:25:46 +01:00
SABnzbd Automation
94fc804394 Update translatable texts
[skip ci]
2023-12-11 01:01:21 +00:00
renovate[bot]
e00d8c09e7 Update all dependencies 2023-12-11 01:00:42 +00:00
Safihre
70a40b4bdd Add duplicate_key to script environment variables 2023-12-08 21:10:47 +01:00
Safihre
f806a62f01 Add change of Pre-queue parameters to changelog 2023-12-08 21:10:47 +01:00
SABnzbd Automation
71a9281b8f Update translatable texts
[skip ci]
2023-12-08 13:25:25 +00:00
Safihre
a34747fbd5 Update text files for 4.2.0RC1
Yes, I used AI to generate the new release notes
2023-12-08 14:24:40 +01:00
Safihre
6b0380199b Mark test_download_sorting_single as xfail on macOS and Windows 2023-12-07 21:43:43 +01:00
Safihre
39d2f90a84 Trigger duplicate analysis if pre-queue script sets a new name 2023-12-07 21:42:43 +01:00
Safihre
7bff7651f3 Only auto-enable Direct Unpack for >100MB/s drives 2023-12-07 21:34:09 +01:00
Safihre
44bd15d519 Small change to internetspeed measurement 2023-12-07 15:49:07 +01:00
SABnzbd Automation
1ca93b03a0 Update translatable texts
[skip ci]
2023-12-06 15:56:06 +00:00
Safihre
3295142d81 Use sabctools for Internet Bandwidth measurement
Closes #2737
2023-12-06 13:44:12 +01:00
Safihre
f12fdc46dc Improve stability of test_adding_nzbs_nzoids 2023-12-06 13:22:59 +01:00
Safihre
fc01254fe6 Mark test_download_sorting_single as xfail on macOS and Windows 32bit 2023-12-06 12:58:47 +01:00
Safihre
8fb3368601 Add guestimate of performance test duration to hint 2023-12-06 12:46:44 +01:00
SABnzbd Automation
58facc2512 Update translatable texts
[skip ci]
2023-12-05 09:56:24 +00:00
Safihre
b43c2b308b Use correct keys for Season and Episode in Smart Duplicate detection 2023-12-05 10:55:34 +01:00
renovate[bot]
1e89a0af56 Update all dependencies 2023-12-04 02:19:58 +00:00
Safihre
acd3cbbf49 Correct test_validate_safedir 2023-12-03 20:02:41 +01:00
SABnzbd Automation
a806521745 Update translatable texts
[skip ci]
2023-12-02 20:20:33 +00:00
Safihre
0dddaf26e0 Stricter validation on Windows to prevent network drives as Incomplete 2023-12-02 21:19:48 +01:00
Safihre
cdf63a005b Python 3.8 doesn't have functools.cache so use lru_cache 2023-12-02 21:09:44 +01:00
SABnzbd Automation
ca422a0af3 Update translatable texts
[skip ci]
2023-12-02 19:40:31 +00:00
Safihre
a682371a91 Cache result of HappyEyeBalls 10 seconds 2023-12-02 20:39:38 +01:00
Safihre
26ef146526 Use decorator to maintain diskspace cache and HappyEyeBalls cache 2023-12-02 20:36:14 +01:00
Safihre
936ee58abb Reduce waiting time if there are no sockets to read 2023-12-01 15:11:05 +01:00
Safihre
71d8c208bc Micro-optimization of NzbQueue.is_empty 2023-12-01 14:50:07 +01:00
Safihre
2200ffa88e Use Server-specific timeout in final attempt 2023-12-01 14:34:07 +01:00
Safihre
4453316516 Server warnings were not always shown 2023-11-30 22:15:32 +01:00
Safihre
b947207571 Use Server-specific timeout during HappyEyeBalls 2023-11-30 19:50:31 +01:00
SABnzbd Automation
25d29deae6 Update translatable texts
[skip ci]
2023-11-30 12:26:53 +00:00
Safihre
9abe6d6d71 Skip empty HTTP-headers in URLGrabber and skip invalid categories 2023-11-30 13:25:43 +01:00
Safihre
77dbc0a37f Check nzb backup folder only if the job is not still in the queue 2023-11-30 13:19:57 +01:00
Safihre
659117512b Give RSS feed it's own history-stage 2023-11-30 13:04:12 +01:00
SABnzbd Automation
b1dbbc6a69 Update translatable texts
[skip ci]
2023-11-29 20:47:52 +00:00
Safihre
424a1c626e Add name of RSS feed to history Source
Closes #2206
2023-11-29 21:46:19 +01:00
Safihre
522666191b Indexer category was not used anymore 2023-11-29 21:46:19 +01:00
Safihre
78055ef794 Do not show propagation label in case job is Forced 2023-11-29 21:46:19 +01:00
SABnzbd Automation
0fe534c202 Update translatable texts
[skip ci]
2023-11-29 13:58:08 +00:00
Safihre
257179de31 Add ability to search Queue/History for status
Closes #2376
2023-11-29 14:57:15 +01:00
Safihre
65b57112b9 Optimize handling of propagation_delay 2023-11-29 14:57:15 +01:00
renovate[bot]
27f0b1d1f2 Update dependency cryptography to v41.0.6 [SECURITY] 2023-11-29 01:54:31 +00:00
SABnzbd Automation
6e31476c45 Update translatable texts
[skip ci]
2023-11-28 21:07:35 +00:00
Safihre
bc7f0f3fb3 Update text files for 4.2.0Beta1 2023-11-28 22:06:43 +01:00
SABnzbd Automation
13eeb5164f Update translatable texts
[skip ci]
2023-11-28 14:31:50 +00:00
Safihre
fc756ed23d Add smarter duplicate detection (#2736)
Restore pre-queue
2023-11-28 15:30:46 +01:00
SABnzbd Automation
c150365462 Update translatable texts
[skip ci]
2023-11-27 12:18:43 +00:00
renovate[bot]
58d209059e Update dependency setuptools to v69 2023-11-27 13:12:00 +01:00
Safihre
506179b517 Remove unused sort_type from guess_what 2023-11-24 21:17:29 +01:00
SABnzbd Automation
f0f4eb75df Update translatable texts
[skip ci]
2023-11-22 15:55:34 +00:00
Safihre
6c1c025668 Update text files 4.2.0Alpha3 2023-11-22 16:54:50 +01:00
SABnzbd Automation
987032b384 Update translatable texts
[skip ci]
2023-11-22 15:14:06 +00:00
Safihre
d516cbf363 Correct tests and improvements for new Duplicate handling 2023-11-22 16:13:22 +01:00
Safihre
824274ac5e Trigger duplicate handling when job is removed from the queue 2023-11-22 16:13:22 +01:00
Safihre
82b1c784f4 No longer warn for duplicates by default 2023-11-22 16:13:22 +01:00
Safihre
232512b860 Let main duplicate handling handle RSS duplicates 2023-11-22 16:13:22 +01:00
Safihre
223fa421c7 Implement more sophisticated duplicate handling
[skip ci]
2023-11-22 16:13:22 +01:00
Safihre
2e5e72bfcf Label in progress bar for URL fetches
Visually more distinctive
2023-11-22 15:37:35 +01:00
Safihre
9bdb986382 Only redirect cherrypy logging to their access log
Closes #2731
2023-11-20 08:49:27 +01:00
SABnzbd Automation
901ff30e11 Update translatable texts
[skip ci]
2023-11-18 20:24:07 +00:00
Safihre
5e04599212 Revert "Simplify handling of nzo.pp"
Closes #2733
2023-11-18 21:22:45 +01:00
Safihre
d3c9b7ead3 Simplify handling of nzo.pp 2023-11-13 12:33:05 +01:00
renovate[bot]
361770c34b Update all dependencies 2023-11-13 01:44:28 +00:00
SABnzbd Automation
5168f3fa97 Update translatable texts
[skip ci]
2023-11-11 22:01:41 +00:00
Safihre
94d307e198 Add simplified Sorter override, to analyse series information 2023-11-11 22:59:58 +01:00
Safihre
eba6236ad2 Make sure we only return successful Happy Eyeballs results 2023-11-10 16:16:46 +01:00
Safihre
d0128bd989 Use sabnzbd.filesystem functions directly 2023-11-10 13:45:56 +01:00
Safihre
fbd7c0ec36 Correct Night display of Sorting page 2023-11-08 16:33:40 +01:00
SABnzbd Automation
55abac97ea Update translatable texts
[skip ci]
2023-11-08 11:38:17 +00:00
Safihre
740b94170e Prevent looping over files for unwanted extension detection 2023-11-08 12:36:57 +01:00
SABnzbd Automation
c6a1a09213 Update translatable texts
[skip ci]
2023-11-07 15:33:21 +00:00
Safihre
cd84d52398 End of queue script to be moved to it's own configuration menu item
Closes #2385
Setting is not copied since it's such an exotic function.
Made pre-queue script an Advanced Setting.
2023-11-07 16:32:39 +01:00
Safihre
cdbad1b397 Add password as option to NzbObject creation
And another refactor of filename/work_name/final_name
2023-11-07 16:24:31 +01:00
Safihre
67e227008a Revert "Remove undocumented detection of password=XX from job name"
This reverts commit 62a057dbfb.

It is listed here: https://sabnzbd.org/wiki/advanced/password-protected-rars
Oops
2023-11-07 15:47:41 +01:00
Safihre
23cf43cac5 Replace uses of os.path.splitext with helper functions 2023-11-06 15:05:50 +01:00
Safihre
62a057dbfb Remove undocumented detection of password=XX from job name 2023-11-06 14:35:17 +01:00
renovate[bot]
f2ff9ae557 Update dependency jaraco.functools to v4 2023-11-06 00:42:28 +00:00
Safihre
9ed4e46919 Update macOS workflow for new GitHub runner 2023-11-03 20:17:52 +01:00
Safihre
faa71bae40 Log traceback in case of exception in __finish_connect_nw 2023-11-03 20:06:41 +01:00
Safihre
bbd5d2cd6d Prevent duplicate IP's in Happy Eyeballs 2023-11-03 12:03:14 +01:00
Safihre
221e135c07 Optimize Happy Eyeballs for our use
Reduced time between connection attempts to prevent slow hosts that happened to be the first in the list to win from faster second-in-list.
Add test for our IPv6 mapping
2023-11-02 21:12:32 +01:00
Safihre
956904c0b3 Correctly implement RFC 6555/8305 (Happy Eyeballs) 2023-11-01 15:16:10 +01:00
Safihre
8590481022 Add IPv6 alternative hostname for common providers
Closes #2721
2023-11-01 09:07:42 +01:00
SABnzbd Automation
2171d0139e Update translatable texts
[skip ci]
2023-10-30 13:45:23 +00:00
Safihre
71d6aca9f8 Remove unused exceptions in servertest 2023-10-30 14:44:31 +01:00
Safihre
0125e279c0 Prevent PyWin32 warning by returning True instead of nothing 2023-10-30 12:33:57 +01:00
SABnzbd Automation
b8e46ccf10 Update translatable texts
[skip ci]
2023-10-30 01:02:52 +00:00
renovate[bot]
787fef1c03 Update dependency orjson to v3.9.10 2023-10-30 01:02:09 +00:00
SABnzbd Automation
98b7a6171f Update translatable texts
[skip ci]
2023-10-27 12:41:14 +00:00
117 changed files with 2726 additions and 2308 deletions

View File

@@ -81,7 +81,7 @@ jobs:
# We need the official Python, because the GA ones only support newer macOS versions
# The deployment target is picked up by the Python build tools automatically
# If updated, make sure to also set LSMinimumSystemVersion in SABnzbd.spec
PYTHON_VERSION: "3.12.0"
PYTHON_VERSION: "3.12.1"
MACOSX_DEPLOYMENT_TARGET: "10.9"
# We need to force compile for universal2 support
CFLAGS: -arch x86_64 -arch arm64
@@ -98,10 +98,7 @@ jobs:
if: steps.cache-python-download.outputs.cache-hit != 'true'
run: curl https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-macos11.pkg -o ~/python.pkg
- name: Install Python
run: |
sudo installer -pkg ~/python.pkg -target /
unlink /usr/local/bin/python
ln -s /usr/local/bin/python3 /usr/local/bin/python
run: sudo installer -pkg ~/python.pkg -target /
- name: Cache Python virtualenv
uses: syphar/restore-virtualenv@v1.3
id: cache-virtualenv

View File

@@ -1,33 +1,60 @@
Release Notes - SABnzbd 4.2.0 Alpha 2
Release Notes - SABnzbd 4.2.0 Release Candidate 2
=========================================================
## Changes since 4.1.0
- Numerous smaller performance improvements were made.
- Reduced recursive unpacking to 2 levels, instead of 5.
- IPv6 addresses are preferred during server address selection.
- Stricter check if `Complete Folder` is inside `Download Folder`.
- Windows: Reduced size of installer.
- Windows/macOS: Updated to Python 3.12.
This is the second pre-release build of SABnzbd 4.2.0, which includes several new features and bug fixes.
## Bugfixes since 4.1.0
- Multi-select in the queue was broken for some users.
- Prevent crash during saving of configuration.
- Removing a failed download from the history could break active downloads.
## Key changes since 4.1.0
* **Duplicate detection workflow was overhauled:**
* `Series Duplicate Detection` was replaced by `Smart Duplicate Detection`
that can also detect `Movie` and `Daily Show` duplicates.
* Additionally, duplicates will also be detected if they are still in the queue.
* More information: https://sabnzbd.org/wiki/duplicate-detection
* **Interface changes:**
* Added ability to filter the Queue and History by `status`.
* RSS-feed that provided the download is shown in History details.
* macOS/Windows 10 & 11: Added `Open Folder` button to `Job/Queue finished` notifications.
Clicking any type of notification will now open a browser with SABnzbd.
* **Performance and usability improvements:**
* Numerous smaller performance improvements were made.
* Server IP-address selection was optimized.
* The `Internet Bandwidth` test was made more reliable.
* macOS/Windows: Updated to Python 3.12.
* **Configuration changes:**
* The `On queue finish script` is now set in Switches.
* Reduced recursive unpacking to 2 levels, instead of 5.
* Duplicate detection related Pre-queue script input parameters were removed.
You will need to update your Pre-queue script.
More information: https://sabnzbd.org/wiki/configuration/4.2/scripts/pre-queue-scripts
* Stricter check if `Complete Folder` is inside `Download Folder`.
* Windows: Prevent use of network drive as `Download Folder`.
## Bug fixes since 4.1.0
* Fixed an issue where the multi-select option in the queue was not working for some users.
* Prevented a crash that would occur during the saving of configuration settings.
* Ensured that server warnings are always displayed to users.
* If `weblogging` was enabled, output was also written to regular log.
* Fixed an issue where removing a failed download from the History could break active downloads.
## Upgrade notices
- Direct upgrade is possible from version 3.0.0 and newer.
Upgrading from older versions will require `Queue repair`.
- Downgrading from version 4.2.0 or newer to 3.7.2 or older will
require `Queue repair` due to changes in the internal data format.
* You can directly upgrade from version 3.0.0 and newer.
* Upgrading from older versions will require performing a `Queue repair`.
* Downgrading from version 4.2.0 or newer to 3.7.2 or older will require
performing a `Queue repair` due to changes in the internal data format.
## Known problems and solutions
- Read the file "ISSUES.txt"
* Read `ISSUES.txt` or https://sabnzbd.org/wiki/introduction/known-issues
## About
SABnzbd is an open-source cross-platform binary newsreader.
It simplifies the process of downloading from Usenet dramatically, thanks
to its web-based user interface and advanced built-in post-processing options
that automatically verify, repair, extract and clean up posts downloaded
from Usenet.
SABnzbd is an open-source cross-platform binary newsreader.
It simplifies the process of downloading from Usenet dramatically, thanks to its web-based
user interface and advanced built-in post-processing options that automatically verify, repair,
extract and clean up posts downloaded from Usenet.
(c) Copyright 2007-2023 by The SABnzbd-Team (sabnzbd.org)
(c) Copyright 2007-2023 by The SABnzbd-Team (sabnzbd.org)

View File

@@ -1349,7 +1349,6 @@ def main():
"server.socket_host": cherryhost,
"server.socket_port": cherryport,
"server.shutdown_timeout": 0,
"log.screen": False,
"engine.autoreload.on": False,
"tools.encode.on": True,
"tools.gzip.on": True,
@@ -1361,13 +1360,11 @@ def main():
)
# Do we want CherryPy Logging? Cannot be done via the config
cherrypy.log.screen = False
cherrypy.log.access_log.propagate = False
if cherrypylogging:
sabnzbd.WEBLOGFILE = os.path.join(logdir, DEF_LOG_CHERRY)
cherrypy.log.screen = True
cherrypy.log.access_log.propagate = True
cherrypy.log.access_file = str(sabnzbd.WEBLOGFILE)
else:
cherrypy.log.access_log.propagate = False
# Force mimetypes (OS might overwrite them)
forced_mime_types = {"css": "text/css", "js": "application/javascript"}
@@ -1765,10 +1762,10 @@ if __name__ == "__main__":
# Initialize the menu
shared_app = NSApplication.sharedApplication()
sabnzbd_menu = SABnzbdDelegate.alloc().init()
shared_app.setDelegate_(sabnzbd_menu)
sabnzbd.MACOSTRAY = SABnzbdDelegate.alloc().init()
shared_app.setDelegate_(sabnzbd.MACOSTRAY)
# Build the menu
sabnzbd_menu.awakeFromNib()
sabnzbd.MACOSTRAY.awakeFromNib()
# Run the main eventloop
AppHelper.runEventLoop()
else:

View File

@@ -1,3 +1,3 @@
# Special requirements for macOS universal2 binary release
# This way dependabot can auto-update them
cryptography==41.0.5
cryptography==41.0.7

View File

@@ -1,20 +1,20 @@
# Basic build requirements
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
pyinstaller==6.1.0
pyinstaller==6.3.0
packaging==23.2
pyinstaller-hooks-contrib==2023.10
altgraph==0.17.4
wrapt==1.15.0
setuptools==68.2.2
wrapt==1.16.0
setuptools==69.0.2
certifi
# Required on 32bit Windows, exclude it based on Python-version
importlib_metadata==6.8.0; python_version < '3.10'
importlib_resources==6.1.0; python_version < '3.10'
importlib_metadata==7.0.0; python_version < '3.10'
importlib_resources==6.1.1; python_version < '3.10'
zipp==3.17.0; python_version < '3.10'
# orjson does not support 32bit Windows, also exclude based on Python-version
orjson==3.9.9; python_version > '3.8'
orjson==3.9.10; python_version > '3.8'
# For the Windows build
pefile==2023.2.7; sys_platform == 'win32'

View File

@@ -200,9 +200,14 @@ Section "SABnzbd" SecDummy
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "URLUpdateInfo" 'https://sabnzbd.org/'
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "Comments" 'The automated Usenet download tool'
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "DisplayIcon" '$INSTDIR\icons\sabnzbd.ico'
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "EstimatedSize" 25674
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "EstimatedSize" 40674
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoRepair" -1
WriteRegDWORD HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd" "NoModify" -1
WriteRegStr HKEY_CURRENT_USER "Software\Classes\AppUserModelId\SABnzbd" "DisplayName" "SABnzbd"
WriteRegStr HKEY_CURRENT_USER "Software\Classes\AppUserModelId\SABnzbd" "IconUri" '$INSTDIR\icons\sabnzbd16_32.ico'
; write out uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"
@@ -348,6 +353,8 @@ Section "un.$(MsgDelProgram)" Uninstall
Delete "$INSTDIR\uninstall.exe"
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\SABnzbd"
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\SABnzbd"
DeleteRegKey HKEY_CURRENT_USER "Software\Classes\AppUserModelId\SABnzbd"
DeleteRegKey HKEY_CURRENT_USER "Software\SABnzbd"
${RemovePrev} "$INSTDIR"
@@ -383,8 +390,6 @@ Section "un.$(MsgDelProgram)" Uninstall
Delete "$DESKTOP\SABnzbd.lnk"
DeleteRegKey HKEY_CURRENT_USER "Software\SABnzbd"
${unregisterExtension} ".nzb" "NZB File"
${RefreshShellIcons}

View File

@@ -202,7 +202,7 @@
<div class="field-pair">
<label class="config" for="nscript_parameters">$T('opt-nscript_parameters')</label>
<input type="text" name="nscript_parameters" id="nscript_parameters" value="$nscript_parameters" />
<span class="desc">$T('Optional') - $T('explain-nscript_parameters')</span>
<span class="desc">$T('Optional') - $T('readwiki')</span>
</div>
$show_notify_checkboxes('nscript')
<div class="field-pair no-field-pair-bg">

View File

@@ -1,12 +1,11 @@
<!--#set global $pane="Sorting"#-->
<!--#set global $help_uri = $confighelpuri + "sorting"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="padTable section explain-sorting">
<a class="main-helplink" href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
$T('explain-sorting')
</div>
<div class="colmask">
<div class="padTable section">
<a class="main-helplink" href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
$T('explain-sorting')
</div>
<div class="padding alt section">
<button type="button" class="btn btn-default addSorter"><span class="glyphicon glyphicon-plus"></span> $T('add-sorter')</button>
<label for="advanced-settings-button" class="form-control advanced-button ">
@@ -345,7 +344,7 @@
</div>
<!--#if len($slotinfo) == 1 and ("tv" in $categories or "movies" in $categories)#-->
<div class="section align-center alt sorting-quick-setup">
<div class="section align-center sorting-quick-setup">
<h3>$T('sort-quick-add'):</h3>
<!--#if "tv" in $categories#-->
<form action="save_sorter" method="post" autocomplete="off">

View File

@@ -41,7 +41,7 @@
</div><!-- /col2 -->
<div class="col1">
<fieldset>
<div class="field-pair">
<div class="field-pair advanced-settings">
<label class="config" for="pre_script">$T('opt-pre_script')</label>
<select name="pre_script" id="pre_script">
<!--#for $sc in $scripts#-->
@@ -54,6 +54,19 @@
</select>
<span class="desc">$T('explain-pre_script')</span>
</div>
<div class="field-pair advanced-settings">
<label class="config" for="end_queue_script">$T('opt-end_queue_script')</label>
<select name="end_queue_script" id="end_queue_script">
<!--#for $sc in $scripts#-->
<!--#if $sc.lower() == $end_queue_script.lower()#-->
<option value="$sc" selected="selected">$Tspec($sc)</option>
<!--#else#-->
<option value="$sc">$Tspec($sc)</option>
<!--#end if#-->
<!--#end for#-->
</select>
<span class="desc">$T('explain-end_queue_script')</span>
</div>
<div class="field-pair">
<label class="config" for="propagation_delay">$T('opt-propagation_delay')</label>
<input type="number" name="propagation_delay" id="propagation_delay" value="$propagation_delay" /> <i>$T('minutes')</i>
@@ -83,23 +96,29 @@
<option value="3" <!--#if int($no_dupes) == 3 then 'selected="selected"' else ""#--> >$T('nodupes-fail')</option>
<option value="1" <!--#if int($no_dupes) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-ignore')</option>
</select>
<span class="desc">$T('explain-no_dupes')</span>
<span class="desc">
$T('explain-no_dupes')<br>
<a href="https://sabnzbd.org/wiki/duplicate-detection" target="_blank">https://sabnzbd.org/wiki/duplicate-detection</a>
</span>
</div>
<div class="field-pair">
<label class="config" for="no_series_dupes">$T('opt-no_series_dupes')</label>
<select name="no_series_dupes" id="no_series_dupes">
<option value="0" <!--#if int($no_series_dupes) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
<option value="4" <!--#if int($no_series_dupes) == 4 then 'selected="selected"' else ""#--> >$T('nodupes-tag')</option>
<option value="2" <!--#if int($no_series_dupes) == 2 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
<option value="3" <!--#if int($no_series_dupes) == 3 then 'selected="selected"' else ""#--> >$T('nodupes-fail')</option>
<option value="1" <!--#if int($no_series_dupes) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-ignore')</option>
<label class="config" for="no_smart_dupes">$T('opt-no_smart_dupes')</label>
<select name="no_smart_dupes" id="no_smart_dupes">
<option value="0" <!--#if int($no_smart_dupes) == 0 then 'selected="selected"' else ""#--> >$T('nodupes-off')</option>
<option value="4" <!--#if int($no_smart_dupes) == 4 then 'selected="selected"' else ""#--> >$T('nodupes-tag')</option>
<option value="2" <!--#if int($no_smart_dupes) == 2 then 'selected="selected"' else ""#--> >$T('nodupes-pause')</option>
<option value="3" <!--#if int($no_smart_dupes) == 3 then 'selected="selected"' else ""#--> >$T('nodupes-fail')</option>
<option value="1" <!--#if int($no_smart_dupes) == 1 then 'selected="selected"' else ""#--> >$T('nodupes-ignore')</option>
</select>
<span class="desc">$T('explain-no_series_dupes')</span>
<span class="desc">
$T('explain-no_smart_dupes')<br>
<a href="https://sabnzbd.org/wiki/duplicate-detection" target="_blank">https://sabnzbd.org/wiki/duplicate-detection</a>
</span>
</div>
<div class="field-pair advanced-settings">
<label class="config" for="series_propercheck">$T('opt-series_propercheck')</label>
<input type="checkbox" name="series_propercheck" id="series_propercheck" value="1" <!--#if int($series_propercheck) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-series_propercheck')</span>
<label class="config" for="dupes_propercheck">$T('opt-dupes_propercheck')</label>
<input type="checkbox" name="dupes_propercheck" id="dupes_propercheck" value="1" <!--#if int($dupes_propercheck) > 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-dupes_propercheck')</span>
</div>
<div class="field-pair">
<label class="config" for="pause_on_pwrar">$T('opt-pause_on_pwrar')</label>
@@ -174,12 +193,12 @@
<div class="field-pair advanced-settings <!--#if not $have_nice then "disabled" else "" #-->">
<label class="config" for="nice">$T('opt-nice')</label>
<input type="text" name="nice" id="nice" value="$nice" <!--#if not $have_nice then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-nice')</span>
<span class="desc">$T('readwiki')</span>
</div>
<div class="field-pair advanced-settings <!--#if not $have_ionice then "disabled" else "" #-->">
<label class="config" for="ionice">$T('opt-ionice')</label>
<input type="text" name="ionice" id="ionice" value="$ionice" <!--#if not $have_ionice then 'readonly="readonly" disabled="disabled"' else "" #--> />
<span class="desc">$T('explain-ionice')</span>
<span class="desc">$T('readwiki')</span>
</div>
<!--#else#-->
<div class="field-pair advanced-settings">
@@ -191,13 +210,13 @@
<option value="2" <!--#if int($win_process_prio) == 2 then 'selected="selected"' else ""#-->>$T('win_process_prio-low')</option>
<option value="1" <!--#if int($win_process_prio) == 1 then 'selected="selected"' else ""#-->>$T('win_process_prio-idle')</option>
</select>
<span class="desc">$T('explain-win_process_prio')</span>
<span class="desc">$T('readwiki')</span>
</div>
<!--#end if#-->
<div class="field-pair advanced-settings">
<label class="config" for="par_option">$T('opt-par_option')</label>
<input type="text" name="par_option" id="par_option" value="$par_option" />
<span class="desc">$T('explain-par_option')</span>
<span class="desc">$T('readwiki')</span>
</div>
<div class="field-pair advanced-settings">
<label class="config" for="sfv_check">$T('opt-sfv_check')</label>

View File

@@ -107,7 +107,6 @@ select.form-control,
.navbar-default,
.search-box input,
.select,
.Sorting .explain-sorting,
.table-striped>tbody>tr:nth-child(even),
.table>tbody>tr:nth-child(even),
.tab-pane tr:nth-child(odd),

View File

@@ -359,10 +359,6 @@ tr.separator {
margin: 5px;
}
.Sorting .explain-sorting {
background-color: #fff;
color: #000;
}
.Sorting .explain-pattern {
border: none;
width: 100%;

View File

@@ -102,26 +102,15 @@
<li class="divider"></li>
<li class="dropdown-header"><span class="glyphicon glyphicon-off"></span> $T('Glitter-onFinish'):</li>
<li>
<!-- ko if: queue.scriptsListLoaded -->
<select data-bind="value: finishaction, event: { change: setOnQueueFinish }" class="form-control">
<option value=""></option>
<optgroup label="$T('eoq-actions')">
<option value="shutdown_program">$T('shutdownSab')</option>
<!--#if $power_options#-->
<option value="shutdown_pc">$T('shutdownPc')</option>
<option value="standby_pc">$T('standbyPc')</option>
<option value="hibernate_pc">$T('hibernatePc')</option>
<!--#end if#-->
</optgroup>
<optgroup label="$T('eoq-scripts')" data-bind="visible: queue.scriptsList().length > 1">
<!-- ko foreach: queue.scriptsList -->
<!-- ko if: \$data.scriptValue != 'None' -->
<option data-bind="text: \$data.scriptText, attr: { value: 'script_'+\$data.scriptValue } " ></option>
<!-- /ko -->
<!-- /ko -->
</optgroup>
<option value="shutdown_program">$T('shutdownSab')</option>
<!--#if $power_options#-->
<option value="shutdown_pc">$T('shutdownPc')</option>
<option value="standby_pc">$T('standbyPc')</option>
<option value="hibernate_pc">$T('hibernatePc')</option>
<!--#end if#-->
</select>
<!-- /ko -->
</li>
</ul>
</li>

View File

@@ -134,7 +134,7 @@
<div class="col-sm-6">$T('dashboard-systemPerformance') &nbsp; </div>
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.pystone"></span>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
<small title="$cpumodel $cpusimd" data-tooltip="true">$cpumodel $cpusimd</small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
@@ -143,7 +143,7 @@
<div class="col-sm-6">$T('dashboard-downloadDirSpeed') &nbsp; </div>
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.downloaddirspeed()"></span> MB/s
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
<small data-bind="text: statusInfo.downloaddir, attr: { 'data-original-title': statusInfo.downloaddir }" data-tooltip="true"></small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
@@ -152,7 +152,7 @@
<div class="col-sm-6">$T('dashboard-completeDirSpeed') &nbsp; </div>
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.completedirspeed()"></span> MB/s
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
<small data-bind="text: statusInfo.completedir, attr: { 'data-original-title': statusInfo.completedir }" data-tooltip="true"></small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
@@ -161,7 +161,7 @@
<div class="col-sm-6">$T('dashboard-internetBandwidth') &nbsp; </div>
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.internetbandwidth()"></span> MB/s
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
<small><span data-bind="text: statusInfo.internetbandwidth()*8"></span> Mbps</small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>

View File

@@ -67,6 +67,7 @@
glitterTranslate.fetch = "$T('Glitter-fetch')";
glitterTranslate.checking = "$T('post-Checking')";
glitterTranslate.misingArt = "$T('missingArt')";
glitterTranslate.fetchingURL = "$T('Glitter-addFromURL')"
glitterTranslate.chooseFile = "$T('Glitter-chooseFile')";
glitterTranslate.orphanedJobsMsg = "$T('explain-orphans')";
glitterTranslate.useCache = "$T('explain-cache_limitstr').replace("64M", "256M").replace("128M", "512M")";
@@ -96,6 +97,7 @@
glitterTranslate.status['Unpack'] = "$T('stage-unpack')";
glitterTranslate.status['Deobfuscate'] = "$T('stage-deobfuscate')";
glitterTranslate.status['Script'] = "$T('stage-script')";
glitterTranslate.status['RSS'] = "$T('stage-rss')";
glitterTranslate.status['Source'] = "$T('stage-source')";
glitterTranslate.status['Servers'] = "$T('stage-servers')";
glitterTranslate.status['INFO'] = "$T('log-info')".replace('+', '').toUpperCase();

View File

@@ -338,7 +338,7 @@ function ViewModel() {
limit: parseInt(self.queue.paginationLimit())
}
if (self.queue.searchTerm()) {
parseSearchQuery(api_call, self.queue.searchTerm(), ["cat", "category", "priority"])
parseSearchQuery(api_call, self.queue.searchTerm(), ["cat", "category", "priority", "status"])
}
var queueApi = callAPI(api_call)
.done(self.updateQueue)
@@ -367,7 +367,7 @@ function ViewModel() {
last_history_update: self.history.lastUpdate
}
if (self.history.searchTerm()) {
parseSearchQuery(history_call, self.history.searchTerm(), ["cat", "category"])
parseSearchQuery(history_call, self.history.searchTerm(), ["cat", "category", "status"])
}
// History
@@ -397,7 +397,6 @@ function ViewModel() {
if (keyword === "priority" && api_request["priority"]) {
for (const prio_name in self.queue.priorityName) {
api_request["priority"] = api_request["priority"].replace(prio_name, self.queue.priorityName[prio_name])
}
}
}
@@ -1110,11 +1109,7 @@ function ViewModel() {
if(script === 'None') return { scriptValue: 'None', scriptText: glitterTranslate.noneText };
return { scriptValue: script, scriptText: script };
}))
self.queue.scriptsListLoaded(true)
})
} else {
// We can already continue
self.queue.scriptsListLoaded(true)
}

View File

@@ -37,7 +37,6 @@ function QueueListModel(parent) {
self.multiEditItems = ko.observableArray([]);
self.categoriesList = ko.observableArray([]);
self.scriptsList = ko.observableArray([]);
self.scriptsListLoaded = ko.observable(false);
self.searchTerm = ko.observable('').extend({ rateLimit: { timeout: 400, method: "notifyWhenChangesStop" } });
self.paginationLimit = ko.observable(20).extend({ persist: 'queuePaginationLimit' });
self.pagination = new paginationModel(self);
@@ -507,6 +506,9 @@ function QueueModel(parent, data) {
// MB's
self.progressText = ko.pureComputed(function() {
if(self.isGrabbing()) {
return glitterTranslate.fetchingURL
}
return (self.totalMB() - self.remainingMB()).toFixed(0) + " MB / " + (self.totalMB() * 1).toFixed(0) + " MB";
})

View File

@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: team@sabnzbd.org\n"
"Language-Team: SABnzbd <team@sabnzbd.org>\n"

View File

@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"
"MIME-Version: 1.0\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Finnish (https://app.transifex.com/sabnzbd/teams/111101/fi/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: ION, 2020\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Polish (https://app.transifex.com/sabnzbd/teams/111101/pl/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Romanian (https://app.transifex.com/sabnzbd/teams/111101/ro/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Serbian (https://app.transifex.com/sabnzbd/teams/111101/sr/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"

View File

@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: team@sabnzbd.org\n"
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
@@ -162,11 +162,6 @@ msgstr ""
msgid "Default"
msgstr ""
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr ""
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -241,7 +236,7 @@ msgstr ""
msgid "Server address required"
msgstr ""
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr ""
@@ -259,7 +254,7 @@ msgid "Permissions setting of %s might deny SABnzbd access to the files and fold
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
@@ -1002,6 +997,16 @@ msgstr ""
msgid "Other Messages"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr ""
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr ""
@@ -1082,6 +1087,18 @@ msgstr ""
msgid "NZB added to queue"
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1096,26 +1113,6 @@ msgstr ""
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1134,6 +1131,10 @@ msgstr ""
msgid "DUPLICATE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr ""
@@ -1179,6 +1180,10 @@ msgstr ""
msgid "%s articles had non-matching duplicates"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr ""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1369,6 +1374,11 @@ msgstr ""
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr ""
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr ""
#. Warning message
#: sabnzbd/postproc.py
msgid "Completed Download Folder %s is on FAT file system, limiting maximum file size to 4GB"
@@ -1551,10 +1561,6 @@ msgstr ""
msgid "Show interface"
msgstr ""
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr ""
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1642,6 +1648,11 @@ msgstr ""
msgid "Script"
msgstr ""
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr ""
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2014,11 +2025,6 @@ msgstr ""
msgid "Scheduling"
msgstr ""
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr ""
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2133,11 +2139,6 @@ msgstr ""
msgid "Retry"
msgstr ""
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr ""
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2432,7 +2433,6 @@ msgstr ""
msgid "Backup"
msgstr ""
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr ""
@@ -2909,19 +2909,19 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect identical NZB files (based on items in your History or files in .nzb Backup Folder)"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect identical episodes in series (based on \"name/season/episode\" of items in your History)"
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -2929,7 +2929,7 @@ msgid "Allow proper releases"
msgstr ""
#: sabnzbd/skintext.py
msgid "Bypass series duplicate detection if PROPER, REAL or REPACK is detected in the download name"
msgid "Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3008,6 +3008,14 @@ msgstr ""
msgid "Used before an NZB enters the queue."
msgstr ""
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr ""
@@ -4462,10 +4470,6 @@ msgstr ""
msgid "Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr ""

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"
@@ -179,11 +179,6 @@ msgstr "Žádný"
msgid "Default"
msgstr "Výchozí"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Nepodařilo se zkompilovat regex pro hledaný výraz: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -266,7 +261,7 @@ msgstr "%s není validní emailová adresa"
msgid "Server address required"
msgstr "Adresa serveru je vyžadována"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr ""
@@ -286,12 +281,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "UNC cesta \"%s\" zde není povolena"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Fronta nené prázdná, nelze změnit složku."
#: sabnzbd/cfg.py
msgid ""
@@ -1069,6 +1064,16 @@ msgstr "Fronta dokončena"
msgid "Other Messages"
msgstr "Ostatní zprávy"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Otevřít složku s kompletními soubory"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Nedostupné"
@@ -1149,6 +1154,18 @@ msgstr "Nelze nahrát %s, detekován porušený soubor"
msgid "NZB added to queue"
msgstr "NZB přidáno do fronty"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignoruji duplikátní NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Nezdařilo se duplikovat NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Duplikátní NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1163,26 +1180,6 @@ msgstr "Prázdný NZB soubor %s"
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignoruji duplikátní NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Nezdařilo se duplikovat NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Duplikátní NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pozastavuji duplikátní NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1201,6 +1198,10 @@ msgstr "Chyba při importu %s"
msgid "DUPLICATE"
msgstr "DUPLIKÁT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ŠIFROVANÉ"
@@ -1246,6 +1247,10 @@ msgstr ""
msgid "%s articles had non-matching duplicates"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pozastavuji duplikátní NZB \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1441,6 +1446,11 @@ msgstr ""
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "Stará fronta nalezena, použijte Status->Repair pro konverzi fronty"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Nepodařilo se zkompilovat regex pro hledaný výraz: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1625,10 +1635,6 @@ msgstr "Prázdný RSS záznam nalezen (%s)"
msgid "Show interface"
msgstr "Zobrazit rozhraní"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Otevřít složku s kompletními soubory"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1717,6 +1723,11 @@ msgstr ""
msgid "Script"
msgstr "Skript"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2089,11 +2100,6 @@ msgstr "Přepínače"
msgid "Scheduling"
msgstr "Plánování"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2208,11 +2214,6 @@ msgstr "Jméno"
msgid "Retry"
msgstr "Opakovat"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Akce"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2527,7 +2528,6 @@ msgstr ""
msgid "Backup"
msgstr "Záloha"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr ""
@@ -3052,23 +3052,19 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Detekovat duplicitní stahování"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -3077,8 +3073,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3163,6 +3159,14 @@ msgstr ""
msgid "Used before an NZB enters the queue."
msgstr ""
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr ""
@@ -4671,10 +4675,6 @@ msgid ""
"Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr ""

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"
@@ -179,11 +179,6 @@ msgstr "Ingen"
msgid "Default"
msgstr "Standard"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Det lykkedes ikke at kompilere regex for søgestreng: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -266,7 +261,7 @@ msgstr "%s er ikke en godkendt e-mail adresse"
msgid "Server address required"
msgstr "Kræver serveradresse"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Ugyldig server adresse."
@@ -286,12 +281,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "UNC søgning \"%s\" er ikke tilladt her"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Køen er ikke tom, kan ikke skifte mappe."
#: sabnzbd/cfg.py
msgid ""
@@ -1073,6 +1068,16 @@ msgstr "Kø færdig"
msgid "Other Messages"
msgstr "Andre beskeder"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Åben færdig mappe"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Ikke tilgængelig"
@@ -1153,6 +1158,18 @@ msgstr "Downloadnings fejl %s, ødelagt fil fundet"
msgid "NZB added to queue"
msgstr "NZB tilføjet i køen"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorerer identiske NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Fejler dublet NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Dublet NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1167,26 +1184,6 @@ msgstr "Tom NZB fil %s"
msgid "Pre-queue script marked job as failed"
msgstr "Før-kø script job markeret som mislykkedet"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorerer identiske NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Fejler dublet NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Dublet NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pause duplikeret NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1205,6 +1202,10 @@ msgstr "Det lykkedes ikke at importere %s"
msgid "DUPLICATE"
msgstr "DUPLIKERE"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "KRYPTEREDE"
@@ -1250,6 +1251,10 @@ msgstr "%s artikler manglede"
msgid "%s articles had non-matching duplicates"
msgstr "%s artikler havde ikke-matchende dubletter"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pause duplikeret NZB \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1473,6 +1478,11 @@ msgstr "Fejl %s: Du skal angive et gyldigt brugernavn og adgangskode."
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "Gamle kø opdaget, brug Status->Reparation for at konvertere kø"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Det lykkedes ikke at kompilere regex for søgestreng: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1657,10 +1667,6 @@ msgstr "Tom RSS post blev fundet (%s)"
msgid "Show interface"
msgstr "Vis grænseflade"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Åben færdig mappe"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1749,6 +1755,11 @@ msgstr ""
msgid "Script"
msgstr "Script"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2121,11 +2132,6 @@ msgstr "Parameter"
msgid "Scheduling"
msgstr "Planlægning"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2240,11 +2246,6 @@ msgstr "Navn"
msgid "Retry"
msgstr "Forsøg igen"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Handlinger"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2568,7 +2569,6 @@ msgstr "Oppetid"
msgid "Backup"
msgstr "Sikkerhedskopi"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Læs mere om dette på Wiki Help!"
@@ -3120,28 +3120,20 @@ msgstr ""
"I tilfælde af \"Pause\", skal du angive en adgangskode og genoptage jobbet."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Find identiske downloads"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
"Fundet identiske NZB filer (baseret på elementer i din historik eller filer "
"i. nzb Backup mappe)"
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Opdage identiske episoder i serier"
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
"Fundet identiske episoder i serie (baseret på \"navn /sæson /episode\" af "
"elementer i din historik)"
#: sabnzbd/skintext.py
msgid "Allow proper releases"
@@ -3149,8 +3141,8 @@ msgstr "Tillad reelle udgivelser"
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3239,6 +3231,14 @@ msgstr "Før kø bruger script"
msgid "Used before an NZB enters the queue."
msgstr "Brugt før, en NZB kommer ind i køen."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Ekstra PAR2 parameter"
@@ -4783,10 +4783,6 @@ msgstr ""
"Ukendt SSL protokol: Prøv at deaktivere SSL eller forbinder på en anden "
"port."
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Server afslut under login-sekvens."
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Serveren kræver brugernavn og adgangskode."

View File

@@ -15,7 +15,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"
@@ -195,12 +195,6 @@ msgstr "Nichts"
msgid "Default"
msgstr "Standard"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr ""
"Kompilieren des regulären Ausdrucks für den Suchbegriff %s fehlgeschlagen."
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -285,7 +279,7 @@ msgstr "%s ist keine gültige E-Mail-Adresse"
msgid "Server address required"
msgstr "Server-Adresse wird benötigt"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Ungültige Server-Adresse."
@@ -307,12 +301,13 @@ msgstr ""
"erstellten Dateien und Ordner von SABnzbd verweigern."
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "UNC-Pfad \"%s\" ist hier nicht erlaubt"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
"Ordner kann nicht geändert werden, da die Warteschlange nicht leer ist."
#: sabnzbd/cfg.py
msgid ""
@@ -1122,6 +1117,16 @@ msgstr "Warteschlange abgearbeitet"
msgid "Other Messages"
msgstr "Andere Nachrichten"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Öffne Zielverzeichnis"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Nicht verfügbar"
@@ -1202,6 +1207,18 @@ msgstr "Fehler beim Laden von %s. Beschädigte Datei gefunden."
msgid "NZB added to queue"
msgstr "NZB zur Warteschlange hinzugefügt"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Doppelte NZB \"%s\" wird ignoriert"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "kopieren der NZB \"%s\" fehlgeschlagen"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Doppelte NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1218,26 +1235,6 @@ msgstr ""
"Das Vorwarteschlangen (pre-queue) Skript hat die Downloadaufgabe als "
"gescheitert markiert"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Doppelte NZB \"%s\" wird ignoriert"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "kopieren der NZB \"%s\" fehlgeschlagen"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Doppelte NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Doppelt vorhandene NZB \"%s\" angehalten"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1256,6 +1253,10 @@ msgstr "Fehler beim Importieren von %s"
msgid "DUPLICATE"
msgstr "DUPLIKAT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "VERSCHLÜSSELT"
@@ -1302,6 +1303,10 @@ msgstr "%s Artikel fehlten"
msgid "%s articles had non-matching duplicates"
msgstr "%s Artikel hatten nicht übereinstimmende Duplikate"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Doppelt vorhandene NZB \"%s\" angehalten"
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1534,6 +1539,12 @@ msgstr ""
"Alte Warteschlangen-Version erkannt, über Status->Reparieren ins neue Format"
" konvertieren"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr ""
"Kompilieren des regulären Ausdrucks für den Suchbegriff %s fehlgeschlagen."
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1721,10 +1732,6 @@ msgstr "Leerer RSS-Feed gefunden: %s"
msgid "Show interface"
msgstr "Interface anzeigen"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Öffne Zielverzeichnis"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1813,6 +1820,11 @@ msgstr "Entschleiern"
msgid "Script"
msgstr "Skript"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2185,11 +2197,6 @@ msgstr "Schalter"
msgid "Scheduling"
msgstr "Planung"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2304,11 +2311,6 @@ msgstr "Name"
msgid "Retry"
msgstr "Erneut versuchen"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Aktionen"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2645,7 +2647,6 @@ msgstr "Zeit seit Start"
msgid "Backup"
msgstr "Sicherheitskopie"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Lesen Sie dazu die Hilfe im Wiki!"
@@ -3238,28 +3239,20 @@ msgstr ""
"fortsetzen."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Doppelte Downloads erkennen"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
"Doppelte NZB Datei entdeckt (basierend auf den Eintragungen in der Historie "
"oder den .nzb Dateien im NZB-Backup-Ordner)"
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Doppelte Episoden in Serien erkennen"
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
"Identische Episoden in den Serien entdeckt (basierend auf "
"\"name/season/episode\") der Einträge in der Historie"
#: sabnzbd/skintext.py
msgid "Allow proper releases"
@@ -3267,11 +3260,9 @@ msgstr "Erlaube \"Proper\" Releases"
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
"Umgehe Serien Duplikat-Erkennung, wenn PROPER, REAL oder REPACK im Download-"
"Namen erkannt wird"
#. Four way switch for duplicates
#: sabnzbd/skintext.py
@@ -3362,6 +3353,14 @@ msgid "Used before an NZB enters the queue."
msgstr ""
"Wird verwendet, bevor eine NZB-Datei zur Warteschlange hinzugefügt wird."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Zusätzliche PAR2-Parameter"
@@ -4956,10 +4955,6 @@ msgstr ""
"Unbekanntes SSL-Protokoll: SSL deaktivieren oder alternativen Port "
"versuchen."
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Sever beendet beim Anmeldeverlauf."
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Server benötigt ein Benutzername und ein Passwort."

View File

@@ -124,4 +124,7 @@ msgid "0 is highest priority, 100 is the lowest priority"
msgstr "0 is highest priority, 99 is the lowest priority"
msgid "Filter out sample files (e.g. video samples)."
msgstr "Filter out sample files (e.g. video samples/proofs)."
msgstr "Filter out sample files (e.g. video samples/proofs)."
msgid "Pre-queue user script"
msgstr "Pre-queue script"

View File

@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"
@@ -188,11 +188,6 @@ msgstr "Ninguno"
msgid "Default"
msgstr "Predeterminado"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Compilación de regex para término fallo: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -281,7 +276,7 @@ msgstr "%s no es una dirección de correo electrónico válida."
msgid "Server address required"
msgstr "Se necesita la dirección del servidor"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Dirección del servidor no válida."
@@ -301,12 +296,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "Ruta de acceso UNC \"%s\" no permitido aqui"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Cola no esta vacía, no se puede cambiar el directorio"
#: sabnzbd/cfg.py
msgid ""
@@ -1113,6 +1108,16 @@ msgstr "Cola terminada"
msgid "Other Messages"
msgstr "Otros mensajes"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Abrir todo el folder"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "No disponible"
@@ -1196,6 +1201,18 @@ msgstr "Error al cargar %s, archivo corrupto"
msgid "NZB added to queue"
msgstr "NZB añadido a la cola"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorando NZB Duplicado \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Fallo al duplicar NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Duplicar NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1212,26 +1229,6 @@ msgstr ""
"La secuencia de comandos de la cola preestablecida ha marcado la tarea como "
"fallida"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorando NZB Duplicado \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Fallo al duplicar NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Duplicar NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pausando NZB duplicados \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1250,6 +1247,10 @@ msgstr "Error importando %s"
msgid "DUPLICATE"
msgstr "DUPLICADO"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ENCRIPTADO"
@@ -1295,6 +1296,10 @@ msgstr "%s artículos no encontrados"
msgid "%s articles had non-matching duplicates"
msgstr "%s artículos contenían duplicados inconexos"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pausando NZB duplicados \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1525,6 +1530,11 @@ msgstr ""
"Se ha encontrado una cola antigua, utilice Estado->Reparar para convertir la"
" cola"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Compilación de regex para término fallo: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1713,10 +1723,6 @@ msgstr "Entrada RSS vacía (%s)"
msgid "Show interface"
msgstr "Mostrar interfaz"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Abrir todo el folder"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1805,6 +1811,11 @@ msgstr ""
msgid "Script"
msgstr "Script"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2177,11 +2188,6 @@ msgstr "Switches"
msgid "Scheduling"
msgstr "Planificación"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2296,11 +2302,6 @@ msgstr "Nombre"
msgid "Retry"
msgstr "Reintentar"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Acciones"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2634,7 +2635,6 @@ msgstr "Tiempo en Activo"
msgid "Backup"
msgstr "Copia de seguridad"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Lee la ayuda en la Wiki (inglés) acerca de esto!"
@@ -3202,28 +3202,20 @@ msgstr ""
"trabajo."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Detectar descargas duplicadas"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
"Detecta archivos NZB idénticos (basándose en los elementos de su historial o"
" los archivos en el directorio de copia de seguridad .nzb)"
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Detectar episodios duplicadas en serie"
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
"Detecta episodios idénticos en series (basándose en "
"\"nombre/temporada/episodio\" de los elementos de su historial)"
#: sabnzbd/skintext.py
msgid "Allow proper releases"
@@ -3231,11 +3223,9 @@ msgstr "Permitir comunicados adecuados"
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
"Evitar detección de duplicado de series si se detecta PROPER, REAL o REPACK "
"en el nombre de la descarga"
#. Four way switch for duplicates
#: sabnzbd/skintext.py
@@ -3323,6 +3313,14 @@ msgstr "Script de usuario Pre-cola"
msgid "Used before an NZB enters the queue."
msgstr "Se usa precediendo a la entrada de un NZB en la cola del sistema."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Parámetros PAR2 extra"
@@ -4891,10 +4889,6 @@ msgstr ""
"Protocolo SSL desconocido: intente desabilitar el SSL o conectarse a un "
"puerto diferente."
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "El servidor se ha cerrado durante el login"
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "El servidor necesita usuario y contraseña."

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Finnish (https://app.transifex.com/sabnzbd/teams/111101/fi/)\n"
@@ -181,11 +181,6 @@ msgstr "Ei mitään"
msgid "Default"
msgstr "Oletus"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Regex käännös epäonnistui hakutermille: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -264,7 +259,7 @@ msgstr "%s ei ole kelvollinen sähköpostiosoite"
msgid "Server address required"
msgstr "Palvelimen osoite vaaditaan"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Virheellinen palvelimen osoite."
@@ -284,12 +279,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "TUNT polku \"%s\" ei ole sallittu"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Jono ei ole tyhjä, kansiota ei voida vaihtaa."
#: sabnzbd/cfg.py
msgid ""
@@ -1067,6 +1062,16 @@ msgstr "Jono valmistunut"
msgid "Other Messages"
msgstr "Muut viestit"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Avaa valmistuneet-kansio"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Ei saatavilla"
@@ -1147,6 +1152,18 @@ msgstr "Virhe ladattaessa %s, korruptoitunut tiedosto havaittu"
msgid "NZB added to queue"
msgstr "NZB lisätty jonoon"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ohitetaan kaksoiskappale NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1161,26 +1178,6 @@ msgstr "Tyhjä NZB tiedosto %s"
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ohitetaan kaksoiskappale NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Keskeytetään kaksoiskappale NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1199,6 +1196,10 @@ msgstr "Virhe tuotaessa %s"
msgid "DUPLICATE"
msgstr "KAKSOISKAPPALE"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "SALATTU"
@@ -1244,6 +1245,10 @@ msgstr "%s artikkelia puuttui"
msgid "%s articles had non-matching duplicates"
msgstr "%s artikkelissa oli ei-vastaavia kaksoiskappaleita"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Keskeytetään kaksoiskappale NZB \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1467,6 +1472,11 @@ msgstr "Virhe %s: Syötä kelvollinen käyttäjänimi ja salasana."
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "Vanhan version jono havaittiin, käytä Tila->Korjaa muuntaaksesi jonon"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Regex käännös epäonnistui hakutermille: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1651,10 +1661,6 @@ msgstr "Tyhjä RSS kohde löytyi (%s)"
msgid "Show interface"
msgstr "Näytä käyttöliittymä"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Avaa valmistuneet-kansio"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1743,6 +1749,11 @@ msgstr ""
msgid "Script"
msgstr "Skripti"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2115,11 +2126,6 @@ msgstr "Muuttujat"
msgid "Scheduling"
msgstr "Ajastus"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2234,11 +2240,6 @@ msgstr "Nimi"
msgid "Retry"
msgstr "Yritä uudelleen"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Toiminnot"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2564,7 +2565,6 @@ msgstr "Käynnissäoloaika"
msgid "Backup"
msgstr "Varmuuskopioi"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Lue Wikin ohjeet tähän!"
@@ -3127,23 +3127,19 @@ msgstr ""
" lataamista."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Tunnista päällekkäiset lataukset"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Tunnista identtiset jaksot sarjassa"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -3152,8 +3148,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3242,6 +3238,14 @@ msgstr "Esijonon käyttäjän skripti"
msgid "Used before an NZB enters the queue."
msgstr "Käytetään ennen NZB lisäämistä jonoon."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Ylimääräiset PAR2 parametrit"
@@ -4788,10 +4792,6 @@ msgid ""
msgstr ""
"Tuntematon SSL protokolla: Kokeile ottaa SSL käytöstä tai vaihda porttia."
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Palvelin lopetettiin kesken kirjautumisen"
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Palvelin vaatii käyttäjänimen ja salasanan."

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Fred L <88com88@gmail.com>, 2023\n"
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"
@@ -190,11 +190,6 @@ msgstr "Aucun"
msgid "Default"
msgstr "Par défaut"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Echec de la compilation de regex pour la recherche du terme : %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -283,7 +278,7 @@ msgstr "%s n'est pas une adresse email valide"
msgid "Server address required"
msgstr "Adresse du serveur requise"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Adresse du serveur erronée"
@@ -305,8 +300,8 @@ msgstr ""
"fichiers et dossiers qu'il crée."
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "Le chemin UNC \"%s\" n'est pas autorisé ici"
msgid "Network path \"%s\" is not allowed here"
msgstr "Le chemin réseau \"%s\" n'est pas autorisé ici"
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
@@ -1123,6 +1118,16 @@ msgstr "File d'attente terminée"
msgid "Other Messages"
msgstr "Autres messages"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Ouvrir le dossier des complets"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Non disponible"
@@ -1203,6 +1208,18 @@ msgstr "Erreur lors du chargement de %s, fichier corrompu détecté"
msgid "NZB added to queue"
msgstr "NZB ajouté à la file d'attente"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Doublon NZB ignoré \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Échec de duplication du NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Dupliquer NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1217,26 +1234,6 @@ msgstr "Fichier NZB %s vide"
msgid "Pre-queue script marked job as failed"
msgstr "Le script de pré-file d'attente a marqué la tâche comme échouée"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Doublon NZB ignoré \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Échec de duplication du NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Dupliquer NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Mise en pause du doublon NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1255,6 +1252,10 @@ msgstr "Erreur lors de l'importation de %s"
msgid "DUPLICATE"
msgstr "DOUBLON"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "ALTERNATIVE"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "CHIFFRÉ"
@@ -1300,6 +1301,10 @@ msgstr "%s articles manquants"
msgid "%s articles had non-matching duplicates"
msgstr "%s articles avec doublons sans correspondance"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Mise en pause du doublon NZB \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1531,6 +1536,11 @@ msgstr ""
"Ancienne file d'attente détectée, utiliser Statut-> Réparation pour "
"convertir la file d'attente"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Echec de la compilation de regex pour la recherche du terme : %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1720,10 +1730,6 @@ msgstr "Entrée vide de flux RSS trouvée (%s)"
msgid "Show interface"
msgstr "Afficher linterface"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Ouvrir le dossier des complets"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1812,6 +1818,11 @@ msgstr "Désobfuscation"
msgid "Script"
msgstr "Script"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2184,11 +2195,6 @@ msgstr "Switches"
msgid "Scheduling"
msgstr "Planification"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2303,11 +2309,6 @@ msgstr "Nom"
msgid "Retry"
msgstr "Réessayer"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Actions"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2646,7 +2647,6 @@ msgstr "Temps de fonctionnement"
msgid "Backup"
msgstr "Secours"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Consultez le Wiki pour plus d'info à ce sujet (en anglais) !"
@@ -3240,28 +3240,21 @@ msgstr ""
"tâche."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Détecter les doublons de téléchargement"
msgid "Identical download detection"
msgstr "Détection des téléchargements identiques"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
"Détecter les fichiers NZB identiques (en fonction des éléments de votre "
"historique ou des fichiers .nzb du dossier de backup)"
"Détecter les téléchargements identiques basés sur le nom ou le contenu NZB."
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Détecter les doublons d'épisodes de séries"
msgid "Smart duplicate detection"
msgstr "Détection intelligente des doublons"
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgstr ""
"Détecter les épisodes de série identiques (en fonction du modèle "
"\"nom/saison/épisode\" des éléments de votre historique)"
msgid "Detect duplicates based on analysis of the filename."
msgstr "Détecter les doublons basés sur l'analyse du nom de fichier."
#: sabnzbd/skintext.py
msgid "Allow proper releases"
@@ -3269,11 +3262,11 @@ msgstr "Autoriser les versions corrigées (proper)"
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
"Contourner la détection des doublons si PROPER, REAL ou REPACK est détecté "
"dans l'intitulé du téléchargement"
"dans l'intitulé du téléchargement."
#. Four way switch for duplicates
#: sabnzbd/skintext.py
@@ -3363,6 +3356,14 @@ msgstr "Script utilisateur de pré-file d'attente"
msgid "Used before an NZB enters the queue."
msgstr "Utilisé avant qu'un NZB n'entre dans la file d'attente."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr "Script de fin de file d'attente"
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr "Exécuté après la fin du téléchargement de la file d'attente."
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Paramètres PAR2 supplémentaires"
@@ -4964,10 +4965,6 @@ msgstr ""
"Protocole SSL inconnu: essayez de désactiver SSL ou de vous connecter sur un"
" autre port."
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Le serveur a interrompu l'ouverture de session."
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Le serveur requiert un identifiant et un mot de passe."

View File

@@ -2,14 +2,14 @@
# Copyright 2007-2023 The SABnzbd-Team
#
# Translators:
# ION, 2023
# Safihre <safihre@sabnzbd.org>, 2023
# ION, 2023
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Last-Translator: ION, 2023\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -30,7 +30,7 @@ msgstr "שגיאה"
#. Error message
#: SABnzbd.py
msgid "Failed to start web-interface"
msgstr "נכשל בהתחלת ממשק רשת"
msgstr "כישלון בהתחלת ממשק רשת"
#. Warning message
#: SABnzbd.py
@@ -116,7 +116,7 @@ msgstr "HTTPS הושבת בגלל קבצים בלתי תקפים של CERT ו־K
#. Error message
#: SABnzbd.py
msgid "Failed to start web-interface: "
msgstr "נכשל בהתחלת ממשק רשת: "
msgstr "כישלון בהתחלת ממשק רשת: "
#: SABnzbd.py
msgid "SABnzbd %s started"
@@ -178,11 +178,6 @@ msgstr "אין"
msgid "Default"
msgstr "ברירת מחדל"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "עבור מונח חיפוש regex נכשל בליקוט: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -262,7 +257,7 @@ msgstr "%s אינה כתובת דוא״ל תקפה"
msgid "Server address required"
msgstr "כתובת שרת דרושה"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "כתובת שרת בלתי תקפה."
@@ -283,12 +278,12 @@ msgstr ""
"הגדרת הרשאות של %s עשויה לדחות גישה מן SABnzbd אל הקבצים והתיקיות שהוא יוצר."
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "נתיב UNC \"%s\" אינו מותר כאן"
msgid "Network path \"%s\" is not allowed here"
msgstr "נתיב הרשת \"%s\" אינו מותר כאן"
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "התור אינו ריק, לא ניתן לשנות תיקייה."
#: sabnzbd/cfg.py
msgid ""
@@ -304,6 +299,8 @@ msgid ""
"Do not use a folder in the application folder as your Scripts Folder, it "
"might be emptied during updates."
msgstr ""
"אל תשתמש בתיקייה בתוך תיקיית היישום כתיקיית התסריטים שלך, היא עשויה להתרוקן "
"במהלך עדכונים."
#. Warning message
#: sabnzbd/config.py
@@ -348,7 +345,7 @@ msgstr "פקודת SQL נכשלה, ראה יומן"
#. Error message
#: sabnzbd/database.py
msgid "Failed to close database, see log"
msgstr "נכשל בסגירת מסד נתונים, ראה יומן"
msgstr "כישלון בסגירת מסד נתונים, ראה יומן"
#. Warning message
#: sabnzbd/database.py
@@ -444,12 +441,12 @@ msgstr "אין שרתים פעילים!"
#. Error message
#: sabnzbd/downloader.py
msgid "Failed to initialize %s@%s with reason: %s"
msgstr "נכשל באתחול %s@%s עם סיבה: %s"
msgstr "כישלון באתחול %s@%s עם סיבה: %s"
#. Error message
#: sabnzbd/downloader.py
msgid "Fatal error in Downloader"
msgstr ""
msgstr "שגיאה גורלית במורידן"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
@@ -460,10 +457,12 @@ msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgstr ""
"כניסה מיותר מדי כתובות IP שונות אל שרת %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "נכשל בכניסה אל השרת %s [%s]"
msgstr "כניסה נכשלה עבור שרת %s [%s]"
#. Error message
#: sabnzbd/downloader.py
@@ -491,11 +490,11 @@ msgstr "השרת %s השתמש במכסה המצויינת"
#: sabnzbd/emailer.py
msgid "Failed to connect to mail server"
msgstr "נכשל בהתחברות אל שרת דוא״ל"
msgstr "כישלון בהתחברות אל שרת דוא״ל"
#: sabnzbd/emailer.py
msgid "Failed to initiate TLS connection"
msgstr "נכשל ביזימת חיבור TLS"
msgstr "כישלון ביזימת חיבור TLS"
#: sabnzbd/emailer.py
msgid "The server didn't reply properly to the helo greeting"
@@ -503,7 +502,7 @@ msgstr "השרת לא הגיב כראוי לברכת השלום"
#: sabnzbd/emailer.py
msgid "Failed to authenticate to mail server"
msgstr "נכשל באימות שרת הדוא״ל"
msgstr "כישלון באימות שרת הדוא״ל"
#: sabnzbd/emailer.py
msgid "No suitable authentication method was found"
@@ -515,11 +514,11 @@ msgstr "כישלון בלתי ידוע של אימות בשרת דוא״ל"
#: sabnzbd/emailer.py
msgid "Failed to send e-mail"
msgstr "נכשל בשליחת דוא״ל"
msgstr "כישלון בשליחת דוא״ל"
#: sabnzbd/emailer.py
msgid "Failed to close mail connection"
msgstr "נכשל בסגירת חיבור דוא״ל"
msgstr "כישלון בסגירת חיבור דוא״ל"
#: sabnzbd/emailer.py, sabnzbd/notifier.py
msgid "Cannot send, missing required data"
@@ -583,12 +582,12 @@ msgstr "לא ניתן לשנות הרשאות של %s"
#. Error message
#: sabnzbd/filesystem.py
msgid "Failed making (%s)"
msgstr "נכשל בעשייה (%s)"
msgstr "כישלון בעשייה (%s)"
#. Error message
#: sabnzbd/filesystem.py, sabnzbd/postproc.py
msgid "Failed moving %s to %s"
msgstr "נכשל בהעברת %s אל %s"
msgstr "כישלון בהעברת %s אל %s"
#. Error message
#: sabnzbd/filesystem.py
@@ -618,12 +617,12 @@ msgstr "%s אינו בר־כתיבה בכלל. זה חוסם הורדות."
#. Warning message
#: sabnzbd/filesystem.py
msgid "Cannot write a long filename to %s. This can cause problems."
msgstr ""
msgstr "בלתי ניתן לכתוב שם ארוך של קובץ אל %s. זה עשוי לגרום לבעיות."
#. Warning message
#: sabnzbd/filesystem.py
msgid "Cannot write a unicode filename to %s. This can cause problems."
msgstr ""
msgstr "בלתי ניתן לכתוב שם יוניקוד של קובץ אל %s. זה עשוי לגרום לבעיות."
#. Warning message
#: sabnzbd/filesystem.py
@@ -757,12 +756,12 @@ msgstr "עדכון זמין!"
#. Error message
#: sabnzbd/misc.py
msgid "Failed to upload file: %s"
msgstr "נכשל בהעלאת קובץ: %s"
msgstr "כישלון בהעלאת קובץ: %s"
#. Error message
#: sabnzbd/misc.py
msgid "Error creating SSL key and certificate"
msgstr "נכשל ביצירה של מפתח ותעודה של SSL"
msgstr "כישלון ביצירה של מפתח ותעודה של SSL"
#. Warning message
#: sabnzbd/misc.py
@@ -776,7 +775,7 @@ msgstr ""
#. Warning message
#: sabnzbd/misc.py
msgid "Failed to read the password file %s"
msgstr "נכשל בקריאת קובץ הסיסמה %s"
msgstr "כישלון בקריאת קובץ הסיסמה %s"
#. Error message
#: sabnzbd/misc.py
@@ -1070,18 +1069,28 @@ msgstr "תור הסתיים"
msgid "Other Messages"
msgstr "הודעות אחרות"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "פתח תיקיית השלמה"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "לא זמין"
#: sabnzbd/notifier.py
msgid "Failed to send macOS notification"
msgstr "נכשל בשליחת התראת macOS"
msgstr "כישלון בשליחת התראת macOS"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Prowl message"
msgstr "נכשל בשליחת הודעת Prowl"
msgstr "כישלון בשליחת הודעת Prowl"
#. Error message
#: sabnzbd/notifier.py
@@ -1091,7 +1100,7 @@ msgstr "תגובה רעה מאת Pushover (%s): %s"
#. Error message - Warning message
#: sabnzbd/notifier.py
msgid "Failed to send pushover message"
msgstr "נכשל בשליחת הודעת Pushover"
msgstr "כישלון בשליחת הודעת Pushover"
#. Error message
#: sabnzbd/notifier.py
@@ -1101,7 +1110,7 @@ msgstr "תגובה רעה מאת Pushbullet (%s): %s"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send pushbullet message"
msgstr "Pushbullet נכשל בשליחת הודעת"
msgstr "כישלון בשליחת הודעת Pushbullet"
#. Error message
#: sabnzbd/notifier.py
@@ -1114,7 +1123,7 @@ msgstr "תסריט ההתראה \"%s\" אינו קיים"
#: sabnzbd/notifier.py
msgid "Failed to send Windows notification"
msgstr "נכשל בשליחת התראת Windows"
msgstr "כישלון בשליחת התראת Windows"
#. Error message
#: sabnzbd/nzbparser.py
@@ -1134,7 +1143,7 @@ msgstr "שגיאה בהסרת %s"
#. Warning message
#: sabnzbd/nzbparser.py
msgid "Failed to import %s files from %s"
msgstr "נכשל ביבוא %s קבצים מן %s"
msgstr "כישלון ביבוא %s קבצים מן %s"
#. Error message
#: sabnzbd/nzbqueue.py
@@ -1150,6 +1159,18 @@ msgstr "שגיאה בטעינת %s, קובץ פגום התגלה"
msgid "NZB added to queue"
msgstr "NZB התווסף לתור"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "מתעלם מן NZB כפול \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "מכשיל NZB כפול \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "NZB כפול"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1164,26 +1185,6 @@ msgstr "קובץ NZB ריק %s"
msgid "Pre-queue script marked job as failed"
msgstr "תסריט קדם־תור סומן כנכשל"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "מתעלם מן NZB כפול \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "מכשיל NZB כפול \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "NZB כפול"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "משהה NZB כפול \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1202,6 +1203,10 @@ msgstr "שגיאה ביבוא %s"
msgid "DUPLICATE"
msgstr "כפול"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "חלופה"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "מוצפן"
@@ -1247,6 +1252,10 @@ msgstr "%s מאמרים היו חסרים"
msgid "%s articles had non-matching duplicates"
msgstr "אל %s מאמרים יש כפילויות בלתי תואמות"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "משהה NZB כפול \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1472,6 +1481,11 @@ msgstr "שגיאה %s: אתה צריך לספק שם משתמש וסיסמה ת
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "תור ישן התגלה, השתמש במעמד->תיקון כדי להמיר את התור"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "כישלון בליקוט ביטוי רגולרי עבור מונח חיפוש: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1508,7 +1522,7 @@ msgstr "שגיאה בשינוי שם \"%s\" אל \"%s\""
#: sabnzbd/postproc.py
msgid "Failed to move files"
msgstr "נכשל בהעברת קבצים"
msgstr "כישלון בהעברת קבצים"
#: sabnzbd/postproc.py
msgid "Running user script %s"
@@ -1602,12 +1616,12 @@ msgstr "הסרת %s נכשלה"
#. Error message
#: sabnzbd/powersup.py
msgid "Failed to hibernate system"
msgstr "נכשל בחריפת מערכת"
msgstr "כישלון בחריפת מערכת"
#. Error message
#: sabnzbd/powersup.py
msgid "Failed to standby system"
msgstr "נכשל בהיכוננות מערכת"
msgstr "כישלון בהיכוננות מערכת"
#. Error message
#: sabnzbd/powersup.py
@@ -1634,7 +1648,7 @@ msgstr "שגיאת צד שרת (קוד שרת %s); לא היה ניתן להשי
#: sabnzbd/rss.py
msgid "Failed to retrieve RSS from %s: %s"
msgstr "נכשל באחזור RSS מן %s: %s"
msgstr "כישלון באחזור RSS מן %s: %s"
#: sabnzbd/rss.py, sabnzbd/urlgrabber.py
msgid "Server %s uses an untrusted HTTPS certificate"
@@ -1658,10 +1672,6 @@ msgstr "כניסת RSS ריקה נמצאה (%s)"
msgid "Show interface"
msgstr "הראה ממשק"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "פתח תיקיית השלמה"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1750,6 +1760,11 @@ msgstr "אי־האפלה"
msgid "Script"
msgstr "תסריט"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2122,11 +2137,6 @@ msgstr "מתגים"
msgid "Scheduling"
msgstr "תזמון"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2241,11 +2251,6 @@ msgstr "שם"
msgid "Retry"
msgstr "נסה שוב"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "פעולות"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2559,6 +2564,7 @@ msgid ""
"Speed up repairs by installing par2cmdline-turbo, it is available for many "
"platforms."
msgstr ""
"האץ תיקונים ע״י התקנת par2cmdline-turbo, הוא זמין עבור פלטפורמות רבות."
#: sabnzbd/skintext.py
msgid "Version"
@@ -2573,7 +2579,6 @@ msgstr "זמן פעולה"
msgid "Backup"
msgstr "גיבוי"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "קרא את עזרת וויקי על זה!"
@@ -2932,7 +2937,7 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Use Sorting to automatically organize and rename your completed downloads."
msgstr ""
msgstr "השתמש במיון כדי לארגן ולשנות שם באופן אוטומטי את ההורדות השלמות שלך."
#: sabnzbd/skintext.py
msgid "Minimum Free Space for Completed Download Folder"
@@ -3015,7 +3020,7 @@ msgstr "תיקיות מערכת"
#: sabnzbd/skintext.py
msgid "Hidden Folders"
msgstr ""
msgstr "תיקיות מוסתרות"
#: sabnzbd/skintext.py
msgid "Administrative Folder"
@@ -3058,7 +3063,7 @@ msgstr ""
#: sabnzbd/skintext.py
msgid "Purge Logs"
msgstr ""
msgstr "טהר יומנים"
#: sabnzbd/skintext.py
msgid ".nzb Backup Folder"
@@ -3131,25 +3136,20 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
msgstr "במקרה של \"השהיה\", תצטרך לקבוע סיסמה ולהמשיך את העבודה."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "גלה הורדות כפולות"
msgid "Identical download detection"
msgstr "גילוי הורדה זהה"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgstr ""
"גלה קבצי NZB זהים (על סמך פריטים בהיסטוריה שלך או קבצים בתיקיית גיבוי .nzb)"
msgid "Detect identical downloads based on name or NZB contents."
msgstr "גלה הורדות זהות על סמך שם או תכני NZB."
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "גלה פרקים כפולים בסדרות"
msgid "Smart duplicate detection"
msgstr "גילוי שכפולים חכם"
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgstr "גלה פרקים זהים בסדרות (על סמך \"שם/עונה/פרק\" של פריטים בהיסטוריה שלך)"
msgid "Detect duplicates based on analysis of the filename."
msgstr "גלה שכפולים על סמך ניתוח של שם הקובץ."
#: sabnzbd/skintext.py
msgid "Allow proper releases"
@@ -3157,9 +3157,9 @@ msgstr "התר שחרורים תקינים"
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
msgstr "עקוף גילוי כפילויות סדרה אם PROPER, REAL או REPACK מתגלים בשם ההורדה"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr "עקוף גילוי שכפולים חכם אם PROPER, REAL או REPACK מתגלים בשם ההורדה."
#. Four way switch for duplicates
#: sabnzbd/skintext.py
@@ -3219,14 +3219,13 @@ msgstr "בצע וידוא נוסף שמבוסס על קבצי SFV."
#: sabnzbd/skintext.py
msgid "User script can flag job as failed"
msgstr "תסריט משתמש יכול לסמן בדגל עבודה כנכשלה"
msgstr "תסריט משתמש יכול לדגל עבודה כנכשלה"
#: sabnzbd/skintext.py
msgid ""
"When the user script returns a non-zero exit code, the job will be flagged "
"as failed."
msgstr ""
"כאשר תסריט המשתמש מחזיר קוד יציאה בלתי אפסי, העבודה תסומן בדגל כנכשלה."
msgstr "כאשר תסריט המשתמש מחזיר קוד יציאה בלתי אפסי, העבודה תדוגל כנכשלה."
#: sabnzbd/skintext.py
msgid "Enable folder rename"
@@ -3248,6 +3247,14 @@ msgstr "תסריט משתמש של קדם־תור"
msgid "Used before an NZB enters the queue."
msgstr "בשימוש לפני ש־NZB נכנס לתור."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr "תסריט בסיום תור"
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr "מבוצע לאחר שהתור יסיים להוריד."
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "פרמטרי PAR2 נוספים"
@@ -4118,7 +4125,7 @@ msgstr "שם_סרט"
#: sabnzbd/skintext.py
msgid "Show Name"
msgstr "הראה שם"
msgstr "שם סדרה"
#: sabnzbd/skintext.py
msgid "Show.Name"
@@ -4126,7 +4133,7 @@ msgstr "שם.סדרה"
#: sabnzbd/skintext.py
msgid "Show_Name"
msgstr "הראה_שם"
msgstr "שם_סדרה"
#: sabnzbd/skintext.py
msgid "Season Number"
@@ -4190,15 +4197,15 @@ msgstr "מחרוזת מיון"
#: sabnzbd/skintext.py
msgid "Multi-part Label"
msgstr ""
msgstr "תווית מרובת־חלקים"
#: sabnzbd/skintext.py
msgid "Show folder"
msgstr ""
msgstr "תיקיית סדרה"
#: sabnzbd/skintext.py
msgid "Season folder"
msgstr ""
msgstr "תיקיית עונה"
#: sabnzbd/skintext.py
msgid "In folders"
@@ -4214,7 +4221,7 @@ msgstr "שם עבודה בתור שם קובץ"
#: sabnzbd/skintext.py
msgid "Series"
msgstr ""
msgstr "סדרות"
#. Note for title expression in Sorting that does case adjustment
#: sabnzbd/skintext.py
@@ -4247,27 +4254,27 @@ msgstr "GuessIt_Property"
#: sabnzbd/skintext.py
msgid "Minimum Filesize"
msgstr ""
msgstr "גודל מזערי של קובץ"
#: sabnzbd/skintext.py
msgid "Affected Job Types"
msgstr ""
msgstr "סוגי עבודה מושפעים"
#: sabnzbd/skintext.py
msgid "All"
msgstr "הכל"
msgstr "הכול"
#: sabnzbd/skintext.py
msgid "Series with air dates"
msgstr ""
msgstr "סדרות עם תאריכי שידור"
#: sabnzbd/skintext.py
msgid "Movies"
msgstr ""
msgstr "סרטים"
#: sabnzbd/skintext.py
msgid "Other / Unknown"
msgstr ""
msgstr "אחר / בלתי ידוע"
#: sabnzbd/skintext.py
msgid ""
@@ -4279,34 +4286,39 @@ msgid ""
"applied.</p><p>More options are available when Advanced Settings is "
"checked.<br/>Detailed information can be found on the Wiki.</p>"
msgstr ""
"<p>השתמש בממיינים כדי לארגן באופן אוטומטי את ההורדות השלמות שלך. לדוגמה, שים"
" את כל הפרקים מסדרה בתיקייה של עונה מסויימת.</p><p>ממיינים מנוסים לפי סדר "
"הופעתם ויכולים להסתדר מחדש על ידי גרירה ושחרור.<br/>הממיין הפעיל הראשון "
"שתואם אל הקטגוריה המושפעת ואל סוג העבודה הוא זה שמוחל.</p><p>עוד אפשרויות "
"זמינות כאשר האפשרות הגדרות מתקדמות מסומנת.<br/>מידע מפורט נמצא בוויקי.</p>"
#: sabnzbd/skintext.py
msgid "Add Sorter"
msgstr ""
msgstr "הוסף ממיין"
#: sabnzbd/skintext.py
msgid "Remove Sorter"
msgstr ""
msgstr "הסר ממיין"
#: sabnzbd/skintext.py
msgid "Test Data"
msgstr ""
msgstr "בחן נתונים"
#: sabnzbd/skintext.py
msgid "Quick start"
msgstr ""
msgstr "התחלה זריזה"
#: sabnzbd/skintext.py
msgid ""
"Move and rename all episodes in the \"tv\" category to a show-specific "
"folder"
msgstr ""
msgstr "העבר ושנה שם את כל הפרקים בקטגוריה \"טלוויזיה\" אל תיקייה של סדרה מסויימת"
#: sabnzbd/skintext.py
msgid ""
"Move and rename all movies in the \"movies\" category to a movie-specific "
"folder"
msgstr ""
msgstr "העבר ושנה שם את כל הסרטים בקטגוריה \"סרטים\" אל תיקייה של סרט מסויים"
#: sabnzbd/skintext.py
msgid ""
@@ -4548,7 +4560,7 @@ msgstr "קיצורי דרך במקלדת"
#: sabnzbd/skintext.py
msgid "Shift+Arrow key: Browse Queue and History pages"
msgstr ""
msgstr "Shift+מקש חץ: עיין בתור ובדפי היסטוריה"
#: sabnzbd/skintext.py
msgid "How long or untill when do you want to pause? (in English!)"
@@ -4727,12 +4739,12 @@ msgstr ""
#. Error message
#: sabnzbd/sorting.py
msgid "Failed to rename %s to %s"
msgstr ""
msgstr "כישלון בשינוי שם %s אל %s"
#. Error message
#: sabnzbd/sorting.py
msgid "Failed to rename similar file: %s to %s"
msgstr "נכשל בשינוי שם של קובץ דומה: %s אל %s"
msgstr "כישלון בשינוי שם של קובץ דומה: %s אל %s"
#: sabnzbd/urlgrabber.py
msgid "Unauthorized access"
@@ -4792,10 +4804,6 @@ msgid ""
"Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr "פרוטוקול SSL בלתי ידוע: נסה להשבית SSL או להתחבר על פתחה שונה."
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "שרת יצא במהלך רצף כניסות."
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr ".השרת דורש שם משתמש וסיסמה"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"
@@ -177,11 +177,6 @@ msgstr "Ingen"
msgid "Default"
msgstr "Standard"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Kunne ikke lage regex for søkestreng: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -260,7 +255,7 @@ msgstr "%s er ikke en godkjent e-post-adresse"
msgid "Server address required"
msgstr "Krever server-adresse"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Ugyldig server-adresse."
@@ -280,12 +275,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "UNC-sti \"%s\" er ikke tillatt her"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Køen er ikke tom, kan ikke bytte mappe."
#: sabnzbd/cfg.py
msgid ""
@@ -1063,6 +1058,16 @@ msgstr "Køen er ferdig"
msgid "Other Messages"
msgstr "Andre meldinger"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Åpne fullført mappe"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Ikke tilgjengelig"
@@ -1143,6 +1148,18 @@ msgstr "Lastingsfeil %s, feilaktig fil oppdaget"
msgid "NZB added to queue"
msgstr "NZB er lagt til i køen"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorerer duplikatfil \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1157,26 +1174,6 @@ msgstr "Tom NZB-fil %s"
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorerer duplikatfil \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Stanser duplikatfil \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1195,6 +1192,10 @@ msgstr "Kunne ikke importere %s"
msgid "DUPLICATE"
msgstr "DUPLIKAT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "KRYPTERT"
@@ -1240,6 +1241,10 @@ msgstr "%s artikler manglet"
msgid "%s articles had non-matching duplicates"
msgstr "%s artikler hadde ulike duplikater"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Stanser duplikatfil \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1463,6 +1468,11 @@ msgstr "Feil %s: Du må oppgi et gyldig brukernavn og passord."
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "Gammel kø oppdaget. Bruk Status -> Reparer for å konvertere køen"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Kunne ikke lage regex for søkestreng: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1647,10 +1657,6 @@ msgstr "Tom RSS post funnet (%s)"
msgid "Show interface"
msgstr "Vis grensesnitt"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Åpne fullført mappe"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1739,6 +1745,11 @@ msgstr ""
msgid "Script"
msgstr "Skript"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2111,11 +2122,6 @@ msgstr "Svitsjer"
msgid "Scheduling"
msgstr "Nedlastingsplan"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2230,11 +2236,6 @@ msgstr "Navn"
msgid "Retry"
msgstr "Prøv igjen"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Hendelser"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2558,7 +2559,6 @@ msgstr "Oppetid"
msgid "Backup"
msgstr "Sikkerhetskopi"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Les Wiki Help fer dette!"
@@ -3108,23 +3108,19 @@ msgstr ""
"I tilfelle \"Pause\", så trenger du å sette et passord og gjenoppta jobben."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Oppdag duplikatnedlastinger"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Oppdag duplikat episoder i serie"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -3133,8 +3129,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3223,6 +3219,14 @@ msgstr "Før-kø bruker skript"
msgid "Used before an NZB enters the queue."
msgstr "Brukes før en NZB blir lagt til kø"
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Ekstra PAR2 parametere"
@@ -4759,10 +4763,6 @@ msgstr ""
"Ukjent SSL-protokoll: Prøv å deaktivere SSL eller koble til på en annen "
"port."
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Server avbrøt undet innloggingssekvens"
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Server krever brukernavn og passord."

View File

@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"
@@ -185,11 +185,6 @@ msgstr "Geen"
msgid "Default"
msgstr "Standaard"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Het compileren van 'regex' voor de zoekterm lukt niet: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -276,7 +271,7 @@ msgstr "%s is geen geldig e-mailadres"
msgid "Server address required"
msgstr "Serveradres verplicht"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Ongeldige servernaam"
@@ -298,12 +293,12 @@ msgstr ""
"tot de aangemaakte bestanden en mappen."
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "UNC-pad '%s' hier niet toegestaan."
msgid "Network path \"%s\" is not allowed here"
msgstr "Netwerk-pad \"%s\" hier niet toegestaan."
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Wachtrij is niet leeg, andere map kiezen niet mogelijk."
#: sabnzbd/cfg.py
msgid ""
@@ -319,6 +314,9 @@ msgid ""
"Do not use a folder in the application folder as your Scripts Folder, it "
"might be emptied during updates."
msgstr ""
"Als de Map voor scripts zich in de SABnzbd installatie-map bevindt kan deze "
"automatisch verwijderd worden tijdens updates. We adviseren een andere "
"locatie te gebruiken voor je scripts."
#. Warning message
#: sabnzbd/config.py
@@ -472,7 +470,7 @@ msgstr "Initialisatie van %s@%s mislukt, vanwege: %s"
#. Error message
#: sabnzbd/downloader.py
msgid "Fatal error in Downloader"
msgstr ""
msgstr "Onherstelbare fout in de Downloader"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
@@ -646,11 +644,15 @@ msgstr ""
#: sabnzbd/filesystem.py
msgid "Cannot write a long filename to %s. This can cause problems."
msgstr ""
"Bestanden met lange bestandsnamen kunnen niet worden opgeslagen in %s. Dit "
"kan voor problemen zorgen tijdens het downloaden."
#. Warning message
#: sabnzbd/filesystem.py
msgid "Cannot write a unicode filename to %s. This can cause problems."
msgstr ""
"Bestanden met speciale karakters in de bestandsnaam kunnen niet worden "
"opgeslagen in %s. Dit kan voor problemen zorgen tijdens het downloaden."
#. Warning message
#: sabnzbd/filesystem.py
@@ -1109,6 +1111,16 @@ msgstr "Wachtrij voltooid"
msgid "Other Messages"
msgstr "Andere berichten"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Open map met voltooide downloads"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Niet beschikbaar"
@@ -1189,6 +1201,18 @@ msgstr "Fout bij inladen van %s, corrupt bestand gevonden"
msgid "NZB added to queue"
msgstr "Download aan wachtrij toegevoegd"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Dubbele download \"%s\" overgeslagen"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Download '%s' geweigerd omdat het een dubbele is"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Dubbele download"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1203,26 +1227,6 @@ msgstr "NZB-bestand %s is leeg"
msgid "Pre-queue script marked job as failed"
msgstr "Wachtrij filter script heeft de download afgekeurd"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Dubbele download \"%s\" overgeslagen"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Download '%s' geweigerd omdat het een dubbele is"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "Dubbele download"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Dubbele download \"%s\" gepauzeerd"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1241,6 +1245,10 @@ msgstr "Fout bij importeren van %s"
msgid "DUPLICATE"
msgstr "DUBBEL"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "ALTERNATIEF"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "VERSLEUTELD"
@@ -1286,6 +1294,10 @@ msgstr "%s artikelen ontbreken"
msgid "%s articles had non-matching duplicates"
msgstr "%s artikelen hadden afwijkende duplicaten"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Dubbele download \"%s\" gepauzeerd"
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1511,6 +1523,11 @@ msgstr "Fout %s: Je moet een geldige gebruikersnaam en wachtwoord invullen."
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "Oude wachtrij gevonden, gebruik Status->Reparatie om te converteren"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Het compileren van 'regex' voor de zoekterm lukt niet: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1698,10 +1715,6 @@ msgstr "Lege RSS-feed gevonden (%s)"
msgid "Show interface"
msgstr "Toon webinterface"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Open map met voltooide downloads"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1790,6 +1803,11 @@ msgstr "Bestandsnaam verbeteren"
msgid "Script"
msgstr "Script"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2162,11 +2180,6 @@ msgstr "Opties"
msgid "Scheduling"
msgstr "Taakplanner"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2281,11 +2294,6 @@ msgstr "Naam"
msgid "Retry"
msgstr "Opnieuw"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Acties"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2605,6 +2613,8 @@ msgid ""
"Speed up repairs by installing par2cmdline-turbo, it is available for many "
"platforms."
msgstr ""
"Versnel reparaties door par2cmdline-turbo te installeren. Beschikbaar voor "
"veel besturingssystemen."
#: sabnzbd/skintext.py
msgid "Version"
@@ -2619,7 +2629,6 @@ msgstr "Tijd in de lucht"
msgid "Backup"
msgstr "Reserve"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Lees de Wiki pagina over dit onderwerp"
@@ -2987,6 +2996,8 @@ msgstr "(kan aangepast worden door de categorieën)."
msgid ""
"Use Sorting to automatically organize and rename your completed downloads."
msgstr ""
"Gebruik Sorteren om automatisch je voltooide downloads te organiseren en "
"hernoemen."
#: sabnzbd/skintext.py
msgid "Minimum Free Space for Completed Download Folder"
@@ -3071,7 +3082,7 @@ msgstr "Systeemmappen"
#: sabnzbd/skintext.py
msgid "Hidden Folders"
msgstr ""
msgstr "Verborgen mappen"
#: sabnzbd/skintext.py
msgid "Administrative Folder"
@@ -3118,7 +3129,7 @@ msgstr ""
#: sabnzbd/skintext.py
msgid "Purge Logs"
msgstr ""
msgstr "Logs wissen"
#: sabnzbd/skintext.py
msgid ".nzb Backup Folder"
@@ -3197,28 +3208,22 @@ msgstr ""
"download vrij te geven"
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Detecteer dubbele downloads"
msgid "Identical download detection"
msgstr "Identieke downloaddetectie"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
"Detecteer identieke downloads (op basis van downloads in je Geschiedenis of "
"bestanden in je .nzb backup map)."
"Detecteer identieke downloads op basis van de naam of de inhoud van de NZB."
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Detecteer dubbele afleveringen in series"
msgid "Smart duplicate detection"
msgstr "Slimme detectie van dubbele downloads"
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
"Detecteer identieke afleveringen in series (gebaseerd op "
"\"naam/seizoen/aflevering\" van downloads in je Geschiedenis)."
"Detecteer dubbele downloads op basis van de analyse van de bestandsnaam."
#: sabnzbd/skintext.py
msgid "Allow proper releases"
@@ -3226,11 +3231,11 @@ msgstr "Sta verbeterde downloads toe"
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
"Sla dubbele download detectie over als er in de naam van de download PROPER,"
" REAL of REPACK bevat"
"Sla slimme detectie van dubbele downloads over als de naam van de download "
"PROPER, REAL of REPACK bevat."
#. Four way switch for duplicates
#: sabnzbd/skintext.py
@@ -3320,6 +3325,14 @@ msgstr "Wachtrij-filter script"
msgid "Used before an NZB enters the queue."
msgstr "Word uitgevoerd vóór een download aan de wachtrij word toegevoegd"
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr "Script voor na het afronden van de wachtrij"
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr "Script wordt uitgevoerd nadat de wachtrij is gedownload."
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Extra PAR2 parameters"
@@ -4290,15 +4303,15 @@ msgstr "Sorteertekst"
#: sabnzbd/skintext.py
msgid "Multi-part Label"
msgstr ""
msgstr "Meervoudig label"
#: sabnzbd/skintext.py
msgid "Show folder"
msgstr ""
msgstr "Map per serie"
#: sabnzbd/skintext.py
msgid "Season folder"
msgstr ""
msgstr "Map per seizoen"
#: sabnzbd/skintext.py
msgid "In folders"
@@ -4314,7 +4327,7 @@ msgstr "Downloadnaam als Bestandsnaam"
#: sabnzbd/skintext.py
msgid "Series"
msgstr ""
msgstr "Series"
#. Note for title expression in Sorting that does case adjustment
#: sabnzbd/skintext.py
@@ -4351,7 +4364,7 @@ msgstr "Minimale bestandsgrootte"
#: sabnzbd/skintext.py
msgid "Affected Job Types"
msgstr ""
msgstr "Type downloads"
#: sabnzbd/skintext.py
msgid "All"
@@ -4359,15 +4372,15 @@ msgstr "alles"
#: sabnzbd/skintext.py
msgid "Series with air dates"
msgstr ""
msgstr "Series met datums"
#: sabnzbd/skintext.py
msgid "Movies"
msgstr ""
msgstr "Films"
#: sabnzbd/skintext.py
msgid "Other / Unknown"
msgstr ""
msgstr "Anders / Onbekend"
#: sabnzbd/skintext.py
msgid ""
@@ -4379,34 +4392,43 @@ msgid ""
"applied.</p><p>More options are available when Advanced Settings is "
"checked.<br/>Detailed information can be found on the Wiki.</p>"
msgstr ""
"<p>Gebruik Sorteren om automatisch je voltooide downloads te organiseren. Bijvoorbeeld het automatisch verplaatsen van alle afleveringen van een serie in een seizoensspecifieke map. Of plaats films in een map met de naam van de film.</p>\n"
"\n"
"<p>Sorteringen worden in de getoonde volgorde geprobeerd en kunnen worden herschikt door ze te slepen.<br/> De eerste actieve Sortering die overeenkomt met zowel de betreffende categorie als het type taak wordt toegepast.</p>\n"
"\n"
"<p>Meer opties zijn beschikbaar wanneer Geavanceerde instellingen zijn aangevinkt.<br/> Gedetailleerde informatie is te vinden op de Wiki.</p>"
#: sabnzbd/skintext.py
msgid "Add Sorter"
msgstr ""
msgstr "Sortering toevoegen"
#: sabnzbd/skintext.py
msgid "Remove Sorter"
msgstr ""
msgstr "Sortering verwijderen"
#: sabnzbd/skintext.py
msgid "Test Data"
msgstr ""
msgstr "Testgegevens"
#: sabnzbd/skintext.py
msgid "Quick start"
msgstr ""
msgstr "Snel beginnen"
#: sabnzbd/skintext.py
msgid ""
"Move and rename all episodes in the \"tv\" category to a show-specific "
"folder"
msgstr ""
"Verplaats en hernoem alle afleveringen in de \"tv\" categorie naar een "
"specifieke map voor de serie."
#: sabnzbd/skintext.py
msgid ""
"Move and rename all movies in the \"movies\" category to a movie-specific "
"folder"
msgstr ""
"Verplaats en hernoem alle films in de categorie \"films\" naar een "
"specifieke map voor de film."
#: sabnzbd/skintext.py
msgid ""
@@ -4649,7 +4671,7 @@ msgstr "Sneltoetsen"
#: sabnzbd/skintext.py
msgid "Shift+Arrow key: Browse Queue and History pages"
msgstr ""
msgstr "Shift+Pijltoets: Blader door de wachtrij- en geschiedenispagina's"
#: sabnzbd/skintext.py
msgid "How long or untill when do you want to pause? (in English!)"
@@ -4828,7 +4850,7 @@ msgstr ""
#. Error message
#: sabnzbd/sorting.py
msgid "Failed to rename %s to %s"
msgstr ""
msgstr "Hernoemen van %s naar %s mislukt"
#. Error message
#: sabnzbd/sorting.py
@@ -4896,10 +4918,6 @@ msgid ""
msgstr ""
"Onbekend SSL protocol: probeer het zonder SSL of probeer een andere poort."
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "De server stopte tijdens de login"
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Server heeft een gebruikersnaam en een wachtwoord nodig."

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Polish (https://app.transifex.com/sabnzbd/teams/111101/pl/)\n"
@@ -173,11 +173,6 @@ msgstr "Brak"
msgid "Default"
msgstr "Domyślne"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Błąd kompilacji wyrażenia regularnego dla wyszukiwania: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -256,7 +251,7 @@ msgstr "%s nie jest prawidłowym adresem email"
msgid "Server address required"
msgstr "Wymagane jest podanie adresu serwera"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Nieprawidłowy adres serwera."
@@ -276,12 +271,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "Ścieżka UNC \"%s\" niedozwolona"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Kolejka nie jest pusta, nie można zmienić katalogu."
#: sabnzbd/cfg.py
msgid ""
@@ -1065,6 +1060,16 @@ msgstr "Kolejka ukończona"
msgid "Other Messages"
msgstr "Inne komunikaty"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Otwórz katalog zakończonych"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Niedostępne"
@@ -1145,6 +1150,18 @@ msgstr "Błąd ładowania %s, wykryto uszkodzony plik"
msgid "NZB added to queue"
msgstr "NZB dodany do kolejki"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignoruję zduplikowany NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1159,26 +1176,6 @@ msgstr "Pusty plik NZB %s"
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignoruję zduplikowany NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Wstrzymuję zduplikowany NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1197,6 +1194,10 @@ msgstr "Błąd importu %s"
msgid "DUPLICATE"
msgstr "DUPLIKAT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ZASZYFROWANY"
@@ -1242,6 +1243,10 @@ msgstr "Brakowało %s artykułów"
msgid "%s articles had non-matching duplicates"
msgstr "%s artykułów posiadało niepasujące duplikaty"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Wstrzymuję zduplikowany NZB \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1469,6 +1474,11 @@ msgstr ""
"Wykryto kolejkę w starszej wersji, użyj funkcji Status->Naprawa, aby ją "
"przekonwertować"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Błąd kompilacji wyrażenia regularnego dla wyszukiwania: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1653,10 +1663,6 @@ msgstr "Znaleziono pusty wpis RSS (%s)"
msgid "Show interface"
msgstr "Pokaż interfejs"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Otwórz katalog zakończonych"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1745,6 +1751,11 @@ msgstr ""
msgid "Script"
msgstr "Skrypt"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2117,11 +2128,6 @@ msgstr "Przełączniki"
msgid "Scheduling"
msgstr "Harmonogram"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2236,11 +2242,6 @@ msgstr "Nazwa"
msgid "Retry"
msgstr "Ponów"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Działania"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2563,7 +2564,6 @@ msgstr "Czas działania"
msgid "Backup"
msgstr "Zapasowy"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Przeczytaj o tym w Wiki!"
@@ -3116,23 +3116,19 @@ msgstr ""
"Jeśli wybrano \"Wstrzymaj\", będzie trzeba ustawić hasło i wznowić zadanie"
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Działanie dla duplikatów"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Wykryj zduplikowane odcinki seriali"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -3141,8 +3137,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3231,6 +3227,14 @@ msgstr "Skrypt użytkownika przed zakolejkowaniem"
msgid "Used before an NZB enters the queue."
msgstr "Uruchamiany zanim plik NZB zostanie umieszczony w kolejce"
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Dodatkowe parametry PAR2"
@@ -4768,10 +4772,6 @@ msgid ""
"Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Serwer przerwał połączenie w trakcie logowania."
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Serwer wymaga podania nazwy użytkownika i hasła."

View File

@@ -2,11 +2,12 @@
# Copyright 2007-2023 The SABnzbd-Team
#
# Translators:
# Henrique Moreno, 2023
# Safihre <safihre@sabnzbd.org>, 2023
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"
@@ -67,7 +68,7 @@ msgstr "aplicativo 7za... NÃO encontrado!"
#. Error message
#: SABnzbd.py
msgid "Essential modules are missing, downloading cannot start."
msgstr ""
msgstr "Módulos essenciais estão faltando, não é possível baixar."
#. Warning message
#: SABnzbd.py
@@ -89,6 +90,8 @@ msgid ""
"SABnzbd was started with encoding %s, this should be UTF-8. Expect problems "
"with Unicoded file and directory names in downloads."
msgstr ""
"SABnzbd iniciou com codificado %s, deveria ser UFT-8. Esperado problemas com"
" arquivos e nomes de diretórios Unicode nos downloades."
#. Warning message
#: SABnzbd.py
@@ -96,11 +99,13 @@ msgid ""
"Current umask (%o) might deny SABnzbd access to the files and folders it "
"creates."
msgstr ""
"Mascara atual (%o) pode negar ao SABnzbd acesso aos arquivos e diretórios "
"criados."
#. Warning message
#: SABnzbd.py
msgid "Could not load additional certificates from certifi package"
msgstr ""
msgstr "Não foi possível carregar certificado do pacote certifi."
#. Warning message
#: SABnzbd.py
@@ -110,7 +115,7 @@ msgstr "HTTPS desabilitado pela falta de arquivos CERT e KEY"
#. Warning message
#: SABnzbd.py
msgid "Disabled HTTPS because of invalid CERT and KEY files"
msgstr ""
msgstr "HTTPs desabilitado por caus de arquivo CERT e KEY invalidos"
#. Error message
#: SABnzbd.py
@@ -138,22 +143,22 @@ msgstr "Erro fatal ao salvar estado"
#. Warning message
#: sabnzbd/__init__.py
msgid "Restarting because of crashed postprocessor"
msgstr ""
msgstr "Reiniciado por falha de pós processamento."
#. Warning message
#: sabnzbd/__init__.py
msgid "Restarting because of crashed downloader"
msgstr ""
msgstr "Reiniciado por falha de download"
#. Warning message
#: sabnzbd/__init__.py
msgid "Restarting because of crashed assembler"
msgstr ""
msgstr "Reiniciado por falha de assembler"
#. Warning message
#: sabnzbd/__init__.py
msgid "Cannot access PID file %s"
msgstr ""
msgstr "Não é possível acessar arquivo PID %s"
#: sabnzbd/api.py, sabnzbd/emailer.py
msgid "Email succeeded"
@@ -177,11 +182,6 @@ msgstr "Nenhum"
msgid "Default"
msgstr "Padrão"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Falha ao compilar a expressão para o termo pesquisado: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -208,6 +208,8 @@ msgid ""
"Paused job \"%s\" because of encrypted RAR file (if supplied, all passwords "
"were tried)"
msgstr ""
"Tarefa \"%s\" pausado por causa de arquivo RAR encripitado (se fornecido, "
"todos as senhas foram tentadas)"
#. Warning message
#: sabnzbd/assembler.py
@@ -215,6 +217,8 @@ msgid ""
"Aborted job \"%s\" because of encrypted RAR file (if supplied, all passwords"
" were tried)"
msgstr ""
"Tarefa \"%s\" abortado por causa de arquivo RAR encripitado (se fornecido, "
"todos as senhas foram tentadas)"
#: sabnzbd/assembler.py
msgid "Aborted, encryption detected"
@@ -224,6 +228,8 @@ msgstr "Cancelado, criptografia detectada"
#: sabnzbd/assembler.py
msgid "In \"%s\" unwanted extension in RAR file. Unwanted file is %s "
msgstr ""
"Em \"%s\" extensão não necessária em arquivo RAR. Arquivo não necessário é "
"%s "
#: sabnzbd/assembler.py
msgid "Unwanted extension is in rar file %s"
@@ -260,7 +266,7 @@ msgstr "%s não é um endereço de e-mail válido"
msgid "Server address required"
msgstr "Endereço do servidor necessário"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Endereço do servidor inválido."
@@ -280,12 +286,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "O caminho UNC \"%s\" não é permitido aqui"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "A fila não está vazia. Não será possível mudar de pasta."
#: sabnzbd/cfg.py
msgid ""
@@ -1066,6 +1072,16 @@ msgstr "Fila concluída"
msgid "Other Messages"
msgstr "Outras Mensagens"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Abrir pasta de finalizados"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Não disponível"
@@ -1146,6 +1162,18 @@ msgstr "Erro ao carregar %s. Arquivo corrompido detectado"
msgid "NZB added to queue"
msgstr "NZB adicionado à fila"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorando NZB duplicado \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1160,26 +1188,6 @@ msgstr "Arquivo NZB %s vazio"
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorando NZB duplicado \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pausando NZB duplicado \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1198,6 +1206,10 @@ msgstr "Erro ao importar %s"
msgid "DUPLICATE"
msgstr "DUPLICADO"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "CRIPTOGRAFADO"
@@ -1243,6 +1255,10 @@ msgstr "%s artigos estavam faltando"
msgid "%s articles had non-matching duplicates"
msgstr "%s artigos tinham duplicatas não-correspondentes"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pausando NZB duplicado \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1470,6 +1486,11 @@ msgstr ""
"Fila antiga detectada, use \"Situação -> Reparação da fila\" para converter "
"a fila"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Falha ao compilar a expressão para o termo pesquisado: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1656,10 +1677,6 @@ msgstr "Entrada RSS vazia encontrada (%s)"
msgid "Show interface"
msgstr "Exibir interface"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Abrir pasta de finalizados"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1748,6 +1765,11 @@ msgstr ""
msgid "Script"
msgstr "Script"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2120,11 +2142,6 @@ msgstr "Opções"
msgid "Scheduling"
msgstr "Agendamento"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2239,11 +2256,6 @@ msgstr "Nome"
msgid "Retry"
msgstr "Repetir"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Ações"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2566,7 +2578,6 @@ msgstr "Tempo ativo"
msgid "Backup"
msgstr "Backup"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Leia a sessão ajuda no Wiki sobre isso!"
@@ -3118,23 +3129,19 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
msgstr "Em caso de \"Pausa\", você precisa definir uma senha e retomar a tarefa."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Detectar Downloads Duplicados"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Detecta episódios duplicados em séries"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -3143,8 +3150,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3233,6 +3240,14 @@ msgstr "Script de usuário de pré-fila"
msgid "Used before an NZB enters the queue."
msgstr "Utilizado antes de um NZB entrar na fila."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Parâmetros Extras PAR2"
@@ -4768,10 +4783,6 @@ msgid ""
"Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Servidor parou durante a sequência de login."
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Servidor requer usuário e senha."

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Romanian (https://app.transifex.com/sabnzbd/teams/111101/ro/)\n"
@@ -182,11 +182,6 @@ msgstr "Niciunul"
msgid "Default"
msgstr "Implicit"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Compilarea unei căutări regex nereuşită: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -271,7 +266,7 @@ msgstr "%s nu este o adresă email validă"
msgid "Server address required"
msgstr "Adresă server necesară"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Adresă server invalidă"
@@ -291,12 +286,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "cale UNC \"%s\" nu este premisă aici"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Coada nu este goală, nu pot schimba dosar."
#: sabnzbd/cfg.py
msgid ""
@@ -1091,6 +1086,16 @@ msgstr "Coadă finalizată"
msgid "Other Messages"
msgstr "Alte Mesaje"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Deschide dosar descărcări complete"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Indisponibil"
@@ -1171,6 +1176,18 @@ msgstr "Eroare încărcare %s, fişier corupt detectat"
msgid "NZB added to queue"
msgstr "NZB adăugat în coadă"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorăm duplicat NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Eșuare duplicat NZB „%s”"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "NZB duplicat"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1185,26 +1202,6 @@ msgstr "Fişier NZB gol %s"
msgid "Pre-queue script marked job as failed"
msgstr "Scriptul pre-coadă a marcat sarcina ca nereușită"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorăm duplicat NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Eșuare duplicat NZB „%s”"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "NZB duplicat"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Întrerupem duplicat NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1223,6 +1220,10 @@ msgstr "Eroare importare %s"
msgid "DUPLICATE"
msgstr "DUPLICAT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ENCRIPTAT"
@@ -1268,6 +1269,10 @@ msgstr "%s articolele au fost lipsă"
msgid "%s articles had non-matching duplicates"
msgstr "%s articolele au avut duplicate diferite"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Întrerupem duplicat NZB \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1497,6 +1502,11 @@ msgstr ""
"Coadă de descărcare veche detectată, utilizează Stare->Reparare pentru a "
"converti coada"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Compilarea unei căutări regex nereuşită: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1683,10 +1693,6 @@ msgstr "Valoare RSS gasită a fost goală (%s)"
msgid "Show interface"
msgstr "Arată interfața"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Deschide dosar descărcări complete"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1775,6 +1781,11 @@ msgstr ""
msgid "Script"
msgstr "Script"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2147,11 +2158,6 @@ msgstr "Comutatoare"
msgid "Scheduling"
msgstr "Planificare"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2266,11 +2272,6 @@ msgstr "Nume"
msgid "Retry"
msgstr "Reîncearcă"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Acțiuni"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2596,7 +2597,6 @@ msgstr "Durata Funcţionării"
msgid "Backup"
msgstr "Server Secundar"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Citeşte Ajutorul Wiki despre asta !"
@@ -3145,23 +3145,19 @@ msgstr ""
"reluați sarcina."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Detectează Descărcări Duplicate"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Detectează episoade duplicate în seriale"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -3170,8 +3166,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3260,6 +3256,14 @@ msgstr "Script utilizator Pre-Coadă"
msgid "Used before an NZB enters the queue."
msgstr "Folosit înainte ca un NZB să intre în coadă."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Parametri Extra PAR2"
@@ -4801,10 +4805,6 @@ msgid ""
"Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Serverul a renunţat în timpul logării."
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Serverul necesită nume utilizator şi parolă"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"
@@ -177,11 +177,6 @@ msgstr "Ничего"
msgid "Default"
msgstr "по умолчанию"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Не удалось составить регулярное выражение поиска: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -260,7 +255,7 @@ msgstr "%s не является допустимым адресом элект
msgid "Server address required"
msgstr "Требуется адрес сервера"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Недопустимый адрес сервера."
@@ -280,12 +275,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "UNC-путь «%s» здесь не допускается"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Очередь не пустая, папку нельзя изменить."
#: sabnzbd/cfg.py
msgid ""
@@ -1064,6 +1059,16 @@ msgstr ""
msgid "Other Messages"
msgstr "Другие сообщения"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr ""
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr ""
@@ -1144,6 +1149,18 @@ msgstr "Ошибка загрузки %s: обнаружен повреждён
msgid "NZB added to queue"
msgstr "NZB-файл добавлен в очередь"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Пропущен повторяющийся NZB-файл «%s»"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1158,26 +1175,6 @@ msgstr "Пустой NZB-файл %s"
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Пропущен повторяющийся NZB-файл «%s»"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Приостановлен повторяющийся NZB-файл «%s»"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1196,6 +1193,10 @@ msgstr "Ошибка импорта %s"
msgid "DUPLICATE"
msgstr "ПОВТОР"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ЗАШИФРОВАН"
@@ -1241,6 +1242,10 @@ msgstr "%s статей отсутствует"
msgid "%s articles had non-matching duplicates"
msgstr "%s статей содержат несовпадающие повторы"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Приостановлен повторяющийся NZB-файл «%s»"
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1466,6 +1471,11 @@ msgstr "Ошибка %s: укажите действительное имя по
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr ""
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Не удалось составить регулярное выражение поиска: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1650,10 +1660,6 @@ msgstr "Обнаружена пустая запись RSS (%s)"
msgid "Show interface"
msgstr "Показать интерфейс"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr ""
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1742,6 +1748,11 @@ msgstr ""
msgid "Script"
msgstr "Сценарий"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2114,11 +2125,6 @@ msgstr "Переключатели"
msgid "Scheduling"
msgstr "Расписание"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2233,11 +2239,6 @@ msgstr "Название"
msgid "Retry"
msgstr "Повторить"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Действия"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2560,7 +2561,6 @@ msgstr "Время работы"
msgid "Backup"
msgstr "Резервный"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Описание см. на вики-странице."
@@ -3112,23 +3112,19 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Обнаруживать повторяющиеся загрузки"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -3137,8 +3133,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3225,6 +3221,14 @@ msgstr "Пользовательский сценарий до помещени
msgid "Used before an NZB enters the queue."
msgstr "Используется до того, как NZB помещается в очередь."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Дополнительные параметры PAR2"
@@ -4764,10 +4768,6 @@ msgid ""
"Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Во время входа на сервер был выполнен выход."
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Для сервера требуется имя пользователя и пароль."

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Serbian (https://app.transifex.com/sabnzbd/teams/111101/sr/)\n"
@@ -175,11 +175,6 @@ msgstr "Ниједно"
msgid "Default"
msgstr "Подразумевано"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Neuspešna kompilacija regularne ekspresije za termin pretrage: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -258,7 +253,7 @@ msgstr "%s nije ispravna email adresa"
msgid "Server address required"
msgstr "Потребна је адреса сервера"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Погрешна адреса сервера."
@@ -278,12 +273,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "UNC путања \"%s\" није дозвољена"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Pед није празан, фасцикла се не може променити."
#: sabnzbd/cfg.py
msgid ""
@@ -1060,6 +1055,16 @@ msgstr "Ред завршен"
msgid "Other Messages"
msgstr "Остале поруке"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Otvori fasciklu završenih"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Недоступно"
@@ -1140,6 +1145,18 @@ msgstr "Грешка учитавање %s, покварена датотека
msgid "NZB added to queue"
msgstr "NZB додат у ред"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Игнорисање дуплог NZB-а \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1154,26 +1171,6 @@ msgstr "Празан NZB %s"
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Игнорисање дуплог NZB-а \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Паузирам због дуплог NZB-а \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1192,6 +1189,10 @@ msgstr "Грешка увоза %s"
msgid "DUPLICATE"
msgstr "ДУПЛИКАТ"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ШИФРИРАНО"
@@ -1237,6 +1238,10 @@ msgstr "%s артикла недостају"
msgid "%s articles had non-matching duplicates"
msgstr "%s артикла нису дупликате"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Паузирам због дуплог NZB-а \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1460,6 +1465,11 @@ msgstr "Грешка %s: Требате да унесете важеће име/
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "Стари ред је нађен, употребити Статус->Поправи за претварање реда"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Neuspešna kompilacija regularne ekspresije za termin pretrage: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1644,10 +1654,6 @@ msgstr "Nađen prazan RSS unos (%s)"
msgid "Show interface"
msgstr "Pokaži interfejs"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Otvori fasciklu završenih"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1736,6 +1742,11 @@ msgstr ""
msgid "Script"
msgstr "Скрипт"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2108,11 +2119,6 @@ msgstr "Прекидачи"
msgid "Scheduling"
msgstr "Планирање"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2227,11 +2233,6 @@ msgstr "Име"
msgid "Retry"
msgstr "Покушај опет"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Акције"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2552,7 +2553,6 @@ msgstr "; Ради"
msgid "Backup"
msgstr "Резервно"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "За више информација, читајте Вики!"
@@ -3099,23 +3099,19 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
msgstr "Ако је \"Пауза\", требате да поставите лозинку и да наставите рад."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Откриј дупликатна преузимања"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Откриј дупле епизоде у серије"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -3124,8 +3120,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3214,6 +3210,14 @@ msgstr "Кориснички скрипт пре-реда"
msgid "Used before an NZB enters the queue."
msgstr "Коришћено пре него што NZB уђе у ред."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Додатни параметри PAR2"
@@ -4743,10 +4747,6 @@ msgid ""
"Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Сервер се затворио при пријављивање"
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Серверу су потребни име и лозинка."

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"
@@ -175,11 +175,6 @@ msgstr "Ingen"
msgid "Default"
msgstr "Standard"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "Det gick inte att kompilera regex för sök-sträng: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -258,7 +253,7 @@ msgstr "%s är inte en godkänd e-mail adress"
msgid "Server address required"
msgstr "Kräver serveradress"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "Ogiltig serveradress"
@@ -278,12 +273,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "UNC sökväg \"%s\" är inte tillåten här"
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "Kön är inte tom, kan inte byta mapp."
#: sabnzbd/cfg.py
msgid ""
@@ -1064,6 +1059,16 @@ msgstr "Kön färdig"
msgid "Other Messages"
msgstr "Andra meddelanden"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Öppna färdig mapp"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "Ej tillgänglig"
@@ -1144,6 +1149,18 @@ msgstr "Laddningsfel %s, felaktig fil detekterad"
msgid "NZB added to queue"
msgstr "NZB tillagd i kön"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorerar dubblett för NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1158,26 +1175,6 @@ msgstr "NZB filen %s är tom"
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorerar dubblett för NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pausar dubblett för NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1196,6 +1193,10 @@ msgstr "Det gick inte att importera %s"
msgid "DUPLICATE"
msgstr "DUBLETT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "KRYPTERAT"
@@ -1241,6 +1242,10 @@ msgstr "%s artiklar saknades"
msgid "%s articles had non-matching duplicates"
msgstr "%s artiklar hade icke-matchande dubletter"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pausar dubblett för NZB \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1466,6 +1471,11 @@ msgstr "Error %s: Du måste ange ett giltigt användarnamn och lösenord."
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "Gammal kö hittad, använd Status -> Reparera för att konvertera kön"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "Det gick inte att kompilera regex för sök-sträng: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1650,10 +1660,6 @@ msgstr "Tom RSS post hittades (%s)"
msgid "Show interface"
msgstr "Visa gränssnitt"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "Öppna färdig mapp"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1742,6 +1748,11 @@ msgstr ""
msgid "Script"
msgstr "Skript"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2114,11 +2125,6 @@ msgstr "Switchar"
msgid "Scheduling"
msgstr "Schemaläggare"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2233,11 +2239,6 @@ msgstr "Namn"
msgid "Retry"
msgstr "Försök igen"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Åtgärder"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2560,7 +2561,6 @@ msgstr "Upptid"
msgid "Backup"
msgstr "Säkerhetskopiera"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "Läs Wiki Help för detta!"
@@ -3109,23 +3109,19 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
msgstr "Om \"Pausad\", så behöver du ange ett lösenord för att återuppta jobbet."
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "Upptäck dubbletter av nedladdningar"
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "Hitta dublettavsnitt i serier"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
@@ -3134,8 +3130,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3224,6 +3220,14 @@ msgstr "Kö-specifika användarskript"
msgid "Used before an NZB enters the queue."
msgstr "Används innan en NZB tas in i kön."
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "Extra PAR2 parametrar"
@@ -4757,10 +4761,6 @@ msgid ""
"Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr ""
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "Servern avslutades under inloggning"
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "Servern kräver användarnamn och lösenord."

View File

@@ -3,12 +3,13 @@
#
# Translators:
# Safihre <safihre@sabnzbd.org>, 2023
# Kangwei Li <lkw20010211@gmail.com>, 2023
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Last-Translator: Kangwei Li <lkw20010211@gmail.com>, 2023\n"
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -173,11 +174,6 @@ msgstr "无"
msgid "Default"
msgstr "默认"
#. Error message
#: sabnzbd/api.py
msgid "Failed to compile regex for search term: %s"
msgstr "为搜索关键词编译正则表达式失败: %s"
#. Error message
#: sabnzbd/assembler.py
msgid "Disk full! Forcing Pause"
@@ -256,7 +252,7 @@ msgstr "%s 不是有效的电子邮箱地址"
msgid "Server address required"
msgstr "服务器地址必填"
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py, sabnzbd/utils/servertests.py
#: sabnzbd/cfg.py, sabnzbd/newswrapper.py
msgid "Invalid server address."
msgstr "服务器地址无效。"
@@ -276,12 +272,12 @@ msgid ""
msgstr ""
#: sabnzbd/cfg.py
msgid "UNC path \"%s\" not allowed here"
msgstr "此处不允许使用 UNC 路径 \"%s\""
msgid "Network path \"%s\" is not allowed here"
msgstr ""
#: sabnzbd/cfg.py
msgid "Queue not empty, cannot change folder."
msgstr ""
msgstr "队列非空,无法变更文件夹。"
#: sabnzbd/cfg.py
msgid ""
@@ -1053,6 +1049,16 @@ msgstr "队列已完成"
msgid "Other Messages"
msgstr "其他信息"
#. Notification action
#: sabnzbd/notifier.py
msgid "Open folder"
msgstr ""
#. Notification action
#: sabnzbd/notifier.py, sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "打开完成文件夹"
#: sabnzbd/notifier.py, sabnzbd/skintext.py
msgid "Not available"
msgstr "不可用"
@@ -1133,6 +1139,18 @@ msgstr "无法加载 %s侦测到损坏文件"
msgid "NZB added to queue"
msgstr "NZB 已添加到队列"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "正在忽略重复 NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "失败于重复的 NZB 文件 \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "重复的 NZB 文件"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
@@ -1147,26 +1165,6 @@ msgstr "空 NZB 文件 %s"
msgid "Pre-queue script marked job as failed"
msgstr "预队列脚本将任务标记为失败的"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "正在忽略重复 NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Failing duplicate NZB \"%s\""
msgstr "失败于重复的 NZB 文件 \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Duplicate NZB"
msgstr "重复的 NZB 文件"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "正在暂停重复 NZB \"%s\""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
@@ -1185,6 +1183,10 @@ msgstr "导入 %s 出错"
msgid "DUPLICATE"
msgstr "*重复*"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "*加密*"
@@ -1230,6 +1232,10 @@ msgstr "%s 篇文章缺失"
msgid "%s articles had non-matching duplicates"
msgstr "%s 篇文章存在未匹配的重复"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "正在暂停重复 NZB \"%s\""
#. Footer: indicator of warnings
#: sabnzbd/osxmenu.py, sabnzbd/skintext.py
msgid "Warnings"
@@ -1453,6 +1459,11 @@ msgstr "错误 %s: 您需要提供有效的用户名与密码。"
msgid "Old queue detected, use Status->Repair to convert the queue"
msgstr "侦测到旧版队列,请使用“状态”→“修复”转换队列"
#. Error message
#: sabnzbd/postproc.py
msgid "Failed to compile regex for search term: %s"
msgstr "为搜索关键词编译正则表达式失败: %s"
#. Warning message
#: sabnzbd/postproc.py
msgid ""
@@ -1637,10 +1648,6 @@ msgstr "发现空的 RSS 条目 (%s)"
msgid "Show interface"
msgstr "显示界面"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Open complete folder"
msgstr "打开完成文件夹"
#. Queue page button or entry box
#: sabnzbd/sabtray.py, sabnzbd/skintext.py
msgid "Pause for"
@@ -1729,6 +1736,11 @@ msgstr ""
msgid "Script"
msgstr "脚本"
#. PP RSS feed of the NZB - Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. PP Source of the NZB (path or URL) - Where to find the SABnzbd sourcecode
#: sabnzbd/skintext.py
msgid "Source"
@@ -2101,11 +2113,6 @@ msgstr "参数"
msgid "Scheduling"
msgstr "定时任务"
#. Main menu item
#: sabnzbd/skintext.py
msgid "RSS"
msgstr "RSS"
#. Main menu item
#: sabnzbd/skintext.py
msgid "Notifications"
@@ -2220,11 +2227,6 @@ msgstr "名称"
msgid "Retry"
msgstr "重试"
#. Queue end-of-queue selection box
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "操作"
#. Queue page table, script selection menu
#: sabnzbd/skintext.py
msgid "Scripts"
@@ -2539,7 +2541,6 @@ msgstr "启动时间"
msgid "Backup"
msgstr "备份"
#. Notification Script settings
#: sabnzbd/skintext.py
msgid "Read the Wiki Help on this!"
msgstr "关于该项请参阅 Wiki 帮助!"
@@ -2880,11 +2881,11 @@ msgstr ""
#: sabnzbd/skintext.py
msgid "Minimum Free Space for Completed Download Folder"
msgstr ""
msgstr "完成下载文件夹的最小剩余空间"
#: sabnzbd/skintext.py
msgid "Will not work if a category folder is on a different disk."
msgstr ""
msgstr "当某分类的路径位于另一磁盘上时不生效。"
#. Auto-resume download on the reset day
#: sabnzbd/skintext.py
@@ -2968,14 +2969,14 @@ msgstr "队列管理及历史数据库的存放位置。<br /><i>仅当队列为
#: sabnzbd/skintext.py
msgid "Backup Folder"
msgstr ""
msgstr "备份文件夹"
#: sabnzbd/skintext.py
msgid ""
"Location where the backups of the configuration file and databases are "
"stored.<br />If left empty, the backup will be created in the Completed "
"Download Folder."
msgstr ""
msgstr "备份配置文件和数据库的位置。<br />如果留空,备份将存放于完成下载文件夹中。"
#: sabnzbd/skintext.py
msgid "<i>Data will <b>not</b> be moved. Requires SABnzbd restart!</i>"
@@ -2992,7 +2993,7 @@ msgstr "SABnzbd 日志文件的位置。<br /><i>需要重启 SABnzbd 才能生
#: sabnzbd/skintext.py
msgid "Purge Logs"
msgstr ""
msgstr "清除日志"
#: sabnzbd/skintext.py
msgid ".nzb Backup Folder"
@@ -3062,24 +3063,20 @@ msgid "In case of \"Pause\", you'll need to set a password and resume the job."
msgstr "若选择“暂停”,您将需要设置密码并手动续传对应任务。"
#: sabnzbd/skintext.py
msgid "Detect Duplicate Downloads"
msgstr "侦测重复下载"
msgid "Identical download detection"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical NZB files (based on items in your History or files in .nzb "
"Backup Folder)"
msgstr "检测相同的 NZB 文件 (基于您的历史项目或 .nzb 备份文件夹中的文件)"
msgid "Detect identical downloads based on name or NZB contents."
msgstr ""
#: sabnzbd/skintext.py
msgid "Detect duplicate episodes in series"
msgstr "侦测同季的重复剧集"
msgid "Smart duplicate detection"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Detect identical episodes in series (based on \"name/season/episode\" of "
"items in your History)"
msgstr "在剧目中检测相同的剧集 (基于您的历史项目,参照 \"name/season/episode\" 的规则)"
msgid "Detect duplicates based on analysis of the filename."
msgstr ""
#: sabnzbd/skintext.py
msgid "Allow proper releases"
@@ -3087,8 +3084,8 @@ msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name"
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in "
"the download name."
msgstr ""
#. Four way switch for duplicates
@@ -3173,6 +3170,14 @@ msgstr "加入队列前执行的用户脚本"
msgid "Used before an NZB enters the queue."
msgstr "用于在 NZB 进入队列前执行。"
#: sabnzbd/skintext.py
msgid "On queue finish script"
msgstr ""
#: sabnzbd/skintext.py
msgid "Executed after the queue finishes downloading."
msgstr ""
#: sabnzbd/skintext.py
msgid "Extra PAR2 Parameters"
msgstr "额外的 PAR2 参数"
@@ -3437,7 +3442,7 @@ msgstr "超时"
#: sabnzbd/skintext.py
msgid "Account expiration date"
msgstr ""
msgstr "账户到期时间"
#: sabnzbd/skintext.py
msgid "Warn 5 days in advance of account expiration date."
@@ -3617,7 +3622,7 @@ msgstr "应用过滤器"
#. Config->RSS edit button
#: sabnzbd/skintext.py
msgid "Edit"
msgstr ""
msgstr "编辑"
#. Config->RSS when will be the next RSS scan
#: sabnzbd/skintext.py
@@ -4691,10 +4696,6 @@ msgid ""
"Unknown SSL protocol: Try disabling SSL or connecting on a different port."
msgstr "未知的 SSL 协议:尝试禁用 SSL 或者连接不同的端口。"
#: sabnzbd/utils/servertests.py
msgid "Server quit during login sequence."
msgstr "登录过程中服务器退出。"
#: sabnzbd/utils/servertests.py
msgid "Server requires username and password."
msgstr "服务器需要用户名与密码。"

View File

@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: team@sabnzbd.org\n"
"Language-Team: SABnzbd <team@sabnzbd.org>\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Pavel C <quoing_transifex@mess.cz>, 2022\n"
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0-develop\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: reloxx13 <reloxx@interia.pl>, 2022\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Ester Molla Aragones <moarages@gmail.com>, 2020\n"
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Finnish (https://app.transifex.com/sabnzbd/teams/111101/fi/)\n"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Fred L <88com88@gmail.com>, 2021\n"
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: ION, 2021\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0RC1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2021\n"
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Polish (https://app.transifex.com/sabnzbd/teams/111101/pl/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Romanian (https://app.transifex.com/sabnzbd/teams/111101/ro/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Serbian (https://app.transifex.com/sabnzbd/teams/111101/sr/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.2.0Alpha1\n"
"Project-Id-Version: SABnzbd-4.2.0Beta1\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2020\n"
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"

View File

@@ -4,13 +4,13 @@ sabctools==8.0.0
cheetah3==3.2.6.post1
cffi==1.16.0
pycparser==2.21
feedparser==6.0.10
feedparser==6.0.11
configobj==5.0.8
cheroot==10.0.0
six==1.16.0
cherrypy==18.8.0
jaraco.functools==3.9.0
jaraco.collections==4.3.0
jaraco.functools==4.0.0
jaraco.collections==5.0.0
jaraco.text==3.8.1 # Newer version introduces irrelevant extra dependencies
jaraco.classes==3.3.0
jaraco.context==4.3.0
@@ -30,18 +30,20 @@ rebulk==3.2.0
# Recent cryptography versions require Rust. If you run into issues compiling this
# SABnzbd will also work with older pre-Rust versions such as cryptography==3.3.2
cryptography==41.0.5
cryptography==41.0.7
# We recommend using "orjson" as it is 2x as fast as "ujson". However, it requires
# Rust so SABnzbd works just as well with "ujson" or the Python built in "json" module
ujson==5.8.0
ujson==5.9.0
# Windows system integration
pywin32==306; sys_platform == 'win32'
toasts-winrt==1.0.0; sys_platform == 'win32'
windows-toasts==1.0.1; sys_platform == 'win32'
# macOS system calls
pyobjc-core==10.0; sys_platform == 'darwin'
pyobjc-framework-Cocoa==10.0; sys_platform == 'darwin'
pyobjc-core==10.1; sys_platform == 'darwin'
pyobjc-framework-Cocoa==10.1; sys_platform == 'darwin'
# Linux notifications
notify2==0.3.1; sys_platform != 'win32' and sys_platform != 'darwin'
@@ -55,4 +57,4 @@ notify2==0.3.1; sys_platform != 'win32' and sys_platform != 'darwin'
# Optional support for system power management on *nix.
# Requires libdbus-1-dev to be installed.
# Uncomment line below or manually install after installing requirements.
# dbus-python; sys_platform != 'win32' and sys_platform != 'darwin'
# dbus-python; sys_platform != 'win32' and sys_platform != 'darwin'

View File

@@ -108,6 +108,7 @@ import sabnzbd.articlecache
import sabnzbd.bpsmeter
import sabnzbd.scheduler as scheduler
import sabnzbd.notifier as notifier
import sabnzbd.sorting
from sabnzbd.decorators import synchronized
import sabnzbd.utils.ssdp
@@ -138,7 +139,6 @@ DIR_PID = None
QUEUECOMPLETE = None # stores the nice name of the action
QUEUECOMPLETEACTION = None # stores the name of the function to be called
QUEUECOMPLETEARG = None # stores an extra arguments that need to be passed
DAEMON = None
LINUX_POWER = powersup.HAVE_DBUS
@@ -162,6 +162,7 @@ RESTART_REQ = False
PAUSED_ALL = False
TRIGGER_RESTART = False # To trigger restart for Scheduler, WinService and Mac
WINTRAY = None # Thread for the Windows SysTray icon
MACOSTRAY = None # Thread for the macOS tray icon
WEBUI_READY = False
LAST_HISTORY_UPDATE = 1
RESTORE_DATA = None
@@ -285,6 +286,11 @@ def initialize(pause_downloader=False, clean_up=False, repair=0):
misc.convert_sorter_settings()
cfg.sorters_converted.set(True)
# Convert duplicate settings
if cfg.no_series_dupes():
cfg.no_smart_dupes.set(cfg.no_series_dupes())
cfg.no_series_dupes.set(0)
# Add hostname to the whitelist
if not cfg.host_whitelist():
cfg.host_whitelist.set(socket.gethostname())

View File

@@ -58,7 +58,7 @@ import sabnzbd.config as config
import sabnzbd.cfg as cfg
from sabnzbd.skintext import SKIN_TEXT
from sabnzbd.utils.diskspeed import diskspeedmeasure
from sabnzbd.utils.internetspeed import internetspeed
from sabnzbd.internetspeed import internetspeed
from sabnzbd.utils.pathbrowser import folders_at_path
from sabnzbd.utils.getperformance import getpystone
from sabnzbd.misc import (
@@ -270,6 +270,7 @@ def _api_queue_default(value, kwargs):
search = kwargs.get("search")
categories = kwargs.get("cat") or kwargs.get("category")
priorities = kwargs.get("priority")
statuses = kwargs.get("status")
nzo_ids = kwargs.get("nzo_ids")
if categories and not isinstance(categories, list):
@@ -277,13 +278,21 @@ def _api_queue_default(value, kwargs):
if priorities and not isinstance(priorities, list):
# Make sure it's an integer
priorities = [int_conv(prio) for prio in priorities.split(",")]
if statuses and not isinstance(statuses, list):
statuses = statuses.split(",")
if nzo_ids and not isinstance(nzo_ids, list):
nzo_ids = nzo_ids.split(",")
return report(
keyword="queue",
data=build_queue(
start=start, limit=limit, search=search, categories=categories, priorities=priorities, nzo_ids=nzo_ids
start=start,
limit=limit,
search=search,
categories=categories,
priorities=priorities,
statuses=statuses,
nzo_ids=nzo_ids,
),
)
@@ -483,8 +492,9 @@ def _api_history(name, kwargs):
limit = int_conv(kwargs.get("limit"))
last_history_update = int_conv(kwargs.get("last_history_update", 0))
search = kwargs.get("search")
failed_only = int_conv(kwargs.get("failed_only"))
categories = kwargs.get("cat") or kwargs.get("category")
statuses = kwargs.get("status")
failed_only = int_conv(kwargs.get("failed_only"))
nzo_ids = kwargs.get("nzo_ids")
# Do we need to send anything?
@@ -494,6 +504,13 @@ def _api_history(name, kwargs):
if categories and not isinstance(categories, list):
categories = categories.split(",")
if statuses and not isinstance(statuses, list):
statuses = statuses.split(",")
if failed_only:
# We ignore any other statuses, having both doesn't make sense
statuses = [Status.FAILED]
if nzo_ids and not isinstance(nzo_ids, list):
nzo_ids = nzo_ids.split(",")
@@ -537,7 +554,12 @@ def _api_history(name, kwargs):
to_units(day),
)
history["slots"], history["ppslots"], history["noofslots"] = build_history(
start=start, limit=limit, search=search, failed_only=failed_only, categories=categories, nzo_ids=nzo_ids
start=start,
limit=limit,
search=search,
categories=categories,
statuses=statuses,
nzo_ids=nzo_ids,
)
history["last_history_update"] = sabnzbd.LAST_HISTORY_UPDATE
history["version"] = sabnzbd.__version__
@@ -592,9 +614,9 @@ def _api_addurl(name, kwargs):
password = kwargs.get("password", "")
if name:
nzo_id = sabnzbd.urlgrabber.add_url(name, pp, script, cat, priority, nzbname, password)
# Reporting a list of NZO's, for compatibility with other add-methods
return report(keyword="", data={"status": True, "nzo_ids": [nzo_id]})
res, nzo_ids = sabnzbd.urlgrabber.add_url(name, pp, script, cat, priority, nzbname, password)
return report(keyword="", data={"status": res is AddNzbFileResult.OK, "nzo_ids": nzo_ids})
else:
logging.info("API-call addurl: no URLs received")
return report(_MSG_NO_VALUE)
@@ -1250,9 +1272,6 @@ def build_status(calculate_performance: bool = False, skip_dashboard: bool = Fal
# Calculate performance measures, if requested
if int_conv(calculate_performance):
# Perform the internetspeed measure in separate thread
internetspeed_future = sabnzbd.THREAD_POOL.submit(internetspeed)
# PyStone
sabnzbd.PYSTONE_SCORE = getpystone()
@@ -1261,7 +1280,7 @@ def build_status(calculate_performance: bool = False, skip_dashboard: bool = Fal
sabnzbd.COMPLETE_DIR_SPEED = round(diskspeedmeasure(sabnzbd.cfg.complete_dir.get_path()), 1)
# Internet bandwidth
sabnzbd.INTERNET_BANDWIDTH = round(internetspeed_future.result(), 1)
sabnzbd.INTERNET_BANDWIDTH = round(internetspeed(), 1)
# How often did we delay?
info["delayed_assembler"] = sabnzbd.BPSMeter.delayed_assembler
@@ -1343,6 +1362,7 @@ def build_queue(
search: Optional[str] = None,
categories: Optional[List[str]] = None,
priorities: Optional[List[str]] = None,
statuses: Optional[List[str]] = None,
nzo_ids: Optional[List[str]] = None,
):
info = build_header(for_template=False)
@@ -1354,7 +1374,13 @@ def build_queue(
queue_fullsize,
nzos_matched,
) = sabnzbd.NzbQueue.queue_info(
search=search, categories=categories, priorities=priorities, nzo_ids=nzo_ids, start=start, limit=limit
search=search,
categories=categories,
priorities=priorities,
statuses=statuses,
nzo_ids=nzo_ids,
start=start,
limit=limit,
)
info["kbpersec"] = "%.2f" % (sabnzbd.BPSMeter.bps / KIBI)
@@ -1384,7 +1410,6 @@ def build_queue(
for nzo in nzo_list:
mbleft = nzo.remaining / MEBI
mb = nzo.bytes / MEBI
is_propagating = (nzo.avg_stamp + float(cfg.propagation_delay() * 60)) > time.time()
slot = {}
slot["index"] = n
@@ -1405,8 +1430,8 @@ def build_queue(
slot["direct_unpack"] = nzo.direct_unpack_progress
if not sabnzbd.Downloader.paused and nzo.status not in (Status.PAUSED, Status.FETCHING, Status.GRABBING):
if is_propagating:
slot["status"] = Status.PROP
if nzo.propagation_delay_left:
slot["status"] = Status.PROPAGATING
elif nzo.status == Status.CHECKING:
slot["status"] = Status.CHECKING
else:
@@ -1420,7 +1445,7 @@ def build_queue(
if (
sabnzbd.Downloader.paused
or sabnzbd.Downloader.paused_for_postproc
or is_propagating
or nzo.propagation_delay_left
or nzo.status not in (Status.DOWNLOADING, Status.FETCHING, Status.QUEUED)
) and nzo.priority != FORCE_PRIORITY:
slot["timeleft"] = "0:00:00"
@@ -1513,7 +1538,7 @@ def retry_job(job, new_nzb=None, password=None):
history_db = sabnzbd.get_db_connection()
futuretype, url, pp, script, cat = history_db.get_other(job)
if futuretype:
nzo_id = sabnzbd.urlgrabber.add_url(url, pp, script, cat)
nzo_id = sabnzbd.urlgrabber.add_url(url, pp, script, cat, dup_check=False)
else:
path = history_db.get_incomplete_path(job)
nzo_id = sabnzbd.NzbQueue.repair_job(path, new_nzb, password)
@@ -1631,36 +1656,20 @@ def build_header(webdir: str = "", for_template: bool = True, trans_functions: b
def build_history(
start: int = 0,
limit: int = 0,
limit: int = 1000000,
search: Optional[str] = None,
failed_only: int = 0,
categories: Optional[List[str]] = None,
statuses: Optional[List[str]] = None,
nzo_ids: Optional[List[str]] = None,
) -> Tuple[List[Dict[str, Any]], int, int]:
"""Combine the jobs still in post-processing and the database history"""
if not limit:
limit = 1000000
# Grab any items that are active or queued in postproc
postproc_queue = sabnzbd.PostProcessor.get_queue()
# Filter out any items that don't match the search term or category
if postproc_queue:
# It would be more efficient to iterate only once, but we accept the penalty for code clarity
if isinstance(categories, list):
postproc_queue = [nzo for nzo in postproc_queue if nzo.cat in categories]
if isinstance(search, str):
# Replace * with .* and ' ' with .
search_text = search.strip().replace("*", ".*").replace(" ", ".*") + ".*?"
try:
re_search = re.compile(search_text, re.I)
postproc_queue = [nzo for nzo in postproc_queue if re_search.search(nzo.final_name)]
except:
logging.error(T("Failed to compile regex for search term: %s"), search_text)
if nzo_ids:
postproc_queue = [nzo for nzo in postproc_queue if nzo.nzo_id in nzo_ids]
postproc_queue = sabnzbd.PostProcessor.get_queue(
search=search,
categories=categories,
statuses=statuses,
nzo_ids=nzo_ids,
)
# Multi-page support for postproc items
postproc_queue_size = len(postproc_queue)
@@ -1669,13 +1678,10 @@ def build_history(
postproc_queue = []
database_history_limit = limit
else:
try:
if limit:
postproc_queue = postproc_queue[start : start + limit]
else:
postproc_queue = postproc_queue[start:]
except:
pass
if limit:
postproc_queue = postproc_queue[start : start + limit]
else:
postproc_queue = postproc_queue[start:]
# Remove the amount of postproc items from the db request for history items
database_history_limit = max(limit - len(postproc_queue), 0)
database_history_start = max(start - postproc_queue_size, 0)
@@ -1692,12 +1698,22 @@ def build_history(
# Fetch history items
if not database_history_limit:
items, total_items = history_db.fetch_history(
database_history_start, 1, search, failed_only, categories, nzo_ids
start=database_history_start,
limit=1,
search=search,
categories=categories,
statuses=statuses,
nzo_ids=nzo_ids,
)
items = []
else:
items, total_items = history_db.fetch_history(
database_history_start, database_history_limit, search, failed_only, categories, nzo_ids
start=database_history_start,
limit=database_history_limit,
search=search,
categories=categories,
statuses=statuses,
nzo_ids=nzo_ids,
)
# Add the postproc items to the top of the history
@@ -1742,6 +1758,7 @@ def add_active_history(postproc_queue: List[NzbObject], items: List[Dict[str, An
"size": to_units(nzo.bytes_downloaded, "B"),
"meta": None,
"series": "",
"duplicate_key": nzo.duplicate_key,
"md5sum": "",
"password": nzo.correct_password,
"action_line": nzo.action_line,

View File

@@ -36,6 +36,7 @@ from sabnzbd.filesystem import (
diskspace,
get_filename,
has_unwanted_extension,
get_basename,
)
from sabnzbd.constants import Status, GIGI, MAX_ASSEMBLER_QUEUE
import sabnzbd.cfg as cfg
@@ -156,6 +157,7 @@ class Assembler(Thread):
sabnzbd.Downloader.pause()
if cfg.fulldisk_autoresume():
sabnzbd.Scheduler.plan_diskspace_resume(full_dir, required_space)
sabnzbd.notifier.send_notification("SABnzbd", T("Too little diskspace forcing PAUSE"), "disk_full")
sabnzbd.emailer.diskfull_mail()
@staticmethod
@@ -249,7 +251,7 @@ SAFE_EXTS = (".mkv", ".mp4", ".avi", ".wmv", ".mpg", ".webm")
def is_cloaked(nzo: NzbObject, path: str, names: List[str]) -> bool:
"""Return True if this is likely to be a cloaked encrypted post"""
fname = os.path.splitext(get_filename(path.lower()))[0]
fname = get_basename(get_filename(path.lower()))
for name in names:
name = get_filename(name.lower())
name, ext = os.path.splitext(name)

View File

@@ -51,7 +51,7 @@ from sabnzbd.constants import (
DEF_HTTPS_CERT_FILE,
DEF_HTTPS_KEY_FILE,
)
from sabnzbd.filesystem import same_directory, real_path
from sabnzbd.filesystem import same_directory, real_path, is_valid_script, is_network_path
# Validators currently only are made for string/list-of-strings
# and return those on success or an error message.
@@ -188,7 +188,7 @@ def validate_host(value: str) -> ValidateResult:
def validate_script(value: str) -> ValidateResult:
"""Check if value is a valid script"""
if not sabnzbd.__INITIALIZED__ or (value and sabnzbd.filesystem.is_valid_script(value)):
if not sabnzbd.__INITIALIZED__ or (value and is_valid_script(value)):
return None, value
elif (value and value == "None") or not value:
return None, "None"
@@ -217,10 +217,10 @@ def validate_permissions(value: str) -> ValidateResult:
def validate_safedir(root: str, value: str, default: str) -> ValidateResult:
"""Allow only when queues are empty and no UNC"""
"""Allow only when queues are empty and not a network-path"""
if not sabnzbd.__INITIALIZED__ or (sabnzbd.PostProcessor.empty() and sabnzbd.NzbQueue.is_empty()):
if value.startswith(r"\\"):
return T('UNC path "%s" not allowed here') % value, None
if is_network_path(real_path(root, value)):
return T('Network path "%s" is not allowed here') % value, None
else:
return validate_default_if_empty(root, value, default)
else:
@@ -276,7 +276,7 @@ def validate_default_if_empty(root: str, value: str, default: str) -> Tuple[None
##############################################################################
# Special settings
##############################################################################
pre_script = OptionStr("misc", "pre_script", "None", validation=validate_script)
queue_complete = OptionStr("misc", "queue_complete")
queue_complete_pers = OptionBool("misc", "queue_complete_pers", False)
bandwidth_perc = OptionNumber("misc", "bandwidth_perc", 100, minval=0, maxval=100)
@@ -375,15 +375,18 @@ ionice = OptionStr("misc", "ionice", validation=clean_nice_ionice_parameters)
fail_hopeless_jobs = OptionBool("misc", "fail_hopeless_jobs", True)
fast_fail = OptionBool("misc", "fast_fail", True)
autodisconnect = OptionBool("misc", "auto_disconnect", True)
pre_script = OptionStr("misc", "pre_script", "None", validation=validate_script)
end_queue_script = OptionStr("misc", "end_queue_script", "None", validation=validate_script)
no_dupes = OptionNumber("misc", "no_dupes", 0)
no_series_dupes = OptionNumber("misc", "no_series_dupes", 0)
series_propercheck = OptionBool("misc", "series_propercheck", True)
no_series_dupes = OptionNumber("misc", "no_series_dupes", 0) # Kept for converting to no_smart_dupes
no_smart_dupes = OptionNumber("misc", "no_smart_dupes", 0)
dupes_propercheck = OptionBool("misc", "dupes_propercheck", True)
pause_on_pwrar = OptionNumber("misc", "pause_on_pwrar", 1)
ignore_samples = OptionBool("misc", "ignore_samples", False)
deobfuscate_final_filenames = OptionBool("misc", "deobfuscate_final_filenames", True)
auto_sort = OptionStr("misc", "auto_sort")
direct_unpack = OptionBool("misc", "direct_unpack", False)
propagation_delay = OptionNumber("misc", "propagation_delay", 0)
propagation_delay = OptionNumber("misc", "propagation_delay", 0, minval=0)
folder_rename = OptionBool("misc", "folder_rename", True)
replace_spaces = OptionBool("misc", "replace_spaces", False)
replace_underscores = OptionBool("misc", "replace_underscores", False)
@@ -448,7 +451,7 @@ wait_for_dfolder = OptionBool("misc", "wait_for_dfolder", False)
rss_filenames = OptionBool("misc", "rss_filenames", False)
api_logging = OptionBool("misc", "api_logging", True)
html_login = OptionBool("misc", "html_login", True)
warn_dupl_jobs = OptionBool("misc", "warn_dupl_jobs", True)
warn_dupl_jobs = OptionBool("misc", "warn_dupl_jobs", False)
helpful_warnings = OptionBool("misc", "helpful_warnings", True)
keep_awake = OptionBool("misc", "keep_awake", True)
tray_icon = OptionBool("misc", "tray_icon", True)

View File

@@ -430,7 +430,7 @@ class ConfigServer:
name = "servers," + self.__name
self.displayname = OptionStr(name, "displayname", add=False)
self.host = OptionStr(name, "host", add=False)
self.host = OptionStr(name, "host", validation=sabnzbd.cfg.all_lowercase, add=False)
self.port = OptionNumber(name, "port", 119, 0, 2**16 - 1, add=False)
self.timeout = OptionNumber(name, "timeout", 60, 20, 240, add=False)
self.username = OptionStr(name, "username", add=False)

View File

@@ -107,7 +107,6 @@ NORMAL_PRIORITY = 0
LOW_PRIORITY = -1
DEFAULT_PRIORITY = -100
PAUSED_PRIORITY = -2
DUP_PRIORITY = -3
STOP_PRIORITY = -4
PP_LOOKUP = {0: "", 1: "R", 2: "U", 3: "D"}
@@ -121,14 +120,15 @@ INTERFACE_PRIORITIES = {
}
STAGES = {
"Source": 0,
"Download": 1,
"Servers": 2,
"Repair": 3,
"Filejoin": 4,
"Unpack": 5,
"Deobfuscate": 6,
"Script": 7,
"RSS": 0,
"Source": 1,
"Download": 2,
"Servers": 3,
"Repair": 4,
"Filejoin": 5,
"Unpack": 6,
"Deobfuscate": 7,
"Script": 8,
}
VALID_ARCHIVES = (".zip", ".rar", ".7z")
@@ -163,7 +163,14 @@ class Status:
RUNNING = "Running" # PP: User's post processing script is running
VERIFYING = "Verifying" # PP: Job is being verified (by par2)
DELETED = "Deleted" # Q: Job has been deleted (and is almost gone)
PROP = "Propagating" # Q: Delayed download
PROPAGATING = "Propagating" # Q: Delayed download
class DuplicateStatus:
DUPLICATE = "Duplicate" # Simple duplicate
DUPLICATE_ALTERNATIVE = "Duplicate Alternative" # Alternative duplicate for a queued job
SMART_DUPLICATE = "Smart Duplicate" # Simple Series duplicate
SMART_DUPLICATE_ALTERNATIVE = "Smart Duplicate Alternative" # Alternative duplicate for a queued job
class AddNzbFileResult:

View File

@@ -82,19 +82,25 @@ class HistoryDB:
version = self.cursor.fetchone()["user_version"]
except IndexError:
version = 0
# Add any new columns added since last DB version
# Use "and" to stop when database has been reset due to corruption
if version < 1:
# Add any missing columns added since first DB version
# Use "and" to stop when database has been reset due to corruption
_ = (
self.execute("PRAGMA user_version = 1;")
and self.execute('ALTER TABLE "history" ADD COLUMN series TEXT;')
and self.execute('ALTER TABLE "history" ADD COLUMN md5sum TEXT;')
and self.execute("ALTER TABLE history ADD COLUMN series TEXT;")
and self.execute("ALTER TABLE history ADD COLUMN md5sum TEXT;")
)
if version < 2:
# Add any missing columns added since second DB version
# Use "and" to stop when database has been reset due to corruption
_ = self.execute("PRAGMA user_version = 2;") and self.execute(
'ALTER TABLE "history" ADD COLUMN password TEXT;'
"ALTER TABLE history ADD COLUMN password TEXT;"
)
if version < 3:
# Transfer data to new column (requires WHERE-hack), original column should be removed later
_ = (
self.execute("PRAGMA user_version = 3;")
and self.execute("ALTER TABLE history ADD COLUMN duplicate_key TEXT;")
and self.execute("UPDATE history SET duplicate_key = series WHERE 1 = 1;")
)
def execute(self, command: str, args: Sequence = (), save: bool = False) -> bool:
@@ -142,7 +148,7 @@ class HistoryDB:
"""Create a new (empty) database file"""
self.execute(
"""
CREATE TABLE "history" (
CREATE TABLE history (
"id" INTEGER PRIMARY KEY,
"completed" INTEGER NOT NULL,
"name" TEXT NOT NULL,
@@ -169,11 +175,12 @@ class HistoryDB:
"meta" TEXT,
"series" TEXT,
"md5sum" TEXT,
"password" TEXT
"password" TEXT,
"duplicate_key" TEXT
)
"""
)
self.execute("PRAGMA user_version = 2;")
self.execute("PRAGMA user_version = 3;")
def close(self):
"""Close database connection"""
@@ -263,7 +270,7 @@ class HistoryDB:
self.execute(
"""INSERT INTO history (completed, name, nzb_name, category, pp, script, report,
url, status, nzo_id, storage, path, script_log, script_line, download_time, postproc_time, stage_log,
downloaded, fail_message, url_info, bytes, series, md5sum, password)
downloaded, fail_message, url_info, bytes, duplicate_key, md5sum, password)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
t,
save=True,
@@ -275,8 +282,8 @@ class HistoryDB:
start: Optional[int] = None,
limit: Optional[int] = None,
search: Optional[str] = None,
failed_only: int = 0,
categories: Optional[List[str]] = None,
statuses: Optional[List[str]] = None,
nzo_ids: Optional[List[str]] = None,
) -> Tuple[List[Dict[str, Any]], int]:
"""Return records for specified jobs"""
@@ -285,18 +292,20 @@ class HistoryDB:
post = ""
if categories:
categories = ["*" if c == "Default" else c for c in categories]
post = " AND (CATEGORY = ?"
post += " OR CATEGORY = ? " * (len(categories) - 1)
post = " AND (category = ?"
post += " OR category = ? " * (len(categories) - 1)
post += ")"
command_args.extend(categories)
if statuses:
post += " AND (status = ?"
post += " OR status = ? " * (len(statuses) - 1)
post += ")"
command_args.extend(statuses)
if nzo_ids:
post += " AND (NZO_ID = ?"
post += " OR NZO_ID = ? " * (len(nzo_ids) - 1)
post += " AND (nzo_id = ?"
post += " OR nzo_id = ? " * (len(nzo_ids) - 1)
post += ")"
command_args.extend(nzo_ids)
if failed_only:
post += " AND STATUS = ?"
command_args.append(Status.FAILED)
cmd = "SELECT COUNT(*) FROM history WHERE name LIKE ?"
total_items = -1
@@ -321,22 +330,31 @@ class HistoryDB:
return items, total_items
def have_episode(self, series: str, season: str, episode: str) -> bool:
"""Check whether History contains this series episode"""
def have_duplicate_key(self, duplicate_key: str) -> bool:
"""Check whether History contains this duplicate key"""
total = 0
if series and season and episode:
pattern = "%s/%s/%s" % (series.lower(), season, episode)
if self.execute(
"""SELECT COUNT(*) FROM History WHERE series = ? AND STATUS != ?""", (pattern, Status.FAILED)
):
total = self.cursor.fetchone()["COUNT(*)"]
if self.execute(
"""
SELECT COUNT(*)
FROM History
WHERE
duplicate_key = ? AND
STATUS != ?""",
(duplicate_key, Status.FAILED),
):
total = self.cursor.fetchone()["COUNT(*)"]
return total > 0
def have_name_or_md5sum(self, name: str, md5sum: str) -> bool:
"""Check whether this name or md5sum is already in History"""
total = 0
if self.execute(
"""SELECT COUNT(*) FROM History WHERE ( LOWER(name) = LOWER(?) OR md5sum = ? ) AND STATUS != ?""",
"""
SELECT COUNT(*)
FROM History
WHERE
( LOWER(name) = LOWER(?) OR md5sum = ? ) AND
STATUS != ?""",
(name, md5sum, Status.FAILED),
):
total = self.cursor.fetchone()["COUNT(*)"]
@@ -424,7 +442,7 @@ class HistoryDB:
def convert_search(search: str) -> str:
"""Convert classic wildcard to SQL wildcard"""
if not search:
if not search or not isinstance(search, str):
# Default value
search = ""
else:
@@ -467,13 +485,8 @@ def build_history_info(nzo, workdir_complete: str, postproc_time: int, script_ou
# Reuse the old 'report' column to indicate a URL-fetch
report = "future" if nzo.futuretype else ""
# Analyze series info only when job is finished
series = ""
show_analysis = sabnzbd.newsunpack.analyse_show(nzo.final_name)
if show_analysis["job_type"] == "tv":
seriesname, season, episode = (show_analysis[key] for key in ("title", "season", "episode"))
if seriesname and season and episode:
series = "%s/%s/%s" % (seriesname.lower(), season, episode)
# Make sure we have the duplicate key
nzo.set_duplicate_key()
return (
completed,
@@ -497,7 +510,7 @@ def build_history_info(nzo, workdir_complete: str, postproc_time: int, script_ou
nzo.fail_msg,
url_info,
nzo.bytes_downloaded,
series,
nzo.duplicate_key,
nzo.md5sum,
nzo.correct_password,
)

View File

@@ -18,6 +18,8 @@
##############################################################################
# Decorators
##############################################################################
import time
import functools
from typing import Union, Callable
from threading import Lock, RLock, Condition
@@ -60,3 +62,24 @@ def NzbQueueLocker(func: Callable):
DOWNLOADER_CV.release()
return call_func
def cache_maintainer(clear_time: int):
"""
A function decorator that clears functools.cache or functools.lru_cache clear_time seconds
:param clear_time: In seconds, how often to clear cache (only checks when called)
"""
def inner(func):
def wrapper(*args, **kwargs):
if hasattr(func, "next_clear"):
if time.time() > func.next_clear or kwargs.get("force"):
func.cache_clear()
func.next_clear = time.time() + clear_time
else:
func.next_clear = time.time() + clear_time
return func(*args, **kwargs)
return wrapper
return inner

View File

@@ -34,7 +34,7 @@ import os
import re
import sabnzbd
from sabnzbd.filesystem import get_unique_filename, renamer, get_ext
from sabnzbd.filesystem import get_unique_filename, renamer, get_ext, get_basename
from sabnzbd.par2file import is_parfile, parse_par2_file
import sabnzbd.utils.file_extension as file_extension
from sabnzbd.misc import match_str
@@ -299,7 +299,7 @@ def deobfuscate(nzo, filelist: List[str], usefulname: str):
nr_files_renamed += 1
# Now find other files with the same basename in filelist, and rename them in the same way:
basedirfile, _ = os.path.splitext(biggest_file) # something like "/home/this/myiso"
basedirfile = get_basename(biggest_file) # something like "/home/this/myiso"
for otherfile in filelist:
if otherfile.startswith(basedirfile) and os.path.isfile(otherfile):
# yes, same basedirfile, only different ending

View File

@@ -30,7 +30,7 @@ from typing import Optional, Dict, List, Tuple
import sabnzbd
import sabnzbd.cfg as cfg
from sabnzbd.misc import int_conv, format_time_string, build_and_run_command
from sabnzbd.filesystem import long_path, remove_all, real_path, remove_file
from sabnzbd.filesystem import long_path, remove_all, real_path, remove_file, get_basename
from sabnzbd.nzbstuff import NzbObject, NzbFile
from sabnzbd.encoding import platform_btou
from sabnzbd.decorators import synchronized
@@ -252,7 +252,7 @@ class DirectUnpacker(threading.Thread):
self.nzo.set_unpack_info("Unpack", msg, self.cur_setname)
# Write current log and clear
logging.debug("DirectUnpack Unrar output %s", "\n".join(unrar_log))
logging.debug("DirectUnpack Unrar output: \n%s", "\n".join(unrar_log))
unrar_log = []
rarfiles = []
extracted = []
@@ -344,7 +344,7 @@ class DirectUnpacker(threading.Thread):
if linebuf:
unrar_log.append(platform_btou(linebuf.strip()))
if unrar_log:
logging.debug("DirectUnpack Unrar output %s", "\n".join(unrar_log))
logging.debug("DirectUnpack Unrar output: \n%s", "\n".join(unrar_log))
# Make more space
self.reset_active()
@@ -552,7 +552,7 @@ def analyze_rar_filename(filename):
else:
# Detect if first of "rxx" set
if filename.endswith(".rar"):
return os.path.splitext(filename)[0], 1
return get_basename(filename), 1
return None, None
@@ -565,9 +565,9 @@ def abort_all():
def test_disk_performance():
"""Test the incomplete-dir performance and enable
Direct Unpack if good enough (> 40MB/s)
Direct Unpack if good enough (> 100MB/s)
"""
if diskspeedmeasure(sabnzbd.cfg.download_dir.get_path()) > 40:
if diskspeedmeasure(sabnzbd.cfg.download_dir.get_path()) > 100:
cfg.direct_unpack.set(True)
logging.warning(
T("Direct Unpack was automatically enabled.")

View File

@@ -223,7 +223,7 @@ class Server:
def request_addrinfo_blocking(self):
"""Blocking attempt to run getaddrinfo() and Happy Eyeballs for specified server"""
logging.debug("Retrieving server address information for %s", self.host)
self.addrinfo = happyeyeballs(self.host, self.port)
self.addrinfo = happyeyeballs(self.host, self.port, self.timeout)
if not self.addrinfo:
self.bad_cons += self.threads
# Notify next call to maybe_block_server
@@ -503,7 +503,7 @@ class Downloader(Thread):
# Remove all connections to server
for nw in server.idle_threads | server.busy_threads:
self.__reset_nw(nw, "forcing disconnect", warn=False, wait=False, retry_article=False)
self.__reset_nw(nw, "Forcing disconnect", warn=False, wait=False, retry_article=False)
# Make sure server address resolution is refreshed
server.addrinfo = None
@@ -570,7 +570,7 @@ class Downloader(Thread):
# Already showed error
self.__reset_nw(nw)
else:
self.__reset_nw(nw, "timed out", warn=True)
self.__reset_nw(nw, "Timed out", warn=True)
server.bad_cons += 1
self.maybe_block_server(server)
@@ -630,14 +630,14 @@ class Downloader(Thread):
server.host,
sys.exc_info()[1],
)
self.__reset_nw(nw, "failed to initialize", warn=True)
self.__reset_nw(nw, "Failed to initialize", warn=True)
if self.force_disconnect or self.shutdown:
for server in self.servers:
for nw in server.idle_threads | server.busy_threads:
# Send goodbye if we have open socket
if nw.nntp:
self.__reset_nw(nw, "forcing disconnect", wait=False, count_article_try=False)
self.__reset_nw(nw, "Forcing disconnect", wait=False, count_article_try=False)
# Make sure server address resolution is refreshed
server.addrinfo = None
server.reset_article_queue()
@@ -666,7 +666,7 @@ class Downloader(Thread):
else:
read = []
BPSMeter.reset()
time.sleep(1.0)
time.sleep(0.1)
self.max_chunk_size = _DEFAULT_CHUNK_SIZE
with DOWNLOADER_CV:
while (
@@ -715,7 +715,7 @@ class Downloader(Thread):
except ssl.SSLWantReadError:
return
except:
self.__reset_nw(nw, "server closed connection", wait=False)
self.__reset_nw(nw, "Server closed connection", wait=False)
return
article = nw.article
@@ -888,6 +888,13 @@ class Downloader(Thread):
errormsg = T("Cannot connect to server %s [%s]") % (server.host, error.msg)
penalty = _PENALTY_UNKNOWN
block = True
# Set error for server and warn user if it was first time thrown
if errormsg and server.active and server.errormsg != errormsg:
server.errormsg = errormsg
logging.warning(errormsg)
# Take action on the problem
if block or (penalty and server.optional):
retry_article = False
if server.active:
@@ -900,19 +907,15 @@ class Downloader(Thread):
self.plan_server(server, penalty)
# Note that the article is discard for this server if the server is not required
self.__reset_nw(nw, retry_article=retry_article)
# Set error for server and warn user if it was first time thrown
if errormsg and server.active and server.errormsg != errormsg:
server.errormsg = errormsg
logging.warning(errormsg)
return False
except:
except Exception as err:
logging.error(
T("Connecting %s@%s failed, message=%s"),
nw.thrdnum,
nw.server.host,
nw.nntp_msg,
err,
)
logging.info("Traceback: ", exc_info=True)
# No reset-warning needed, above logging is sufficient
self.__reset_nw(nw, retry_article=False)
return True
@@ -983,11 +986,11 @@ class Downloader(Thread):
self.add_socket(nw.nntp.fileno, nw)
except socket.error as err:
logging.info("Looks like server closed connection: %s", err)
self.__reset_nw(nw, "server broke off connection", warn=True)
self.__reset_nw(nw, "Server broke off connection", warn=True)
except:
logging.error(T("Suspect error in downloader"))
logging.info("Traceback: ", exc_info=True)
self.__reset_nw(nw, "server broke off connection", warn=True)
self.__reset_nw(nw, "Server broke off connection", warn=True)
# ------------------------------------------------------------------------------
# Timed restart of servers admin.

View File

@@ -33,6 +33,7 @@ import fnmatch
import stat
import ctypes
import random
import functools
from typing import Union, List, Tuple, Any, Dict, Optional, BinaryIO
try:
@@ -42,7 +43,7 @@ except ImportError:
pass
import sabnzbd
from sabnzbd.decorators import synchronized
from sabnzbd.decorators import synchronized, cache_maintainer
from sabnzbd.constants import FUTURE_Q_FOLDER, JOB_ADMIN, GIGI, DEF_FILE_MAX, IGNORED_FILES_AND_FOLDERS, DEF_LOG_FILE
from sabnzbd.encoding import correct_unknown_encoding, utob, ubtou
from sabnzbd.utils import rarfile
@@ -63,6 +64,11 @@ def get_ext(filename: str) -> str:
return ""
def get_basename(filename: str) -> str:
"""Shorthand for getting the basename of a filename"""
return os.path.splitext(filename)[0]
def is_listed_ext(ext: str, ext_list: list) -> bool:
"""Check if the extension is listed. In case of a regexp the entire extension must be matched;
partial matches aren't accepted (e.g. 'r[0-9]{2}' will be treated the same as '^r[0-9]{2}$' and
@@ -111,7 +117,7 @@ def get_filename(path: str) -> str:
def setname_from_path(path: str) -> str:
"""Get the setname from a path"""
return os.path.splitext(os.path.basename(path))[0]
return get_basename(os.path.basename(path))
def is_writable(path: str) -> bool:
@@ -447,9 +453,23 @@ def same_directory(a: str, b: str) -> int:
return is_subfolder
def check_mount(path: str) -> bool:
"""Return False if volume isn't mounted on Linux or macOS
Retry 6 times with an interval of 1 sec.
def is_network_path(path: str) -> bool:
"""Check weither a path is a network path.
On Windows, use win32 functions to detect users that try to avoid this detection by using a mapped drive letter.
We don't check on Linux for mnt or media, since those could also be used for internal drives."""
path = clip_path(path)
if path.startswith(r"\\"):
return True
if sabnzbd.WIN32:
drive_letter, _ = os.path.splitdrive(path)
return win32file.GetDriveType(drive_letter) == win32file.DRIVE_REMOTE
return False
def mount_is_available(path: str) -> bool:
"""Return False if volume isn't mounted on Linux or macOS or
the network path isn't available on Windows.
Retry wait_ext_drive times with an interval of 1 sec.
"""
if sabnzbd.MACOS:
m = re.search(r"^(/Volumes/[^/]+)", path, re.I)
@@ -574,7 +594,7 @@ def list_scripts(default: bool = False, none: bool = True) -> List[str]:
if (
(
sabnzbd.WIN32
and os.path.splitext(script)[1].lower() in PATHEXT
and get_ext(script) in PATHEXT
and not win32api.GetFileAttributes(script) & win32file.FILE_ATTRIBUTE_HIDDEN
)
or script.endswith(".py")
@@ -743,7 +763,7 @@ def create_all_dirs(path: str, apply_permissions: bool = False) -> Union[str, bo
@synchronized(DIR_LOCK)
def get_unique_dir(path: str, n: int = 0, create_dir: bool = True) -> Union[str, bool]:
"""Determine a unique folder or filename"""
if not check_mount(path):
if not mount_is_available(path):
return path
new_path = path
@@ -1063,43 +1083,15 @@ def diskspace_base(dir_to_check: str) -> Tuple[float, float]:
return 20.0, 10.0
# Store all results to speed things up
__DIRS_CHECKED = []
__DISKS_SAME = None
__LAST_DISK_RESULT = {"download_dir": (0.0, 0.0), "complete_dir": (0.0, 0.0)}
__LAST_DISK_CALL = 0
@cache_maintainer(clear_time=10)
@functools.lru_cache(maxsize=None)
def diskspace(force: bool = False) -> Dict[str, Tuple[float, float]]:
"""Wrapper to cache results"""
global __DIRS_CHECKED, __DISKS_SAME, __LAST_DISK_RESULT, __LAST_DISK_CALL
# Reset everything when folders changed
dirs_to_check = [sabnzbd.cfg.download_dir.get_path(), sabnzbd.cfg.complete_dir.get_path()]
if __DIRS_CHECKED != dirs_to_check:
__DIRS_CHECKED = dirs_to_check
__DISKS_SAME = None
__LAST_DISK_RESULT = {"download_dir": [], "complete_dir": []}
__LAST_DISK_CALL = 0
# When forced, ignore any cache to avoid problems in UI
if force:
__LAST_DISK_CALL = 0
# Check against cache
if time.time() > __LAST_DISK_CALL + 10.0:
# Same disk? Then copy-paste
__LAST_DISK_RESULT["download_dir"] = diskspace_base(sabnzbd.cfg.download_dir.get_path())
__LAST_DISK_RESULT["complete_dir"] = (
__LAST_DISK_RESULT["download_dir"] if __DISKS_SAME else diskspace_base(sabnzbd.cfg.complete_dir.get_path())
)
__LAST_DISK_CALL = time.time()
# Do we know if it's same disk?
if __DISKS_SAME is None:
__DISKS_SAME = __LAST_DISK_RESULT["download_dir"] == __LAST_DISK_RESULT["complete_dir"]
return __LAST_DISK_RESULT
"""Wrapper to keep results cached by cache_maintainer
If called with force=True, the wrapper will clear the results"""
return {
"download_dir": diskspace_base(sabnzbd.cfg.download_dir.get_path()),
"complete_dir": diskspace_base(sabnzbd.cfg.complete_dir.get_path()),
}
def get_new_id(prefix, folder, check_list=None):
@@ -1213,8 +1205,7 @@ def wait_for_download_folder():
def backup_exists(filename: str) -> bool:
"""Return True if backup exists and no_dupes is set"""
path = sabnzbd.cfg.nzb_backup_dir.get_path()
return path and os.path.exists(os.path.join(path, filename + ".gz"))
return os.path.exists(os.path.join(sabnzbd.cfg.nzb_backup_dir.get_path(), filename + ".gz"))
def backup_nzb(nzb_path: str):

View File

@@ -19,24 +19,28 @@
sabnzbd.happyeyeballs - Python implementation of RFC 6555 / Happy Eyeballs: find the quickest IPv4/IPv6 connection
"""
# Python implementation of RFC 6555 / Happy Eyeballs: find the quickest IPv4/IPv6 connection
# Python implementation of RFC 6555/8305 (Happy Eyeballs): find the quickest IPv4/IPv6 connection
# See https://tools.ietf.org/html/rfc6555
# Method: Start parallel sessions using threads, and only wait for the quickest successful socket connect
# See https://tools.ietf.org/html/rfc6555#section-4.1
# We do not implement caching, as the lookup result is stored in the Server object
# See https://tools.ietf.org/html/rfc8305
import socket
import threading
import time
import logging
import queue
import functools
from dataclasses import dataclass
from typing import Tuple, Union, Optional
from more_itertools import roundrobin
from sabnzbd import cfg as cfg
from sabnzbd.constants import DEF_TIMEOUT
from sabnzbd.decorators import cache_maintainer
# We always prefer IPv6 connections
IP4_DELAY = 0.1
# How long to delay between connection attempts? The RFC suggests 250ms, but this is
# quite long and might give us a slow host that just happened to be on top of the list.
# The absolute minium specified in RFC 8305 is 10ms, so we use that.
CONNECTION_ATTEMPT_DELAY = 0.01
# For typing and convenience!
@@ -55,71 +59,107 @@ class AddrInfo:
# Called by each thread
def do_socket_connect(result_queue: queue.Queue, addrinfo: AddrInfo, ipv4_delay: int):
def do_socket_connect(result_queue: queue.Queue, addrinfo: AddrInfo, timeout: int):
"""Connect to the ip, and put the result into the queue"""
try:
start = time.time()
s = socket.socket(addrinfo.family, addrinfo.type)
s.settimeout(3)
# Delay IPv4 connects in case we need it
if ipv4_delay and addrinfo.family == socket.AddressFamily.AF_INET:
time.sleep(ipv4_delay)
s.settimeout(timeout)
try:
s.connect(addrinfo.sockaddr)
result_queue.put(addrinfo)
logging.debug(
"Happy Eyeballs connected to %s (%s) in %dms",
addrinfo.ipaddress,
addrinfo.canonname,
1000 * (time.time() - start),
)
except socket.error:
logging.debug(
"Happy Eyeballs failed to connect to %s (%s) in %dms",
addrinfo.ipaddress,
addrinfo.canonname,
1000 * (time.time() - start),
)
finally:
s.close()
result_queue.put((addrinfo, True))
except:
# We got an exception, so no successful connect on IP & port:
result_queue.put((addrinfo, False))
pass
def happyeyeballs(host: str, port: int) -> Optional[AddrInfo]:
"""Return the fastest result of getaddrinfo() based on RFC 6555 / Happy Eyeballs,
@cache_maintainer(clear_time=10)
@functools.lru_cache(maxsize=None)
def happyeyeballs(host: str, port: int, timeout: int = DEF_TIMEOUT) -> Optional[AddrInfo]:
"""Return the fastest result of getaddrinfo() based on RFC 6555/8305 (Happy Eyeballs),
including IPv6 addresses if desired. Returns None in case no addresses were returned
or if no connection could be made to any of the addresses"""
by getaddrinfo or if no connection could be made to any of the addresses"""
try:
# Time how long it took us
start = time.time()
# Get address information, by default both IPV4 and IPV6
family = socket.AF_UNSPEC
if not cfg.ipv6_servers():
family = socket.AF_INET
all_addrinfo = []
ipv4_delay = 0
ipv4_addrinfo = []
ipv6_addrinfo = []
last_canonname = ""
for addrinfo in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM, flags=socket.AI_CANONNAME):
# Convert to AddrInfo
all_addrinfo.append(addrinfo := AddrInfo(*addrinfo))
# We only want delay for IPv4 in case we got any IPv6
if addrinfo.family == socket.AddressFamily.AF_INET6:
ipv4_delay = IP4_DELAY
# The canonname is only reported once per alias
if addrinfo.canonname:
last_canonname = addrinfo.canonname
elif last_canonname:
addrinfo.canonname = last_canonname
logging.debug("Available addresses for %s (port=%d): %d", host, port, len(all_addrinfo))
# Fill queue used for threads that will return the results
# Even if there is just 1 result, we still check if we can connect
result_queue: queue.Queue[Tuple[AddrInfo, bool]] = queue.Queue()
for addrinfo in all_addrinfo:
threading.Thread(target=do_socket_connect, args=(result_queue, addrinfo, ipv4_delay), daemon=True).start()
try:
for addrinfo in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM, flags=socket.AI_CANONNAME):
# Convert to AddrInfo
addrinfo = AddrInfo(*addrinfo)
# start reading from the Queue for message from the threads:
result = None
for _ in range(len(all_addrinfo)):
connect_result = result_queue.get()
if connect_result[1]:
result = connect_result[0]
# The canonname is only reported once per alias
if addrinfo.canonname:
last_canonname = addrinfo.canonname
elif last_canonname:
addrinfo.canonname = last_canonname
# Put it in the right list for further processing
# But prevent adding duplicate items to the lists
if addrinfo not in ipv6_addrinfo and addrinfo not in ipv4_addrinfo:
if addrinfo.family == socket.AddressFamily.AF_INET6:
ipv6_addrinfo.append(addrinfo)
else:
ipv4_addrinfo.append(addrinfo)
except:
# Did we fail on the first getaddrinfo already?
# Otherwise, we failed on the IPv6 alternative address, and those failures can be ignored
if not ipv4_addrinfo and not ipv6_addrinfo:
raise
logging.debug(
"Available addresses for %s (port=%d): %d IPv4 and %d IPv6",
host,
port,
len(ipv4_addrinfo),
len(ipv6_addrinfo),
)
# To optimize success, the RFC states to alternate between trying the
# IPv6 and IPv4 results, starting with IPv6 since it is the preferred method.
result_queue: queue.Queue[AddrInfo] = queue.Queue()
addr_tried = 0
result: Optional[AddrInfo] = None
for addrinfo in roundrobin(ipv6_addrinfo, ipv4_addrinfo):
threading.Thread(target=do_socket_connect, args=(result_queue, addrinfo, timeout), daemon=True).start()
addr_tried += 1
try:
result = result_queue.get(timeout=CONNECTION_ATTEMPT_DELAY)
break
except queue.Empty:
# Start a thread for the next address in the list if the previous
# connection attempt did not complete in time or if it wasn't a success
continue
# If we had no results, we might just need to give it more time
if not result:
try:
# Reduce waiting time by time already spent
result = result_queue.get(timeout=timeout - addr_tried * CONNECTION_ATTEMPT_DELAY)
except queue.Empty:
raise ConnectionError("No addresses could be resolved")
logging.info("Quickest IP address for %s (port=%d): %s (%s)", host, port, result.ipaddress, result.canonname)
logging.debug("Happy Eyeballs lookup and port connect took: %d ms", int(1000 * (time.time() - start)))
return result
except Exception as e:
logging.debug("Failed Happy Eyeballs lookup: %s", e)

View File

@@ -21,7 +21,7 @@ sabnzbd.interface - webinterface
import os
import time
from datetime import datetime
import datetime
import cherrypy
import logging
import urllib.parse
@@ -80,6 +80,7 @@ from sabnzbd.constants import (
GUESSIT_SORT_TYPES,
VALID_NZB_FILES,
VALID_ARCHIVES,
DEF_TIMEOUT,
)
from sabnzbd.lang import list_languages
from sabnzbd.api import (
@@ -766,6 +767,7 @@ SWITCH_LIST = (
"nice",
"ionice",
"pre_script",
"end_queue_script",
"pause_on_pwrar",
"sfv_check",
"deobfuscate_final_filenames",
@@ -780,8 +782,8 @@ SWITCH_LIST = (
"fail_hopeless_jobs",
"enable_all_par",
"enable_recursive",
"no_series_dupes",
"series_propercheck",
"no_smart_dupes",
"dupes_propercheck",
"script_can_fail",
"unwanted_extensions",
"action_on_unwanted_extensions",
@@ -1150,7 +1152,7 @@ def handle_server(kwargs, root=None, new_svr=False):
kwargs["connections"] = "1"
if kwargs.get("enable") == "1":
if not happyeyeballs(host, int_conv(port)):
if not happyeyeballs(host, int_conv(port), int_conv(kwargs.get("timeout"), default=DEF_TIMEOUT)):
return badParameterResponse(T('Server address "%s:%s" is not valid.') % (host, port), ajax)
# Default server name is just the host name
@@ -1484,16 +1486,24 @@ class ConfigRss:
"""Download NZB from provider (Download button)"""
feed = kwargs.get("feed")
url = kwargs.get("url")
nzbname = kwargs.get("nzbname")
att = sabnzbd.RSSReader.lookup_url(feed, url)
if att:
if att := sabnzbd.RSSReader.lookup_url(feed, url):
nzbname = kwargs.get("nzbname")
pp = att.get("pp")
cat = att.get("cat")
script = att.get("script")
prio = att.get("prio")
priority = att.get("prio")
if url:
sabnzbd.urlgrabber.add_url(url, pp, script, cat, prio, nzbname)
logging.info("Adding %s (%s) to queue", url, nzbname)
sabnzbd.urlgrabber.add_url(
url,
pp=pp,
script=script,
cat=cat,
priority=priority,
nzbname=nzbname,
nzo_info={"RSS": feed},
)
# Need to pass the title instead
sabnzbd.RSSReader.flag_downloaded(feed, url)
raise rssRaiser(self.__root, kwargs)
@@ -1934,7 +1944,7 @@ def GetRssLog(feed):
# And we add extra fields for sorting
if job.get("age", 0):
job["age_ms"] = (job["age"] - datetime.utcfromtimestamp(0)).total_seconds()
job["age_ms"] = (job["age"] - datetime.datetime(1970, 1, 1)).total_seconds()
job["age"] = calc_age(job["age"], True)
else:
job["age_ms"] = ""
@@ -2117,7 +2127,7 @@ class ConfigNotify:
@secured_expose(check_configlock=True)
def index(self, **kwargs):
conf = build_header(sabnzbd.WEB_DIR_CONFIG)
conf["notify_types"] = sabnzbd.notifier.NOTIFICATION
conf["notify_types"] = sabnzbd.notifier.NOTIFICATION_TYPES
conf["categories"] = list_cats(False)
conf["have_ntfosd"] = sabnzbd.notifier.have_ntfosd()
conf["have_ncenter"] = sabnzbd.MACOS and sabnzbd.FOUNDATION

110
sabnzbd/internetspeed.py Normal file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2023 The SABnzbd-Team (sabnzbd.org)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
sabnzbd.internetspeed - Measure internet bandwidth using sabctools routines
"""
import sys
import logging
import socket
import ssl
import time
import threading
from typing import Dict
import sabctools
import sabnzbd
from sabnzbd.happyeyeballs import happyeyeballs
TEST_HOSTNAME = "sabnzbd.org"
TEST_PORT = 443
TEST_FILE = "/tests/internetspeed/100MB.bin"
TEST_FILE_SIZE = 100 * 1024 * 1024
TEST_REQUEST = f"GET {TEST_FILE} HTTP/1.1\nHost: {TEST_HOSTNAME}\nUser-Agent: SABnzbd/{sabnzbd.__version__}\n\n"
SOCKET_TIMEOUT = 3
BUFFER_SIZE = 5 * 1024 * 1024 # Each connection will allocate its own buffer, so mind the memory usage!
NR_CONNECTIONS = 5
TIME_LIMIT = 3
def internetspeed_worker(secure_sock: ssl.SSLSocket, socket_speed: Dict[ssl.SSLSocket, float]):
"""Worker to perform the requests in parallel"""
secure_sock.sendall(TEST_REQUEST.encode())
empty_buffer = memoryview(sabctools.bytearray_malloc(BUFFER_SIZE))
start_time = time.perf_counter()
diff_time = 0
data_received = 0
while diff_time < TIME_LIMIT:
if data_received < TEST_FILE_SIZE:
try:
if new_bytes := sabctools.unlocked_ssl_recv_into(secure_sock, empty_buffer):
# Update the speed after every loop
diff_time = time.perf_counter() - start_time
data_received += new_bytes
socket_speed[secure_sock] = data_received / diff_time
else:
break
except ssl.SSLWantReadError:
time.sleep(0)
else:
break
try:
secure_sock.close()
except socket.error:
# In case socket was closed unexpectedly already
pass
def internetspeed(test_time_limit: int = TIME_LIMIT) -> float:
"""Measure internet speed from a test-download using our optimized SSL-code"""
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
socket_speed = {}
try:
for _ in range(NR_CONNECTIONS):
addrinfo = happyeyeballs(TEST_HOSTNAME, TEST_PORT, SOCKET_TIMEOUT)
sock = socket.socket(addrinfo.family, addrinfo.type)
sock.settimeout(SOCKET_TIMEOUT)
sock.connect(addrinfo.sockaddr)
secure_sock = context.wrap_socket(sock, server_hostname=TEST_HOSTNAME)
secure_sock.setblocking(False)
socket_speed[secure_sock] = 0
for secure_sock in socket_speed:
threading.Thread(target=internetspeed_worker, args=(secure_sock, socket_speed), daemon=True).start()
except Exception:
logging.info("Internet Bandwidth connection failure", exc_info=True)
return 0.0
# We let the workers finish
time.sleep(test_time_limit + 0.5)
speed = sum(socket_speed.values()) / 1024 / 1024
logging.debug("Internet Bandwidth = %.2f MB/s - %.2f Mbps", speed, speed * 8.05)
return speed
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
internetspeed()

View File

@@ -52,7 +52,7 @@ from sabnzbd.constants import (
import sabnzbd.config as config
import sabnzbd.cfg as cfg
from sabnzbd.encoding import ubtou
from sabnzbd.filesystem import userxbit, make_script_path, remove_file, is_valid_script
from sabnzbd.filesystem import userxbit, make_script_path, remove_file
if sabnzbd.WIN32:
try:
@@ -85,7 +85,14 @@ HAVE_AMPM = bool(time.strftime("%p"))
def helpful_warning(*args, **kwargs):
"""Wrapper to ignore helpful warnings if desired"""
if sabnzbd.cfg.helpful_warnings():
if cfg.helpful_warnings():
return logging.warning(*args, **kwargs)
return logging.info(*args, **kwargs)
def duplicate_warning(*args, **kwargs):
"""Wrapper to ignore duplicate warnings if desired"""
if cfg.warn_dupl_jobs():
return logging.warning(*args, **kwargs)
return logging.info(*args, **kwargs)
@@ -228,7 +235,7 @@ def cat_to_opts(cat, pp=None, script=None, priority=None) -> Tuple[str, int, str
return cat, pp, script, priority
def pp_to_opts(pp: int) -> Tuple[bool, bool, bool]:
def pp_to_opts(pp: Optional[int]) -> Tuple[bool, bool, bool]:
"""Convert numeric processing options to (repair, unpack, delete)"""
# Convert the pp to an int
pp = sabnzbd.interface.int_conv(pp)
@@ -791,12 +798,13 @@ def format_time_string(seconds: float) -> str:
return " ".join(completestr)
def int_conv(value: Any) -> int:
"""Safe conversion to int (can handle None)"""
def int_conv(value: Any, default: Any = 0) -> int:
"""Safe conversion to int (can handle None)
Returns 0 or requested default value"""
try:
return int(value)
except:
return 0
return default
def create_https_certificates(ssl_cert, ssl_key):
@@ -1161,15 +1169,14 @@ def run_command(cmd: List[str], **kwargs):
return txt
def run_script(script):
"""Run a user script (queue complete only)"""
script_path = make_script_path(script)
if script_path:
def run_script(script: str):
"""Run a user script"""
if script_path := make_script_path(script):
try:
script_output = run_command([script_path])
logging.info("Output of queue-complete script %s: \n%s", script, script_output)
script_output = run_command([script_path], env=sabnzbd.newsunpack.create_env())
logging.info("Output of script %s: \n%s", script, script_output)
except:
logging.info("Failed queue-complete script %s, Traceback: ", script, exc_info=True)
logging.info("Failed script %s, Traceback: ", script, exc_info=True)
def set_socks5_proxy():
@@ -1288,24 +1295,17 @@ def system_standby():
def change_queue_complete_action(action: str, new: bool = True):
"""Action or script to be performed once the queue has been completed
Scripts are prefixed with 'script_'
"""
_action = None
_argument = None
"""Action or script to be performed once the queue has been completed"""
function = None
if new or cfg.queue_complete_pers():
if action.startswith("script_") and is_valid_script(action.replace("script_", "", 1)):
# all scripts are labeled script_xxx
_action = sabnzbd.misc.run_script
_argument = action.replace("script_", "", 1)
elif action == "shutdown_pc":
_action = system_shutdown
if action == "shutdown_pc":
function = system_shutdown
elif action == "hibernate_pc":
_action = system_hibernate
function = system_hibernate
elif action == "standby_pc":
_action = system_standby
function = system_standby
elif action == "shutdown_program":
_action = sabnzbd.shutdown_program
function = sabnzbd.shutdown_program
else:
action = None
else:
@@ -1316,8 +1316,7 @@ def change_queue_complete_action(action: str, new: bool = True):
config.save_config()
sabnzbd.QUEUECOMPLETE = action
sabnzbd.QUEUECOMPLETEACTION = _action
sabnzbd.QUEUECOMPLETEARG = _argument
sabnzbd.QUEUECOMPLETEACTION = function
def keep_awake():

View File

@@ -61,11 +61,12 @@ from sabnzbd.filesystem import (
get_filename,
SEVENMULTI_RE,
is_size,
get_basename,
)
from sabnzbd.nzbstuff import NzbObject
import sabnzbd.cfg as cfg
from sabnzbd.constants import Status, JOB_ADMIN
from sabnzbd.sorting import Sorter
# Regex globals
RAR_V3_RE = re.compile(r"\.(?P<ext>part\d*)$", re.I)
@@ -184,6 +185,7 @@ ENV_NZO_FIELDS = [
"cat",
"correct_password",
"duplicate",
"duplicate_key",
"encrypted",
"fail_msg",
"filename",
@@ -511,7 +513,7 @@ def rar_unpack(nzo: NzbObject, workdir_complete: str, one_folder: bool, rars: Li
rar_set = setname_from_path(rar)
if RAR_V3_RE.search(rar_set):
# Remove the ".partXX" part
rar_set = os.path.splitext(rar_set)[0]
rar_set = get_basename(rar_set)
if rar_set not in rar_sets:
rar_sets[rar_set] = []
rar_sets[rar_set].append(rar)
@@ -878,7 +880,7 @@ def unseven(nzo: NzbObject, workdir_complete: str, one_folder: bool, sevens: Lis
setname = setname_from_path(seven)
if SEVENMULTI_RE.search(setname):
# Remove the ".001" part
setname = os.path.splitext(setname)[0]
setname = get_basename(setname)
if setname not in seven_sets:
seven_sets[setname] = []
seven_sets[setname].append(seven)
@@ -1090,7 +1092,7 @@ def par2_repair(nzo: NzbObject, setname: str) -> Tuple[bool, bool]:
# Remove extra files created during repair and par2 base files
for path in new_dir_content:
if os.path.splitext(path)[1] == ".1" and path not in old_dir_content:
if get_ext(path) == ".1" and path not in old_dir_content:
deletables.append(os.path.join(nzo.download_path, path))
deletables.append(os.path.join(nzo.download_path, setname + ".par2"))
deletables.append(os.path.join(nzo.download_path, setname + ".PAR2"))
@@ -2134,41 +2136,6 @@ def add_time_left(perc: float, start_time: Optional[float] = None, time_used: Op
return ""
def analyse_show(name: str) -> Dict[str, str]:
"""Use the Sorter to collect some basic info on series"""
job = Sorter(
None,
name,
None,
None,
force=True,
sorter_config={
"name": "newsunpack__analyse_show",
"order": 0,
"min_size": -1,
"multipart_label": "",
"sort_string": "",
"sort_cats": [], # Categories and types are ignored when using the force
"sort_type": [],
"is_active": 1,
},
)
job.get_values()
return {
"title": job.info.get("title", ""),
"season": job.info.get("season_num", ""),
"episode": job.info.get("episode_num", ""),
"episode_name": job.info.get("ep_name", ""),
"is_proper": job.is_proper(),
"resolution": job.info.get("resolution", ""),
"decade": job.info.get("decade", ""),
"year": job.info.get("year", ""),
"month": job.info.get("month", ""),
"day": job.info.get("day", ""),
"job_type": job.type,
}
def pre_queue(nzo: NzbObject, pp, cat):
"""Run pre-queue script (if any) and process results.
pp and cat are supplied separate since they can change.
@@ -2194,23 +2161,23 @@ def pre_queue(nzo: NzbObject, pp, cat):
str(nzo.bytes),
" ".join(nzo.groups),
]
command.extend(list(analyse_show(nzo.final_name_with_password).values()))
command = [fix(arg) for arg in command]
# Fields not in the NZO directly
show_analysis = sabnzbd.sorting.BasicAnalyzer(nzo.final_name)
extra_env_fields = {
"groups": " ".join(nzo.groups),
"show_name": command[8],
"show_season": command[9],
"show_episode": command[10],
"show_episode_name": command[11],
"proper": command[12],
"resolution": command[13],
"decade": command[14],
"year": command[15],
"month": command[16],
"day": command[17],
"type": command[18],
"title": show_analysis.info.get("title", ""),
"season": show_analysis.info.get("season_num", ""),
"episode": show_analysis.info.get("episode_num", ""),
"episode_name": show_analysis.info.get("ep_name", ""),
"is_proper": show_analysis.is_proper(),
"resolution": show_analysis.info.get("resolution", ""),
"decade": show_analysis.info.get("decade", ""),
"year": show_analysis.info.get("year", ""),
"month": show_analysis.info.get("month", ""),
"day": show_analysis.info.get("day", ""),
"job_type": show_analysis.type,
}
try:

View File

@@ -199,7 +199,7 @@ class NewsWrapper:
# No data received
if bytes_recv == 0:
raise ConnectionError("server closed connection")
raise ConnectionError("Server closed connection")
# Success, move timeout and internal data position
self.timeout = time.time() + self.server.timeout

View File

@@ -28,6 +28,7 @@ import urllib.parse
import http.client
import json
from threading import Thread
from typing import Optional, Dict
import sabnzbd
import sabnzbd.cfg
@@ -36,9 +37,17 @@ from sabnzbd.filesystem import make_script_path
from sabnzbd.misc import build_and_run_command
from sabnzbd.newsunpack import create_env
if sabnzbd.FOUNDATION:
import Foundation
import objc
if sabnzbd.WIN32:
try:
from win32comext.shell import shell
from windows_toasts import InteractableWindowsToaster, Toast, ToastActivatedEventArgs, ToastButton
# Set a custom AUMID to display the right icon, it is written to the registry by the installer
shell.SetCurrentProcessExplicitAppUserModelID("SABnzbd")
_HAVE_WINDOWS_TOASTER = True
except:
# Only supported on Windows 10 and above
_HAVE_WINDOWS_TOASTER = False
try:
import notify2
@@ -57,7 +66,7 @@ except:
# Define translatable message table
##############################################################################
TT = lambda x: x
NOTIFICATION = {
NOTIFICATION_TYPES = {
"startup": TT("Startup/Shutdown"), #: Notification
"pause_resume": TT("Pause") + "/" + TT("Resume"), #: Notification
"download": TT("Added NZB"), #: Notification
@@ -72,37 +81,36 @@ NOTIFICATION = {
"other": TT("Other Messages"), #: Notification
}
def get_icon():
icon = os.path.join(sabnzbd.DIR_PROG, "icons", "sabnzbd.ico")
with open(icon, "rb") as fp:
return fp.read()
NOTIFICATION_ACTIONS = {
"open_folder": TT("Open folder"), #: Notification action
"open_complete": TT("Open complete folder"), #: Notification action
}
def have_ntfosd():
def have_ntfosd() -> bool:
"""Return if any PyNotify (notify2) support is present"""
return bool(_HAVE_NTFOSD)
def check_classes(gtype, section):
"""Check if `gtype` is enabled in `section`"""
def check_classes(notification_type: str, section: str) -> bool:
"""Check if `notification_type` is enabled in `section`"""
try:
return sabnzbd.config.get_config(section, "%s_prio_%s" % (section, gtype))() > 0
return sabnzbd.config.get_config(section, "%s_prio_%s" % (section, notification_type))() > 0
except TypeError:
logging.debug("Incorrect Notify option %s:%s_prio_%s", section, section, gtype)
logging.debug("Incorrect Notify option %s:%s_prio_%s", section, section, notification_type)
return False
def get_prio(gtype, section):
"""Check prio of `gtype` in `section`"""
def get_prio(notification_type: str, section: str) -> int:
"""Check prio of `notification_type` in `section`"""
try:
return sabnzbd.config.get_config(section, "%s_prio_%s" % (section, gtype))()
return sabnzbd.config.get_config(section, "%s_prio_%s" % (section, notification_type))()
except TypeError:
logging.debug("Incorrect Notify option %s:%s_prio_%s", section, section, gtype)
logging.debug("Incorrect Notify option %s:%s_prio_%s", section, section, notification_type)
return -1000
def check_cat(section, job_cat, keyword=None):
def check_cat(section: str, job_cat: str, keyword: Optional[str] = None) -> bool:
"""Check if `job_cat` is enabled in `section`.
* = All, if no other categories selected.
"""
@@ -118,42 +126,48 @@ def check_cat(section, job_cat, keyword=None):
return True
def send_notification(title, msg, gtype, job_cat=None):
def send_notification(
title: str,
msg: str,
notification_type: str,
job_cat: Optional[str] = None,
actions: Optional[Dict[str, str]] = None,
):
"""Send Notification message"""
logging.info("Sending notification: %s - %s (type=%s, job_cat=%s)", title, msg, gtype, job_cat)
logging.info("Sending notification: %s - %s (type=%s, job_cat=%s)", title, msg, notification_type, job_cat)
# Notification Center
if sabnzbd.MACOS and sabnzbd.cfg.ncenter_enable():
if check_classes(gtype, "ncenter") and check_cat("ncenter", job_cat):
send_notification_center(title, msg, gtype)
if check_classes(notification_type, "ncenter") and check_cat("ncenter", job_cat):
send_notification_center(title, msg, notification_type, actions)
# Windows
if sabnzbd.WIN32 and sabnzbd.cfg.acenter_enable():
if check_classes(gtype, "acenter") and check_cat("acenter", job_cat):
send_windows(title, msg, gtype)
if check_classes(notification_type, "acenter") and check_cat("acenter", job_cat):
send_windows(title, msg, notification_type, actions)
# 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()
Thread(target=send_prowl, args=(title, msg, notification_type)).start()
# 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()
Thread(target=send_pushover, args=(title, msg, notification_type)).start()
# 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()
if sabnzbd.cfg.pushbullet_apikey() and check_classes(notification_type, "pushbullet"):
Thread(target=send_pushbullet, args=(title, msg, notification_type)).start()
# 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()
Thread(target=send_nscript, args=(title, msg, notification_type)).start()
# NTFOSD
if have_ntfosd() and sabnzbd.cfg.ntfosd_enable():
if check_classes(gtype, "ntfosd") and check_cat("ntfosd", job_cat):
if check_classes(notification_type, "ntfosd") and check_cat("ntfosd", job_cat):
send_notify_osd(title, msg)
@@ -193,25 +207,26 @@ def send_notify_osd(title, message):
return error
def send_notification_center(title, msg, gtype):
"""Send message to macOS Notification Center"""
def send_notification_center(title: str, msg: str, notification_type: str, actions: Optional[Dict[str, str]] = None):
"""Send message to macOS Notification Center.
Only 1 button is possible on macOS!"""
try:
NSUserNotification = objc.lookUpClass("NSUserNotification")
NSUserNotificationCenter = objc.lookUpClass("NSUserNotificationCenter")
notification = NSUserNotification.alloc().init()
notification.setTitle_(title)
notification.setSubtitle_(T(NOTIFICATION.get(gtype, "other")))
notification.setInformativeText_(msg)
notification.setSoundName_("NSUserNotificationDefaultSoundName")
notification.setDeliveryDate_(Foundation.NSDate.dateWithTimeInterval_sinceDate_(0, Foundation.NSDate.date()))
NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
subtitle = T(NOTIFICATION_TYPES.get(notification_type, "other"))
button_text = button_action = None
if actions:
for action in actions:
button_text = NOTIFICATION_ACTIONS[action]
button_action = actions[action]
break
sabnzbd.MACOSTRAY.send_notification(title, subtitle, msg, button_text, button_action)
except:
logging.info(T("Failed to send macOS notification"))
logging.debug("Traceback: ", exc_info=True)
return T("Failed to send macOS notification")
def send_prowl(title, msg, gtype, force=False, test=None):
def send_prowl(title, msg, notification_type, force=False, test=None):
"""Send message to Prowl"""
if test:
@@ -221,10 +236,10 @@ def send_prowl(title, msg, gtype, force=False, test=None):
if not apikey:
return T("Cannot send, missing required data")
title = T(NOTIFICATION.get(gtype, "other"))
title = T(NOTIFICATION_TYPES.get(notification_type, "other"))
title = urllib.parse.quote(utob(title))
msg = urllib.parse.quote(utob(msg))
prio = get_prio(gtype, "prowl")
prio = get_prio(notification_type, "prowl")
if force:
prio = 0
@@ -244,7 +259,7 @@ def send_prowl(title, msg, gtype, force=False, test=None):
return ""
def send_pushover(title, msg, gtype, force=False, test=None):
def send_pushover(title, msg, notification_type, force=False, test=None):
"""Send message to pushover"""
if test:
@@ -260,8 +275,8 @@ def send_pushover(title, msg, gtype, force=False, test=None):
if not apikey or not userkey:
return T("Cannot send, missing required data")
title = T(NOTIFICATION.get(gtype, "other"))
prio = get_prio(gtype, "pushover")
title = T(NOTIFICATION_TYPES.get(notification_type, "other"))
prio = get_prio(notification_type, "pushover")
if force:
prio = 1
@@ -311,7 +326,7 @@ def do_send_pushover(body):
return T("Failed to send pushover message")
def send_pushbullet(title, msg, gtype, force=False, test=None):
def send_pushbullet(title, msg, notification_type, force=False, test=None):
"""Send message to Pushbullet"""
if test:
@@ -323,7 +338,7 @@ def send_pushbullet(title, msg, gtype, force=False, test=None):
if not apikey:
return T("Cannot send, missing required data")
title = "SABnzbd: " + T(NOTIFICATION.get(gtype, "other"))
title = "SABnzbd: " + T(NOTIFICATION_TYPES.get(notification_type, "other"))
try:
conn = http.client.HTTPSConnection("api.pushbullet.com:443")
@@ -346,7 +361,7 @@ def send_pushbullet(title, msg, gtype, force=False, test=None):
return ""
def send_nscript(title, msg, gtype, force=False, test=None):
def send_nscript(title, msg, notification_type, force=False, test=None):
"""Run user's notification script"""
if test:
script = test.get("nscript_script")
@@ -357,15 +372,23 @@ def send_nscript(title, msg, gtype, force=False, test=None):
if not script:
return T("Cannot send, missing required data")
title = "SABnzbd: " + T(NOTIFICATION.get(gtype, "other"))
title = "SABnzbd: " + T(NOTIFICATION_TYPES.get(notification_type, "other"))
if force or check_classes(gtype, "nscript"):
if force or check_classes(notification_type, "nscript"):
script_path = make_script_path(script)
if script_path:
ret = -1
output = None
try:
p = build_and_run_command([script_path, gtype, title, msg], env=create_env(extra_env_fields=env_params))
p = build_and_run_command(
[
script_path,
notification_type,
title,
msg,
],
env=create_env(extra_env_fields=env_params),
)
output = p.stdout.read()
ret = p.wait()
except:
@@ -382,12 +405,22 @@ def send_nscript(title, msg, gtype, force=False, test=None):
return ""
def send_windows(title, msg, gtype):
if sabnzbd.WINTRAY and not sabnzbd.WINTRAY.terminate:
try:
def send_windows(title: str, msg: str, notification_type: str, actions: Optional[Dict[str, str]] = None):
try:
if _HAVE_WINDOWS_TOASTER:
notification_sender = InteractableWindowsToaster("SABnzbd", notifierAUMID="SABnzbd")
toast_notification = Toast([title, msg], group=notification_type, launch_action=sabnzbd.BROWSER_URL)
# Add any buttons
if actions:
for action in actions:
toast_notification.AddAction(ToastButton(NOTIFICATION_ACTIONS[action], launch=actions[action]))
notification_sender.show_toast(toast_notification)
elif sabnzbd.WINTRAY and not sabnzbd.WINTRAY.terminate:
sabnzbd.WINTRAY.sendnotification(title, msg)
except:
logging.info(T("Failed to send Windows notification"))
logging.debug("Traceback: ", exc_info=True)
return T("Failed to send Windows notification")
except:
logging.info(T("Failed to send Windows notification"))
logging.debug("Traceback: ", exc_info=True)
return T("Failed to send Windows notification")
return None

View File

@@ -214,20 +214,20 @@ def process_nzb_archive_file(
cat=cat,
url=url,
priority=priority,
password=password,
nzbname=nzbname,
nzo_info=nzo_info,
reuse=reuse,
nzo_id=nzo_id,
dup_check=dup_check,
)
if not nzo.password:
nzo.password = password
except (sabnzbd.nzbstuff.NzbEmpty, sabnzbd.nzbstuff.NzbRejected):
# Empty or fully rejected
pass
except sabnzbd.nzbstuff.NzbRejectedToHistory as err:
# Duplicate or unwanted extension that was failed to history
nzo_ids.append(err.nzo_id)
except sabnzbd.nzbstuff.NzbRejectToHistory as err:
# Duplicate or unwanted extension directed to history
sabnzbd.NzbQueue.fail_to_history(err.nzo)
nzo_ids.append(err.nzo.nzo_id)
except:
# Something else is wrong, show error
logging.error(T("Error while adding %s, removing"), name, exc_info=True)
@@ -321,23 +321,23 @@ def process_single_nzb(
cat=cat,
url=url,
priority=priority,
password=password,
nzbname=nzbname,
nzo_info=nzo_info,
reuse=reuse,
nzo_id=nzo_id,
dup_check=dup_check,
)
if not nzo.password:
nzo.password = password
except sabnzbd.nzbstuff.NzbEmpty:
# Malformed or might not be an NZB file
result = AddNzbFileResult.NO_FILES_FOUND
except sabnzbd.nzbstuff.NzbRejected:
# Rejected as duplicate or by pre-queue script
result = AddNzbFileResult.ERROR
except sabnzbd.nzbstuff.NzbRejectedToHistory as err:
# Duplicate or unwanted extension that was failed to history
nzo_ids.append(err.nzo_id)
except sabnzbd.nzbstuff.NzbRejectToHistory as err:
# Duplicate or unwanted extension directed to history
sabnzbd.NzbQueue.fail_to_history(err.nzo)
nzo_ids.append(err.nzo.nzo_id)
except:
# Something else is wrong, show error
logging.error(T("Error while adding %s, removing"), filename, exc_info=True)
@@ -422,7 +422,7 @@ def nzbfile_parser(full_nzb_path: str, nzo):
# Get segments
raw_article_db = {}
file_bytes = 0
if element.find("segments"):
if len(element.find("segments")):
for segment in element.find("segments").iter("segment"):
try:
article_id = segment.text

View File

@@ -27,7 +27,7 @@ from typing import List, Dict, Union, Tuple, Optional
import sabnzbd
from sabnzbd.nzbstuff import NzbObject, Article
from sabnzbd.misc import exit_sab, cat_to_opts, int_conv, caller_name, safe_lower
from sabnzbd.misc import exit_sab, cat_to_opts, int_conv, caller_name, safe_lower, duplicate_warning
from sabnzbd.filesystem import get_admin_path, remove_all, globber_full, remove_file, is_valid_script
from sabnzbd.nzbparser import process_single_nzb
from sabnzbd.panic import panic_queue
@@ -37,7 +37,6 @@ from sabnzbd.constants import (
QUEUE_VERSION,
FUTURE_Q_FOLDER,
JOB_ADMIN,
DEFAULT_PRIORITY,
LOW_PRIORITY,
HIGH_PRIORITY,
FORCE_PRIORITY,
@@ -45,6 +44,7 @@ from sabnzbd.constants import (
VERIFIED_FILE,
Status,
IGNORED_FILES_AND_FOLDERS,
DuplicateStatus,
)
import sabnzbd.cfg as cfg
@@ -189,8 +189,7 @@ class NzbQueue:
else:
try:
logging.debug("Repair job %s without stored NZB", name)
nzo = NzbObject(name, nzbname=name, reuse=repair_folder)
nzo.password = password
nzo = NzbObject(name, password=password, nzbname=name, reuse=repair_folder)
self.add(nzo)
nzo_ids = [nzo.nzo_id]
except:
@@ -247,25 +246,6 @@ class NzbQueue:
def set_top_only(self, value):
self.__top_only = value
def generate_future(
self, msg, pp=None, script=None, cat=None, url=None, priority=DEFAULT_PRIORITY, nzbname=None
) -> NzbObject:
"""Create and return a placeholder nzo object"""
logging.debug("Creating placeholder NZO")
future_nzo = NzbObject(
filename=msg,
pp=pp,
script=script,
futuretype=True,
cat=cat,
url=url,
priority=priority,
nzbname=nzbname,
status=Status.GRABBING,
)
self.add(future_nzo)
return future_nzo
def change_opts(self, nzo_ids: str, pp: int) -> int:
result = 0
for nzo_id in [item.strip() for item in nzo_ids.split(",")]:
@@ -380,7 +360,7 @@ class NzbQueue:
return nzo.nzo_id
@NzbQueueLocker
def remove(self, nzo_id: str, cleanup: bool = True, delete_all_data: bool = True) -> Optional[str]:
def remove(self, nzo_id: str, cleanup: bool = True, delete_all_data: bool = True) -> Optional[NzbObject]:
"""Remove NZO from queue.
It can be added to history directly.
Or, we do some clean-up, sometimes leaving some data.
@@ -396,18 +376,21 @@ class NzbQueue:
nzo.status = Status.DELETED
nzo.purge_data(delete_all_data=delete_all_data)
self.save(False)
return nzo_id
return None
return nzo
@NzbQueueLocker
def remove_multiple(self, nzo_ids: List[str], delete_all_data=True) -> List[str]:
"""Remove multiple jobs from the queue. Also triggers duplicate handling
and downloader-disconnect, so intended for external use only!"""
removed = []
for nzo_id in nzo_ids:
if self.remove(nzo_id, delete_all_data=delete_all_data):
if nzo := self.remove(nzo_id, delete_all_data=delete_all_data):
removed.append(nzo_id)
# Start an alternative, if available
self.handle_duplicate_alternatives(nzo, success=False)
# Any files left? Otherwise let's disconnect
if self.actives(grabs=False) == 0 and cfg.autodisconnect():
if not self.actives(grabs=False) and cfg.autodisconnect():
# This was the last job, close server connections
sabnzbd.Downloader.disconnect()
@@ -713,15 +696,13 @@ class NzbQueue:
"""Get next article for jobs in the queue
Not locked for performance, since it only reads the queue
"""
# Pre-calculate propagation delay
propagation_delay = float(cfg.propagation_delay() * 60)
for nzo in self.__nzo_list:
# Not when queue paused, individually paused, or when waiting for propagation
# Force items will always download
if (
not sabnzbd.Downloader.paused
and nzo.status not in (Status.PAUSED, Status.GRABBING)
and (not propagation_delay or (nzo.avg_stamp + propagation_delay) < time.time())
and not nzo.propagation_delay_left
) or nzo.priority == FORCE_PRIORITY:
if not nzo.server_in_try_list(server):
if articles := nzo.get_articles(server, servers, fetch_limit):
@@ -799,6 +780,13 @@ class NzbQueue:
pass
sabnzbd.Assembler.process(nzo)
def fail_to_history(self, nzo: NzbObject):
"""Fail to history, with all the steps in between"""
if not nzo.nzo_id:
self.add(nzo, quiet=True)
self.remove(nzo.nzo_id, cleanup=False)
sabnzbd.PostProcessor.process(nzo)
def actives(self, grabs: bool = True) -> int:
"""Return amount of non-paused jobs, optionally with 'grabbing' items
Not locked for performance, only reads the queue
@@ -817,12 +805,12 @@ class NzbQueue:
search: Optional[str] = None,
categories: Optional[List[str]] = None,
priorities: Optional[List[str]] = None,
statuses: Optional[List[str]] = None,
nzo_ids: Optional[List[str]] = None,
start: int = 0,
limit: int = 0,
) -> Tuple[int, int, int, List[NzbObject], int, int]:
"""Return list of queued jobs,
optionally filtered by 'search' and 'nzo_ids', and limited by start and limit.
"""Return list of queued jobs, optionally filtered and limited by start and limit.
Not locked for performance, only reads the queue
"""
if search:
@@ -851,6 +839,10 @@ class NzbQueue:
continue
if priorities and nzo.priority not in priorities:
continue
if statuses and nzo.status not in statuses:
# Propagation status is set only by the API-code, so has to be filtered specially
if not (Status.PROPAGATING in statuses and nzo.propagation_delay_left):
continue
if nzo_ids and nzo.nzo_id not in nzo_ids:
continue
@@ -873,12 +865,10 @@ class NzbQueue:
return bytes_left
def is_empty(self) -> bool:
empty = True
for nzo in self.__nzo_list:
if not nzo.futuretype and nzo.status != Status.PAUSED:
empty = False
break
return empty
return False
return True
def stop_idle_jobs(self):
"""Detect jobs that have zero files left and send them to post processing"""
@@ -956,5 +946,79 @@ class NzbQueue:
lst.append((url, nzo))
return lst
@NzbQueueLocker
def have_name_or_md5sum(self, name: str, md5sum: str) -> bool:
"""Check whether this name or md5sum is already
in the queue or the post-processing queue"""
lname = name.lower()
for nzo in self.__nzo_list + sabnzbd.PostProcessor.get_queue():
# Skip any jobs already marked as duplicate, to prevent double-triggers
# URL's do not have an MD5!
if not nzo.duplicate and (
nzo.final_name.lower() == lname or (nzo.md5sum and md5sum and nzo.md5sum == md5sum)
):
return True
return False
@NzbQueueLocker
def have_duplicate_key(self, duplicate_key: str) -> bool:
"""Check whether this duplicate key is already
in the queue or the post-processing queue"""
for nzo in self.__nzo_list + sabnzbd.PostProcessor.get_queue():
# Skip any jobs already marked as duplicate, to prevent double-triggers
if not nzo.duplicate and nzo.duplicate_key == duplicate_key:
return True
return False
@NzbQueueLocker
def handle_duplicate_alternatives(self, finished_nzo: NzbObject, success: bool):
"""Remove matching duplicates if the first job succeeded,
or start the next alternative if the job failed"""
if not cfg.no_dupes() and not cfg.no_smart_dupes():
return
# Unfortunately we need a copy, since we might remove items from the list
for nzo in self.__nzo_list[:]:
if not nzo.duplicate:
continue
# URL's do not have an MD5!
if (
nzo.final_name.lower() == finished_nzo.final_name.lower()
or (nzo.md5sum and finished_nzo.md5sum and nzo.md5sum == finished_nzo.md5sum)
) or (nzo.duplicate_key and finished_nzo.duplicate_key and nzo.duplicate_key == finished_nzo.duplicate_key):
# Start the next alternative
if not success:
# Don't just resume if only set to tag
if (nzo.duplicate == DuplicateStatus.DUPLICATE_ALTERNATIVE and cfg.no_dupes() != 4) or (
nzo.duplicate == DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE and cfg.no_smart_dupes() != 4
):
logging.info("Resuming duplicate alternative %s for ", nzo.final_name, finished_nzo.final_name)
nzo.resume()
nzo.duplicate = None
return
# Take action on the alternatives to the duplicate
# 1 = Discard
# 2 = Pause
# 3 = Fail (move to History)
# 4 = Tag
smart_duplicate = nzo.duplicate == DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE
if (not smart_duplicate and cfg.no_dupes() == 1) or (smart_duplicate and cfg.no_smart_dupes() == 1):
duplicate_warning(T('Ignoring duplicate NZB "%s"'), nzo.final_name)
self.remove(nzo.nzo_id)
elif (not smart_duplicate and cfg.no_dupes() == 3) or (smart_duplicate and cfg.no_smart_dupes() == 3):
duplicate_warning(T('Failing duplicate NZB "%s"'), nzo.final_name)
nzo.fail_msg = T("Duplicate NZB")
self.fail_to_history(nzo)
else:
# Action set to Pause or Tag, so only adjust the label on the first matching job
logging.info("Re-tagging duplicate alternative %s for %s", nzo.final_name, finished_nzo.final_name)
if nzo.duplicate == DuplicateStatus.DUPLICATE_ALTERNATIVE:
nzo.duplicate = DuplicateStatus.DUPLICATE
else:
nzo.duplicate = DuplicateStatus.SMART_DUPLICATE
return
def __repr__(self):
return "<NzbQueue>"

View File

@@ -42,11 +42,11 @@ from sabnzbd.constants import (
LOW_PRIORITY,
DEFAULT_PRIORITY,
PAUSED_PRIORITY,
DUP_PRIORITY,
STOP_PRIORITY,
RENAMES_FILE,
MAX_BAD_ARTICLES,
Status,
DuplicateStatus,
)
from sabnzbd.misc import (
to_units,
@@ -59,6 +59,7 @@ from sabnzbd.misc import (
caller_name,
opts_to_pp,
pp_to_opts,
duplicate_warning,
)
from sabnzbd.filesystem import (
sanitize_foldername,
@@ -79,6 +80,14 @@ from sabnzbd.filesystem import (
is_valid_script,
has_unwanted_extension,
create_all_dirs,
get_basename,
backup_exists,
get_new_id,
save_data,
load_data,
save_compressed,
backup_nzb,
remove_data,
)
from sabnzbd.par2file import FilePar2Info
from sabnzbd.decorators import synchronized
@@ -228,7 +237,7 @@ class Article(TryList):
def get_art_id(self):
"""Return unique article storage name, create if needed"""
if not self.art_id:
self.art_id = sabnzbd.filesystem.get_new_id("article", self.nzf.nzo.admin_path)
self.art_id = get_new_id("article", self.nzf.nzo.admin_path)
return self.art_id
def search_new_server(self):
@@ -342,7 +351,7 @@ class NzbFile(TryList):
self.bytes_left: int = file_bytes
self.nzo: NzbObject = nzo
self.nzf_id: str = sabnzbd.filesystem.get_new_id("nzf", nzo.admin_path)
self.nzf_id: str = get_new_id("nzf", nzo.admin_path)
self.deleted = False
self.import_finished = False
@@ -366,7 +375,7 @@ class NzbFile(TryList):
# Any articles left?
if raw_article_db:
# Save the rest
sabnzbd.filesystem.save_data(raw_article_db, self.nzf_id, nzo.admin_path)
save_data(raw_article_db, self.nzf_id, nzo.admin_path)
else:
# All imported
self.import_finished = True
@@ -374,8 +383,7 @@ class NzbFile(TryList):
def finish_import(self):
"""Load the article objects from disk"""
logging.debug("Finishing import on %s", self.filename)
raw_article_db = sabnzbd.filesystem.load_data(self.nzf_id, self.nzo.admin_path, remove=False)
if raw_article_db:
if raw_article_db := load_data(self.nzf_id, self.nzo.admin_path, remove=False):
for raw_article in raw_article_db:
self.add_article(raw_article)
@@ -505,9 +513,10 @@ class NzbRejected(Exception):
pass
class NzbRejectedToHistory(Exception):
def __init__(self, nzo_id: str):
self.nzo_id = nzo_id
class NzbRejectToHistory(Exception):
def __init__(self, nzo, fail_msg):
self.nzo: NzbObject = nzo
self.nzo.fail_msg = fail_msg
super().__init__()
@@ -528,6 +537,7 @@ NzbObjectSaver = (
"url",
"groups",
"avg_date",
"propagation_delay",
"md5of16k",
"extrapars",
"par2packs",
@@ -554,6 +564,7 @@ NzbObjectSaver = (
"encrypted",
"bad_articles",
"duplicate",
"duplicate_key",
"oversized",
"precheck",
"incomplete",
@@ -585,6 +596,7 @@ class NzbObject(TryList):
cat: Optional[str] = None,
url: Optional[str] = None,
priority: Optional[Union[int, str]] = DEFAULT_PRIORITY,
password: Optional[str] = None,
nzbname: Optional[str] = None,
status: str = Status.QUEUED,
nzo_info: Optional[Dict[str, Any]] = None,
@@ -593,30 +605,29 @@ class NzbObject(TryList):
dup_check: bool = True,
):
super().__init__()
# Use original filename as basis
self.work_name = self.filename = filename
self.filename = filename # Original filename
if nzbname and nzb_fp:
self.work_name = nzbname # Use nzbname if set and only for non-future slot
else:
self.work_name = filename
# User defined job name
if nzbname:
self.final_name = self.work_name = nzbname
# For future-slots we keep the name given by URLGrabber
if nzb_fp is None:
self.final_name = self.work_name = filename
else:
# Remove trailing .nzb and .par(2)
self.work_name = create_work_name(self.work_name)
# Extract password if not explicitly set, also on URL-fetches which might have a custom name with password
self.password = password
if not self.password:
# Extract before create_work_name, as it would escape the "/" on Windows
self.work_name, self.password = scan_password(self.work_name)
# Extract password
self.work_name, self.password = scan_password(self.work_name)
if not self.work_name:
# In case only /password was entered for nzbname
self.work_name = filename
# Check for password also in filename
if not self.password:
_, self.password = scan_password(get_basename(filename))
# Remove trailing .nzb/.par(2) and sanitize
self.work_name = create_work_name(self.work_name)
self.final_name = self.work_name
# Check for password also in filename
if not self.password:
_, self.password = scan_password(os.path.splitext(filename)[0])
# Temporary store for custom job name for after URL-fetching
self.custom_name = nzbname
# Create a record of the input for pp, script, and priority
input_pp = pp
@@ -645,6 +656,7 @@ class NzbObject(TryList):
self.groups = []
self.avg_date = datetime.datetime(1970, 1, 1, 1, 0)
self.avg_stamp = 0.0 # Avg age in seconds (calculated from avg_age)
self.propagation_delay: Optional[float] = None # Set during parsing
self.correct_password: Optional[str] = None
# Bookkeeping values
@@ -671,19 +683,21 @@ class NzbObject(TryList):
# The current status of the nzo eg:
# Queued, Downloading, Repairing, Unpacking, Failed, Complete
self.status: str = status
self.avg_bps_freq = 0
self.avg_bps_total = 0
self.first_articles: List[Article] = []
self.first_articles_count = 0
self.saved_articles: Set[Article] = set()
self.nzo_id: Optional[str] = None
self.duplicate: Optional[str] = None
self.duplicate_key: Optional[str] = None
self.futuretype = futuretype
self.removed_from_queue = False
self.to_be_removed = False
self.duplicate = False
self.oversized = False
self.precheck = False
self.incomplete = False
@@ -703,9 +717,6 @@ class NzbObject(TryList):
# Stores various info about the nzo to be
self.nzo_info: Dict[str, Any] = nzo_info or {}
# Temporary store for custom foldername - needs to be stored because of url fetching
self.custom_name = nzbname
self.next_save = None
self.save_timeout = None
self.encrypted = 0
@@ -717,9 +728,14 @@ class NzbObject(TryList):
# Path is empty in case of a future NZB
self.download_path = ""
# This is a slot for a future NZB, ready now
# It can also be a retry of a failed job with no extra NZB-file
if nzb_fp is None and not reuse:
# This is a slot for a future NZB, ready now
# It can also be a retry of a failed job with no extra NZB-file
# For future NZB, check if we don't already have this in the queue or history
# based on the custom name supplied by the user or the RSS feed
if self.custom_name and dup_check:
self.duplicate_check()
self.handle_duplicate_action()
return
# Re-use existing nzo_id, when a "future" job gets it payload
@@ -727,9 +743,6 @@ class NzbObject(TryList):
self.nzo_id = nzo_id
sabnzbd.NzbQueue.remove(nzo_id, delete_all_data=False)
# To be updated later if it's a duplicate
duplicate = series_duplicate = False
# Apply conversion option to final folder
if cfg.replace_spaces():
logging.info("Replacing spaces with underscores in %s", self.final_name)
@@ -765,7 +778,7 @@ class NzbObject(TryList):
remove_all(admin_dir, "SABnzbd_article_*", keep_folder=True)
if nzb_fp:
full_nzb_path = sabnzbd.filesystem.save_compressed(admin_dir, filename, nzb_fp)
full_nzb_path = save_compressed(admin_dir, filename, nzb_fp)
try:
sabnzbd.nzbparser.nzbfile_parser(full_nzb_path, self)
except Exception as err:
@@ -783,11 +796,11 @@ class NzbObject(TryList):
# Check against identical checksum or series/season/episode if not repair
# Have to check for duplicate before saving the backup, as it will
# trigger the duplicate-detection based on the backup
if not reuse and dup_check and self.priority != REPAIR_PRIORITY:
duplicate, series_duplicate = self.has_duplicates()
if not reuse and dup_check and not self.duplicate and self.priority != REPAIR_PRIORITY:
self.duplicate_check()
# Copy to backup
sabnzbd.filesystem.backup_nzb(full_nzb_path)
backup_nzb(full_nzb_path)
if not self.files and not reuse:
self.purge_data()
@@ -821,20 +834,24 @@ class NzbObject(TryList):
if not self.password and self.meta.get("password"):
self.password = self.meta.get("password", [None])[0]
# Check if we expect propagation delay
if (propagation_delay := self.avg_stamp + float(cfg.propagation_delay() * 60)) > time.time():
self.propagation_delay = propagation_delay
# Run user pre-queue script if set and valid
if not reuse and make_script_path(cfg.pre_script()):
# Call the script
accept, name, pp, cat_pp, script_pp, priority, group = sabnzbd.newsunpack.pre_queue(self, pp, cat)
accept, name, pq_pp, pq_cat, pq_script, pq_priority, pq_group = sabnzbd.newsunpack.pre_queue(self, pp, cat)
if cat_pp:
if pq_cat:
# An explicit pp/script/priority set upon adding the job takes precedence
# over an implicit setting based on the category set by pre-queue
if input_priority and not priority:
priority = input_priority
if input_pp and not pp:
pp = input_pp
if input_script and not script_pp:
script_pp = input_script
if input_priority and not pq_priority:
pq_priority = input_priority
if input_pp and not pq_pp:
pq_pp = input_pp
if input_script and not pq_script:
pq_script = input_script
# Accept or reject
accept = int_conv(accept)
@@ -842,34 +859,33 @@ class NzbObject(TryList):
self.purge_data()
raise NzbRejected
if accept == 2:
self.fail_msg = T("Pre-queue script marked job as failed")
raise NzbRejectToHistory(self, T("Pre-queue script marked job as failed"))
# Process all options, only over-write if set by script
# Beware that cannot do "if priority/pp", because those can
# also have a valid value of 0, which shouldn't be ignored
if name:
self.set_final_name_and_scan_password(name)
self.duplicate_check(repeat=True)
try:
pp = int(pp)
pp = int(pq_pp)
except:
pp = None
if cat_pp:
cat = cat_pp
if pq_cat:
cat = pq_cat
try:
priority = int(priority)
priority = int(pq_priority)
except:
priority = DEFAULT_PRIORITY
if script_pp and is_valid_script(script_pp):
script = script_pp
if group:
self.groups = [str(group)]
if pq_script and is_valid_script(pq_script):
script = pq_script
if pq_group:
self.groups = [str(pq_group)]
# Re-evaluate results from pre-queue script
self.cat, pp, self.script, priority = cat_to_opts(cat, pp, script, priority)
self.set_priority(priority)
self.repair, self.unpack, self.delete = pp_to_opts(pp)
else:
accept = 1
# Pause if requested by the NZB-adding or the pre-queue script
if self.priority == PAUSED_PRIORITY:
@@ -884,57 +900,22 @@ class NzbObject(TryList):
self.oversized = True
self.priority = LOW_PRIORITY
# If the job is forced in any way, skip duplicate check
if self.priority == FORCE_PRIORITY:
duplicate = series_duplicate = False
# Handle duplicates
if duplicate and (
(not series_duplicate and cfg.no_dupes() == 1) or (series_duplicate and cfg.no_series_dupes() == 1)
):
if cfg.warn_dupl_jobs():
logging.warning(T('Ignoring duplicate NZB "%s"'), filename)
self.purge_data()
raise NzbRejected
if duplicate and (
(not series_duplicate and cfg.no_dupes() == 3) or (series_duplicate and cfg.no_series_dupes() == 3)
):
if cfg.warn_dupl_jobs():
logging.warning(T('Failing duplicate NZB "%s"'), filename)
# Move to history, utilizing the same code as accept&fail from pre-queue script
self.fail_msg = T("Duplicate NZB")
accept = 2
duplicate = False
if duplicate or self.priority == DUP_PRIORITY:
self.duplicate = True
if cfg.no_dupes() == 4 or cfg.no_series_dupes() == 4:
if cfg.warn_dupl_jobs():
logging.warning('%s: "%s"', T("Duplicate NZB"), filename)
else:
if cfg.warn_dupl_jobs():
logging.warning(T('Pausing duplicate NZB "%s"'), filename)
self.pause()
# Only change priority if it's currently set to duplicate, otherwise keep original one
if self.priority == DUP_PRIORITY:
self.set_stateless_priority(self.cat)
# Take action on the duplicate status
self.handle_duplicate_action()
# Check if there is any unwanted extension in plain sight in the NZB itself
for nzf in self.files:
if cfg.action_on_unwanted_extensions() and has_unwanted_extension(nzf.filename):
# ... we found an unwanted extension
logging.warning(T("Unwanted Extension in file %s (%s)"), nzf.filename, self.final_name)
# Pause, or Abort:
if cfg.action_on_unwanted_extensions() == 1:
logging.debug("Unwanted extension ... pausing")
self.unwanted_ext = 1
self.pause()
if cfg.action_on_unwanted_extensions() == 2:
logging.debug("Unwanted extension ... aborting")
self.fail_msg = T("Aborted, unwanted extension detected")
accept = 2
if cfg.action_on_unwanted_extensions():
for nzf in self.files:
if has_unwanted_extension(nzf.filename):
logging.warning(T("Unwanted Extension in file %s (%s)"), nzf.filename, self.final_name)
# Pause, or Abort:
if cfg.action_on_unwanted_extensions() == 1:
logging.debug("Unwanted extension ... pausing")
self.unwanted_ext = 1
self.pause()
if cfg.action_on_unwanted_extensions() == 2:
logging.debug("Unwanted extension ... aborting")
raise NzbRejectToHistory(self, T("Aborted, unwanted extension detected"))
if reuse:
self.check_existing_files(self.download_path)
@@ -951,14 +932,6 @@ class NzbObject(TryList):
# Set nzo save-delay to minimum 120 seconds
self.save_timeout = max(120, min(6.0 * self.bytes / GIGI, 300.0))
# In case pre-queue script or duplicate check want to move
# to history we first need a nzo_id by entering the NzbQueue
if accept == 2:
sabnzbd.NzbQueue.add(self, quiet=True)
sabnzbd.NzbQueue.end_job(self)
# Raise error, so it's not added
raise NzbRejectedToHistory(nzo_id=self.nzo_id)
def update_download_stats(self, bps, serverid, bytes_received):
if bps:
self.avg_bps_total += bps / 1024
@@ -1255,7 +1228,7 @@ class NzbObject(TryList):
existing_files = globber(wdir, "*.*")
# Substitute renamed files
if renames := sabnzbd.filesystem.load_data(RENAMES_FILE, self.admin_path, remove=True):
if renames := load_data(RENAMES_FILE, self.admin_path, remove=True):
for name in renames:
if name in existing_files or renames[name] in existing_files:
if name in existing_files:
@@ -1325,6 +1298,17 @@ class NzbObject(TryList):
else:
return opts_to_pp(self.repair, self.unpack, self.delete)
@property
def propagation_delay_left(self) -> int:
"""Returns number of propagation minutes remaining, if any.
It could return seconds, but the numerical value is only used in the queue."""
if self.propagation_delay:
if (time_left := self.propagation_delay - time.time()) > 0:
return int(time_left / 60 + 0.5)
# We can remove the value, to skip any further calculations
self.propagation_delay = None
return 0
def set_pp(self, value: int):
self.repair, self.unpack, self.delete = pp_to_opts(value)
logging.info("Set pp=%s for job %s", value, self.final_name)
@@ -1349,7 +1333,6 @@ class NzbObject(TryList):
LOW_PRIORITY,
DEFAULT_PRIORITY,
PAUSED_PRIORITY,
DUP_PRIORITY,
STOP_PRIORITY,
):
self.priority = value
@@ -1369,7 +1352,7 @@ class NzbObject(TryList):
for cat in cat_options:
prio = cat_to_opts(cat)[3]
if prio not in (DUP_PRIORITY, PAUSED_PRIORITY, FORCE_PRIORITY):
if prio not in (PAUSED_PRIORITY, FORCE_PRIORITY):
self.priority = prio
break
else:
@@ -1379,8 +1362,13 @@ class NzbObject(TryList):
def labels(self):
"""Return (translated) labels of job"""
labels = []
if self.duplicate:
if self.duplicate in (DuplicateStatus.DUPLICATE, DuplicateStatus.SMART_DUPLICATE):
labels.append(T("DUPLICATE"))
if self.duplicate in (
DuplicateStatus.DUPLICATE_ALTERNATIVE,
DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE,
):
labels.append(T("ALTERNATIVE"))
if self.encrypted > 0:
labels.append(T("ENCRYPTED"))
if self.oversized:
@@ -1397,10 +1385,8 @@ class NzbObject(TryList):
labels.append(T("WAIT %s sec") % dif)
# Propagation delay label
propagation_delay = float(cfg.propagation_delay() * 60)
if propagation_delay and self.avg_stamp + propagation_delay > time.time() and self.priority != FORCE_PRIORITY:
wait_time = int((self.avg_stamp + propagation_delay - time.time()) / 60 + 0.5)
labels.append(T("PROPAGATING %s min") % wait_time) # Queue indicator while waiting for propagation of post
if self.propagation_delay_left and self.priority != FORCE_PRIORITY:
labels.append(T("PROPAGATING %s min") % self.propagation_delay_left) # Queue indicator: propagation of post
return labels
@@ -1446,7 +1432,7 @@ class NzbObject(TryList):
# If user resumes after encryption warning, no more auto-pauses
self.encrypted = 2
# If user resumes after warning, reset duplicate/oversized/incomplete/unwanted indicators
self.duplicate = False
self.duplicate = None
self.oversized = False
self.incomplete = False
if self.unwanted_ext:
@@ -1506,7 +1492,8 @@ class NzbObject(TryList):
def abort_direct_unpacker(self):
"""Abort any running DirectUnpackers"""
if self.direct_unpacker:
# During nzo creation the property doesn't exist yet
if hasattr(self, "direct_unpacker") and self.direct_unpacker:
self.direct_unpacker.abort()
def check_availability_ratio(self):
@@ -1597,6 +1584,10 @@ class NzbObject(TryList):
if dups:
download_msgs.append(T("%s articles had non-matching duplicates") % dups)
self.set_unpack_info("Download", "<br/>".join(download_msgs), unique=True)
# Add RSS source
if rss_feed := self.nzo_info.get("RSS"):
self.set_unpack_info("RSS", rss_feed, unique=True)
self.set_unpack_info("Source", self.url or self.filename, unique=True)
@synchronized(NZO_LOCK)
@@ -1823,14 +1814,14 @@ class NzbObject(TryList):
# Delete all, or just basic files
if self.futuretype:
# Remove temporary file left from URL-fetches
sabnzbd.filesystem.remove_data(self.nzo_id, self.admin_path)
remove_data(self.nzo_id, self.admin_path)
elif delete_all_data:
remove_all(self.download_path, recursive=True)
else:
# We remove any saved articles and save the renames file
remove_all(self.download_path, "SABnzbd_nz?_*", keep_folder=True)
remove_all(self.download_path, "SABnzbd_article_*", keep_folder=True)
sabnzbd.filesystem.save_data(self.renames, RENAMES_FILE, self.admin_path, silent=True)
save_data(self.renames, RENAMES_FILE, self.admin_path, silent=True)
def get_nzf_by_id(self, nzf_id: str) -> NzbFile:
if nzf_id in self.files_table:
@@ -1869,7 +1860,7 @@ class NzbObject(TryList):
"""Save job's admin to disk"""
self.save_attribs()
if self.nzo_id and not self.removed_from_queue:
sabnzbd.filesystem.save_data(self, self.nzo_id, self.admin_path)
save_data(self, self.nzo_id, self.admin_path)
def save_attribs(self):
"""Save specific attributes for Retry"""
@@ -1877,11 +1868,11 @@ class NzbObject(TryList):
for attrib in NzoAttributeSaver:
attribs[attrib] = getattr(self, attrib)
logging.debug("Saving attributes %s for %s", attribs, self.final_name)
sabnzbd.filesystem.save_data(attribs, ATTRIB_FILE, self.admin_path, silent=True)
save_data(attribs, ATTRIB_FILE, self.admin_path, silent=True)
def load_attribs(self) -> Tuple[Optional[str], Optional[int], Optional[str]]:
"""Load saved attributes and return them to be parsed"""
attribs = sabnzbd.filesystem.load_data(ATTRIB_FILE, self.admin_path, remove=False)
attribs = load_data(ATTRIB_FILE, self.admin_path, remove=False)
logging.debug("Loaded attributes %s for %s", attribs, self.final_name)
# If attributes file somehow does not exist
@@ -1917,56 +1908,121 @@ class NzbObject(TryList):
else:
nzf_ids.remove(nzf_id)
def has_duplicates(self) -> Tuple[bool, bool]:
"""Return (res, series)
where "res" is True when this is a duplicate
where "series" is True when this is an episode
"""
def set_duplicate_key(self):
"""Shorthand to set the key once"""
if not self.duplicate_key:
show_analysis = sabnzbd.sorting.BasicAnalyzer(self.final_name)
no_dupes = cfg.no_dupes()
no_series_dupes = cfg.no_series_dupes()
series_propercheck = cfg.series_propercheck()
# We can only set a duplicate key for these types
if show_analysis.type not in ("tv", "movie", "date"):
return
# Abort if dupe check is off for both nzb and series
if not no_dupes and not no_series_dupes:
return False, False
# The key always includes the title, for movies we don't add anything else
duplicate_key_items = [show_analysis.info.get("title", "")]
if show_analysis.type == "tv":
# For TV-shows we add the season and episode
duplicate_key_items.append(str(show_analysis.info.get("season_num", "")))
duplicate_key_items.append(str(show_analysis.info.get("episode_num", "")))
elif show_analysis.type == "date":
# Add date
duplicate_key_items.append(str(show_analysis.info.get("year", "")))
duplicate_key_items.append(str(show_analysis.info.get("month", "")))
duplicate_key_items.append(str(show_analysis.info.get("day", "")))
series = False
res = False
# We allow 1 proper result to bypass the detection, if desired
if show_analysis.is_proper() and cfg.dupes_propercheck():
duplicate_key_items.append("proper")
self.duplicate_key = "/".join(duplicate_key_items).lower()
def duplicate_check(self, repeat: bool = False):
"""Set the correct duplicate status"""
if not cfg.no_dupes() and not cfg.no_smart_dupes():
return
# Reset status in case of a repeat analysis
if repeat:
self.duplicate = None
self.duplicate_key = None
duplicate_in_history = smart_duplicate_in_history = False
duplicate_in_queue = smart_duplicate_in_queue = False
with HistoryDB() as history_db:
# Dupe check off nzb contents
if no_dupes:
res = history_db.have_name_or_md5sum(self.final_name, self.md5sum)
logging.debug(
"Duplicate checked NZB in history: filename=%s, md5sum=%s, result=%s",
self.filename,
self.md5sum,
res,
)
if not res and cfg.backup_for_duplicates():
res = sabnzbd.filesystem.backup_exists(self.filename)
logging.debug("Duplicate checked NZB against backup: filename=%s, result=%s", self.filename, res)
# Dupe check off just name or nzb contents
if cfg.no_dupes():
logging.debug("Duplicate checking NZB %s (md5sum=%s)", self.final_name, self.md5sum)
duplicate_in_history = history_db.have_name_or_md5sum(self.final_name, self.md5sum)
logging.debug("Duplicate in history: %s", duplicate_in_history)
duplicate_in_queue = sabnzbd.NzbQueue.have_name_or_md5sum(self.final_name, self.md5sum)
logging.debug("Duplicate in queue: %s", duplicate_in_queue)
# The nzb can already be in the backup while the job is still in the queue, so skip on repeat
if not repeat and not duplicate_in_history and not duplicate_in_queue and cfg.backup_for_duplicates():
duplicate_in_history = backup_exists(self.filename)
logging.debug("Duplicate in backup: %s", duplicate_in_history)
# Dupe check off nzb filename
if not res and no_series_dupes:
show_analysis = sabnzbd.newsunpack.analyse_show(self.final_name)
series, season, episode, is_proper = (
show_analysis[key] for key in ("title", "season", "episode", "is_proper")
)
if is_proper and series_propercheck:
logging.debug("Dupe checking series+season+ep in history aborted due to PROPER/REAL/REPACK found")
else:
res = history_db.have_episode(series, season, episode)
logging.debug(
"Dupe checking series+season+ep in history: series=%s, season=%s, episode=%s, result=%s",
series,
season,
episode,
res,
)
if not duplicate_in_history and not duplicate_in_queue and cfg.no_smart_dupes():
self.set_duplicate_key()
logging.debug("Smart duplicate checking (%s): %s", self.final_name, self.duplicate_key)
if self.duplicate_key:
smart_duplicate_in_history = history_db.have_duplicate_key(self.duplicate_key)
logging.debug("Duplicate in history: %s", smart_duplicate_in_history)
return res, series
smart_duplicate_in_queue = sabnzbd.NzbQueue.have_duplicate_key(self.duplicate_key)
logging.debug("Duplicate in queue: %s", smart_duplicate_in_queue)
else:
logging.debug("Unknown type, skipping smart duplicate check")
# Set the correct status
if smart_duplicate_in_queue:
self.duplicate = DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE
elif duplicate_in_queue:
self.duplicate = DuplicateStatus.DUPLICATE_ALTERNATIVE
elif smart_duplicate_in_history:
self.duplicate = DuplicateStatus.SMART_DUPLICATE
elif duplicate_in_history:
self.duplicate = DuplicateStatus.DUPLICATE
def handle_duplicate_action(self):
"""Handle duplicate detection action"""
# If the job is set Force in any way, ignore results of duplicate check
if self.priority == FORCE_PRIORITY:
self.duplicate = None
# Take a direct action
# 1 = Discard
# 2 = Pause
# 3 = Fail (move to History)
# 4 = Tag
if self.duplicate in (DuplicateStatus.DUPLICATE, DuplicateStatus.SMART_DUPLICATE):
smart_duplicate = self.duplicate == DuplicateStatus.SMART_DUPLICATE
if (not smart_duplicate and cfg.no_dupes() == 1) or (smart_duplicate and cfg.no_smart_dupes() == 1):
# Discard
duplicate_warning(T('Ignoring duplicate NZB "%s"'), self.final_name)
self.purge_data()
raise NzbRejected
elif (not smart_duplicate and cfg.no_dupes() == 3) or (smart_duplicate and cfg.no_smart_dupes() == 3):
# Fail (move to History)
duplicate_warning(T('Failing duplicate NZB "%s"'), self.final_name)
raise NzbRejectToHistory(self, T("Duplicate NZB"))
elif (not smart_duplicate and cfg.no_dupes() == 2) or (smart_duplicate and cfg.no_smart_dupes() == 2):
# Pause
duplicate_warning(T('Pausing duplicate NZB "%s"'), self.final_name)
self.pause()
else:
# Tag job
duplicate_warning('%s: "%s"', T("Duplicate NZB"), self.final_name)
# In case of alternative, just pause (unless only tagging is desired)
if (self.duplicate == DuplicateStatus.DUPLICATE_ALTERNATIVE and cfg.no_dupes() != 4) or (
self.duplicate == DuplicateStatus.SMART_DUPLICATE_ALTERNATIVE and cfg.no_smart_dupes() != 4
):
logging.info("Pausing duplicate alternative %s", self.final_name)
self.pause()
def __getstate__(self):
"""Save to pickle file, selecting attributes"""

View File

@@ -23,7 +23,9 @@ import os
import sys
import time
import logging
from objc import YES, NO
from typing import Optional
from objc import YES, NO, lookUpClass
from Foundation import (
NSObject,
NSDate,
@@ -34,6 +36,8 @@ from Foundation import (
NSFont,
NSImage,
NSAttributedString,
NSUserNotification,
NSUserNotificationCenter,
)
from AppKit import (
NSStatusBar,
@@ -65,6 +69,8 @@ from sabnzbd.panic import launch_a_browser
from sabnzbd.api import fast_queue
import sabnzbd.config as config
DefaultUserNotificationCenter = NSUserNotificationCenter.defaultUserNotificationCenter()
status_icons = {
"idle": "icons/sabnzbd_osx_idle.tiff",
"pause": "icons/sabnzbd_osx_pause.tiff",
@@ -83,6 +89,9 @@ class SABnzbdDelegate(NSObject):
while not sabnzbd.WEBUI_READY and not sabnzbd.SABSTOP:
time.sleep(0.5)
# Set this thread as default handler for notification actions
DefaultUserNotificationCenter.setDelegate_(self)
# Do we want the menu
if sabnzbd.cfg.tray_icon():
# Status Bar initialize
@@ -541,3 +550,45 @@ class SABnzbdDelegate(NSObject):
self.status_item.setHighlightMode_(NO)
sabnzbd.shutdown_program()
return NSTerminateNow
def send_notification(
self,
title: str,
subtitle: str,
msg: str,
button_text: Optional[str] = None,
button_action: Optional[str] = None,
):
"""Send a macOS notification, optionally with 1 action button"""
notification = NSUserNotification.alloc().init()
notification.setTitle_(title)
notification.setSubtitle_(subtitle)
notification.setInformativeText_(msg)
notification.setSoundName_("NSUserNotificationDefaultSoundName")
if button_text and button_action:
notification.setHasActionButton_(True)
notification.set_showsButtons_(True)
notification.setActionButtonTitle_(button_text)
notification.setUserInfo_({"value": button_action})
else:
notification.setHasActionButton_(False)
notification.set_showsButtons_(False)
notification.setDeliveryDate_(NSDate.dateWithTimeInterval_sinceDate_(0, NSDate.date()))
DefaultUserNotificationCenter.scheduleNotification_(notification)
def userNotificationCenter_didActivateNotification_(self, center, notification):
"""Handler for the clicks on the notification"""
if notification.activationType() == 1:
# user clicked on the notification (not on a button)
launch_a_browser(sabnzbd.BROWSER_URL, force=True)
elif notification.activationType() == 2:
# User clicked on the action button
if os.path.exists(folder2open := notification.userInfo()["value"]):
os.system('open "%s"' % folder2open)
# Remove this notification after interaction
DefaultUserNotificationCenter._removeDisplayedNotification_(notification)

View File

@@ -29,6 +29,7 @@ from typing import Dict, Optional, Tuple
from sabnzbd.constants import MEBI
from sabnzbd.encoding import correct_unknown_encoding
from sabnzbd.filesystem import get_basename
PROBABLY_PAR2_RE = re.compile(r"(.*)\.vol(\d*)[+\-](\d*)\.par2", re.I)
SCAN_LIMIT = 10 * MEBI
@@ -80,7 +81,7 @@ def analyse_par2(name: str, filepath: Optional[str] = None) -> Tuple[str, int, i
block = m.group(3)
else:
# Base-par2 file
setname = os.path.splitext(name)[0].strip()
setname = get_basename(name).strip()
# Could not parse the filename, need deep inspection
# We already know it's a par2 from the is_parfile
if filepath:

View File

@@ -39,7 +39,14 @@ from sabnzbd.newsunpack import (
is_sfv_file,
)
from threading import Thread
from sabnzbd.misc import on_cleanup_list, is_sample, helpful_warning
from sabnzbd.misc import (
on_cleanup_list,
is_sample,
helpful_warning,
history_updated,
change_queue_complete_action,
run_script,
)
from sabnzbd.filesystem import (
real_path,
get_unique_dir,
@@ -172,7 +179,7 @@ class PostProcessor(Thread):
else:
self.slow_queue.put(nzo)
self.save()
sabnzbd.misc.history_updated()
history_updated()
def remove(self, nzo: NzbObject):
"""Remove given nzo from the queue"""
@@ -181,7 +188,7 @@ class PostProcessor(Thread):
except:
pass
self.save()
sabnzbd.misc.history_updated()
history_updated()
def stop(self):
"""Stop thread after finishing running job"""
@@ -209,9 +216,39 @@ class PostProcessor(Thread):
"""Return True if pp queue is empty"""
return self.slow_queue.empty() and self.fast_queue.empty() and not self.__busy
def get_queue(self) -> List[NzbObject]:
"""Return list of NZOs that still need to be processed"""
return [nzo for nzo in self.history_queue if nzo.work_name]
def get_queue(
self,
search: Optional[str] = None,
categories: Optional[List[str]] = None,
statuses: Optional[List[str]] = None,
nzo_ids: Optional[List[str]] = None,
) -> List[NzbObject]:
"""Return list of NZOs that still need to be processed.
Optionally filtered by the search terms"""
re_search = None
if isinstance(search, str):
# Replace * with .* and ' ' with .
search_text = search.strip().replace("*", ".*").replace(" ", ".*") + ".*?"
try:
re_search = re.compile(search_text, re.I)
except:
logging.error(T("Failed to compile regex for search term: %s"), search_text)
# Need a copy to prevent race conditions
filtered_queue = []
for nzo in self.history_queue[:]:
if not nzo.work_name:
continue
if re_search and not re_search.search(nzo.final_name):
continue
if categories and nzo.cat not in categories:
continue
if statuses and nzo.status not in statuses:
continue
if nzo_ids and nzo.nzo_id not in nzo_ids:
continue
filtered_queue.append(nzo)
return filtered_queue
def get_path(self, nzo_id: str) -> Optional[str]:
"""Return download path for given nzo_id or None when not found"""
@@ -398,7 +435,7 @@ def process_job(nzo: NzbObject) -> bool:
return False
# If we don't need extra par2, we can disconnect
if sabnzbd.NzbQueue.actives(grabs=False) == 0 and cfg.autodisconnect():
if not sabnzbd.NzbQueue.actives(grabs=False) and cfg.autodisconnect():
# This was the last job, close server connections
sabnzbd.Downloader.disconnect()
@@ -593,6 +630,9 @@ def process_job(nzo: NzbObject) -> bool:
# Force error for empty result
all_ok = all_ok and not empty
# See if we need to start an alternative or remove the duplicates
sabnzbd.NzbQueue.handle_duplicate_alternatives(nzo, all_ok)
except:
logging.error(T("Post Processing Failed for %s (%s)"), filename, T("see logfile"))
logging.info("Traceback: ", exc_info=True)
@@ -617,6 +657,7 @@ def process_job(nzo: NzbObject) -> bool:
0,
)
workdir_notifcation_action = workdir_complete
if all_ok:
# If the folder only contains one file OR folder, have that as the path
# Be aware that series/generic/date sorting may move a single file into a folder containing other files
@@ -641,7 +682,13 @@ def process_job(nzo: NzbObject) -> bool:
# Show final status in history
if all_ok:
notifier.send_notification(T("Download Completed"), filename, "complete", nzo.cat)
notifier.send_notification(
T("Download Completed"),
filename,
"complete",
nzo.cat,
{"open_folder": clip_path(workdir_notifcation_action)},
)
nzo.status = Status.COMPLETED
nzo.fail_msg = ""
else:
@@ -658,7 +705,7 @@ def process_job(nzo: NzbObject) -> bool:
# Purge items
history_db.auto_history_purge()
sabnzbd.misc.history_updated()
history_updated()
return True
@@ -718,7 +765,8 @@ def prepare_extraction_path(nzo: NzbObject) -> Tuple[str, str, Sorter, bool, Opt
# Is the unique path different? Then we also need to modify the final path
if prefixed_path != tmp_workdir_complete:
workdir_complete = workdir_complete + os.path.splitext(tmp_workdir_complete)[1]
# The unique path adds an "extension"
workdir_complete = workdir_complete + get_ext(tmp_workdir_complete)
else:
tmp_workdir_complete = workdir_complete
@@ -1040,20 +1088,25 @@ def rar_renamer(nzo: NzbObject) -> int:
def handle_empty_queue():
"""Check if empty queue calls for action"""
if sabnzbd.NzbQueue.actives() == 0:
if not sabnzbd.NzbQueue.actives():
sabnzbd.save_state()
notifier.send_notification("SABnzbd", T("Queue finished"), "queue_done")
notifier.send_notification(
"SABnzbd",
T("Queue finished"),
"queue_done",
actions={"open_complete": cfg.complete_dir.get_clipped_path()},
)
# Perform end-of-queue script
if cfg.end_queue_script():
logging.info("Queue has finished, launching script: %s ", cfg.end_queue_script())
run_script(cfg.end_queue_script())
# Perform end-of-queue action when one is set
if sabnzbd.QUEUECOMPLETEACTION:
logging.info(
"Queue has finished, launching: %s (%s)", sabnzbd.QUEUECOMPLETEACTION, sabnzbd.QUEUECOMPLETEARG
)
if sabnzbd.QUEUECOMPLETEARG:
sabnzbd.QUEUECOMPLETEACTION(sabnzbd.QUEUECOMPLETEARG)
else:
Thread(target=sabnzbd.QUEUECOMPLETEACTION).start()
sabnzbd.misc.change_queue_complete_action(cfg.queue_complete(), new=False)
logging.info("Queue has finished, launching action: %s ", sabnzbd.QUEUECOMPLETEACTION)
Thread(target=sabnzbd.QUEUECOMPLETEACTION).start()
change_queue_complete_action(cfg.queue_complete(), new=False)
# Trigger garbage collection and release of memory
logging.debug("Triggering garbage collection and release of memory")

View File

@@ -27,7 +27,7 @@ import threading
import urllib.parse
import sabnzbd
from sabnzbd.constants import RSS_FILE_NAME, DEFAULT_PRIORITY, DUP_PRIORITY
from sabnzbd.constants import RSS_FILE_NAME, DEFAULT_PRIORITY
from sabnzbd.decorators import synchronized
import sabnzbd.config as config
import sabnzbd.cfg as cfg
@@ -308,8 +308,9 @@ class RSSReader:
myPrio = defPrio
n = 0
if ("F" in reTypes or "S" in reTypes) and (not season or not episode):
show_analysis = sabnzbd.newsunpack.analyse_show(title)
season, episode = show_analysis["season"], show_analysis["episode"]
show_analysis = sabnzbd.sorting.BasicAnalyzer(title)
season = show_analysis.info.get("season")
episode = show_analysis.info.get("episode")
# Match against all filters until an positive or negative match
logging.debug("Size %s", size)
@@ -336,12 +337,7 @@ class RSSReader:
logging.debug("Filter requirement match on rule %d", n)
result = False
break
elif (
reTypes[n] == "S"
and season
and episode
and ep_match(season, episode, regexes[n], title)
):
elif reTypes[n] == "S" and ep_match(season, episode, regexes[n], title):
logging.debug("Filter matched on rule %d", n)
result = True
break
@@ -391,19 +387,6 @@ class RSSReader:
elif not ((rePrios[n] != str(DEFAULT_PRIORITY)) or category):
myPrio = catPrio
if cfg.no_dupes() and self.check_duplicate(title):
if cfg.no_dupes() == 1:
# Dupe-detection: Discard
logging.info("Ignoring duplicate job %s", title)
continue
elif cfg.no_dupes() == 3:
# Dupe-detection: Fail
# We accept it so the Queue can send it to the History
logging.info("Found duplicate job %s", title)
else:
# Dupe-detection: Pause
myPrio = DUP_PRIORITY
act = download and not first
if link in jobs:
act = act and not jobs[link].get("status", "").endswith("*")
@@ -413,6 +396,7 @@ class RSSReader:
star = first
if result:
_HandleLink(
feed,
jobs,
link,
infourl,
@@ -435,6 +419,7 @@ class RSSReader:
new_downloads.append(title)
else:
_HandleLink(
feed,
jobs,
link,
infourl,
@@ -546,18 +531,6 @@ class RSSReader:
if self.jobs[feed][item]["status"] == "D":
self.jobs[feed][item]["status"] = "D-"
def check_duplicate(self, title):
"""Check if this title was in this or other feeds
Return matching feed name
"""
title = title.lower()
for fd in self.jobs:
for lk in self.jobs[fd]:
item = self.jobs[fd][lk]
if item.get("status", " ")[0] == "D" and item.get("title", "").lower() == title:
return fd
return ""
def patch_feedparser():
"""Apply options that work for SABnzbd
@@ -605,6 +578,7 @@ def patch_feedparser():
def _HandleLink(
feed,
jobs,
link,
infourl,
@@ -653,8 +627,17 @@ def _HandleLink(
if download:
jobs[link]["status"] = "D"
jobs[link]["time_downloaded"] = time.localtime()
logging.info("Adding %s (%s) to queue", link, title)
sabnzbd.urlgrabber.add_url(link, pp=pp, script=script, cat=cat, priority=priority, nzbname=nzbname)
sabnzbd.urlgrabber.add_url(
link,
pp=pp,
script=script,
cat=cat,
priority=priority,
nzbname=nzbname,
nzo_info={"RSS": feed},
)
else:
if star:
jobs[link]["status"] = flag + "*"

View File

@@ -35,6 +35,7 @@ from sabnzbd.utils.systrayiconthread import SysTrayIconThread
class SABTrayThread(SysTrayIconThread):
# When updating these paths, also update them in the NSIS script!
sabicons = {
"default": "icons/sabnzbd16_32.ico",
"green": "icons/sabnzbd16_32green.ico",

View File

@@ -28,6 +28,7 @@ SKIN_TEXT = {
"stage-unpack": TT("Unpack"), #: PP phase "unpack"
"stage-deobfuscate": TT("Deobfuscate"), #: PP phase "deobfuscate"
"stage-script": TT("Script"), #: PP phase "script"
"stage-rss": TT("RSS"), #: PP RSS feed of the NZB
"stage-source": TT("Source"), #: PP Source of the NZB (path or URL)
"stage-servers": TT("Servers"), #: PP Distribution over servers
"post-Completed": TT("Completed"), #: PP status
@@ -169,7 +170,6 @@ SKIN_TEXT = {
"mode": TT("Processing"), #: Queue page table column header
"name": TT("Name"), #: Queue page table column header
"button-retry": TT("Retry"), #: Queue page button
"eoq-actions": TT("Actions"), #: Queue end-of-queue selection box
"eoq-scripts": TT("Scripts"), #: Queue page table, script selection menu
"purgeQueue": TT("Purge Queue"), #: Queue page button
"purgeQueueConf": TT("Delete all items from the queue?"), #: Confirmation popup
@@ -415,17 +415,13 @@ SKIN_TEXT = {
),
"opt-pause_on_pwrar": TT("Action when encrypted RAR is downloaded"),
"explain-pause_on_pwrar": TT('In case of "Pause", you\'ll need to set a password and resume the job.'),
"opt-no_dupes": TT("Detect Duplicate Downloads"),
"explain-no_dupes": TT(
"Detect identical NZB files (based on items in your History or files in .nzb Backup Folder)"
),
"opt-no_series_dupes": TT("Detect duplicate episodes in series"),
"explain-no_series_dupes": TT(
'Detect identical episodes in series (based on "name/season/episode" of items in your History)'
),
"opt-series_propercheck": TT("Allow proper releases"),
"explain-series_propercheck": TT(
"Bypass series duplicate detection if PROPER, REAL or REPACK is detected in the download name"
"opt-no_dupes": TT("Identical download detection"),
"explain-no_dupes": TT("Detect identical downloads based on name or NZB contents."),
"opt-no_smart_dupes": TT("Smart duplicate detection"),
"explain-no_smart_dupes": TT("Detect duplicates based on analysis of the filename."),
"opt-dupes_propercheck": TT("Allow proper releases"),
"explain-dupes_propercheck": TT(
"Bypass smart duplicate detection if PROPER, REAL or REPACK is detected in the download name."
),
"nodupes-off": TT("Off"), #: Three way switch for duplicates
"nodupes-ignore": TT("Discard"), #: Four way switch for duplicates
@@ -453,14 +449,12 @@ SKIN_TEXT = {
),
"opt-pre_script": TT("Pre-queue user script"),
"explain-pre_script": TT("Used before an NZB enters the queue."),
"opt-end_queue_script": TT("On queue finish script"),
"explain-end_queue_script": TT("Executed after the queue finishes downloading."),
"opt-par_option": TT("Extra PAR2 Parameters"),
"explain-par_option": TT("Read the Wiki Help on this!"),
"opt-nice": TT("Nice Parameters"),
"explain-nice": TT("Read the Wiki Help on this!"),
"opt-ionice": TT("IONice Parameters"),
"explain-ionice": TT("Read the Wiki Help on this!"),
"opt-win_process_prio": TT("External process priority"),
"explain-win_process_prio": TT("Read the Wiki Help on this!"),
"win_process_prio-high": TT("High"),
"win_process_prio-normal": TT("Normal"),
"win_process_prio-low": TT("Low"),
@@ -689,7 +683,6 @@ SKIN_TEXT = {
"opt-nscript_parameters": TT("Parameters"), #: Notification Script settings
"explain-nscript_enable": TT("Executes a custom script"), #: Notification Scriptsettings
"explain-nscript_script": TT("Which script should we execute for notification?"), #: Notification Scriptsettings
"explain-nscript_parameters": TT("Read the Wiki Help on this!"), #: Notification Script settings
# Config->Cat
"explain-catTags": TT(
'Indexers can supply a category inside the NZB which SABnzbd will try to match to the categories defined below. Additionally, you can add terms to "Indexer Categories / Groups" to match more categories. Use commas to separate terms. Wildcards in the terms are supported. <br>More information can be found on the Wiki.'

View File

@@ -73,8 +73,8 @@ class Sorter:
self,
nzo: Optional[NzbObject],
job_name: str,
path: str,
cat: str,
path: Optional[str] = None,
cat: Optional[str] = None,
force: Optional[bool] = False,
sorter_config: Optional[dict] = None,
):
@@ -96,6 +96,9 @@ class Sorter:
self.is_season_pack = False
self.season_pack_setname = ""
self.match_sorters()
def match_sorters(self):
# If a sorter configuration is passed as an argument, only use that one
sorters = [self.sorter_config] if self.sorter_config else config.get_ordered_sorters()
@@ -260,7 +263,7 @@ class Sorter:
except TypeError:
pass
def is_proper(self):
def is_proper(self) -> bool:
"""Determine if the release is tagged 'Proper'. Note that guessit also sets this for similar
tags such as 'Real' and 'Repack', saving us the trouble of checking for additional keywords."""
if not self.guess:
@@ -582,6 +585,23 @@ class Sorter:
return move_to_parent_directory(base_path)
class BasicAnalyzer(Sorter):
def __init__(self, job_name: str):
"""Very basic sorter that doesn't require a config"""
super().__init__(nzo=None, job_name=job_name)
# Directly trigger setting all values
self.get_values()
def match_sorters(self):
"""Much more basic matching"""
self.guess = guess_what(self.original_job_name)
# Set the detected job type
self.type = self.guess["type"]
if self.guess["type"] == "episode":
self.type = "date" if self.guess.get("date") else "tv"
def ends_in_file(path: str) -> bool:
"""Return True when path ends with '.%ext' or '%fn' while allowing for a lowercase marker"""
return bool(RE_ENDEXT.search(path) or RE_ENDFN.search(path))
@@ -612,9 +632,8 @@ def move_to_parent_directory(workdir: str) -> Tuple[str, bool]:
return dest, True
def guess_what(name: str, sort_type: Optional[str] = None) -> MatchesDict:
"""Guess metadata for movies or episodes from their name. The sort_type ('movie' or 'episode')
is passed as a hint to guessit, if given."""
def guess_what(name: str) -> MatchesDict:
"""Guess metadata for movies or episodes from their name."""
if not name:
raise ValueError("Need a name for guessing")
@@ -633,9 +652,6 @@ def guess_what(name: str, sort_type: Optional[str] = None) -> MatchesDict:
"excludes": EXCLUDED_GUESSIT_PROPERTIES,
"date_year_first": True, # Make sure also short-dates are detected as YY-MM-DD
}
if sort_type:
# Hint the type if known
guessit_options["type"] = sort_type
guess = guessit.api.guessit(digit_fix + name, options=guessit_options)
logging.debug("Initial guess for %s is %s", digit_fix + name, guess)
@@ -650,7 +666,7 @@ def guess_what(name: str, sort_type: Optional[str] = None) -> MatchesDict:
# Try to avoid setting the type to movie on arbitrary jobs (e.g. 'Setup.exe') just because guessit defaults to that
table = str.maketrans({char: "" for char in whitespace + "_.-()[]{}"})
if guess.get("type") == "movie" and not sort_type == "movie": # No movie hint
if guess.get("type") == "movie":
if (
guess.get("title", "").translate(table) == name.translate(table) # Check for full name used as title
or any(
@@ -660,7 +676,9 @@ def guess_what(name: str, sort_type: Optional[str] = None) -> MatchesDict:
[key in guess for key in ("year", "screen_size", "video_codec")]
) # No typical movie properties set
or (
name.lower().startswith("http://") and name.lower().endswith(".nzb") and guess.get("container" == "nzb")
name.lower().startswith(("http://", "https://"))
and name.lower().endswith(".nzb")
and guess.get("container" == "nzb")
) # URL to an nzb file, can happen when pre-queue script rejects a job
):
guess["type"] = "unknown"

View File

@@ -31,7 +31,7 @@ from http.client import IncompleteRead, HTTPResponse
from mailbox import Message
from threading import Thread
import base64
from typing import Tuple, Optional, Union
from typing import Tuple, Optional, Union, List, Dict, Any
import sabnzbd
from sabnzbd.constants import DEF_TIMEOUT, FUTURE_Q_FOLDER, VALID_NZB_FILES, Status, VALID_ARCHIVES, DEFAULT_PRIORITY
@@ -42,7 +42,7 @@ import sabnzbd.emailer as emailer
import sabnzbd.notifier as notifier
from sabnzbd.encoding import ubtou, utob
from sabnzbd.nzbparser import AddNzbFileResult
from sabnzbd.nzbstuff import NzbObject
from sabnzbd.nzbstuff import NzbObject, NzbRejected, NzbRejectToHistory
class URLGrabber(Thread):
@@ -112,8 +112,7 @@ class URLGrabber(Thread):
continue
filename = None
category = None
nzo_info = {}
nzo_info = future_nzo.nzo_info
wait = 0
retry = True
fetch_request = None
@@ -150,11 +149,19 @@ class URLGrabber(Thread):
value = fetch_request.headers[hdr]
except:
continue
# Skip empty values
if not value:
continue
if item in ("category_id", "x-dnzb-category"):
category = value
elif item in ("x-dnzb-moreinfo",):
# Use indexer category in case no specific one was set
if value and future_nzo.cat in (None, "*"):
if indexer_cat := misc.cat_convert(value):
future_nzo.cat = indexer_cat
elif item == "x-dnzb-moreinfo":
nzo_info["more_info"] = value
elif item in ("x-dnzb-name",):
elif item == "x-dnzb-name":
filename = value
if not filename.endswith(".nzb"):
filename += ".nzb"
@@ -172,10 +179,10 @@ class URLGrabber(Thread):
nzo_info["password"] = value
elif item == "retry-after":
wait = misc.int_conv(value)
# Get filename from Content-Disposition header
if not filename and "filename" in value:
filename = filename_from_content_disposition(value)
elif item == "content-disposition":
# Get filename from Content-Disposition header
if not filename and "filename" in value:
filename = filename_from_content_disposition(value)
if wait:
# For sites that have a rate-limiting attribute
@@ -207,14 +214,6 @@ class URLGrabber(Thread):
# Sometimes the filename contains the full URL, duh!
filename = filename[filename.find("&nzbname=") + 9 :]
pp = future_nzo.pp
script = future_nzo.script
cat = future_nzo.cat
if (cat is None or cat == "*") and category:
cat = misc.cat_convert(category)
priority = future_nzo.priority
nzbname = future_nzo.custom_name
# process data
if not data:
try:
@@ -246,11 +245,11 @@ class URLGrabber(Thread):
if sabnzbd.filesystem.get_ext(filename) in VALID_ARCHIVES + VALID_NZB_FILES:
res, _ = sabnzbd.nzbparser.add_nzbfile(
path,
pp=pp,
script=script,
cat=cat,
priority=priority,
nzbname=nzbname,
pp=future_nzo.pp,
script=future_nzo.script,
cat=future_nzo.cat,
priority=future_nzo.priority,
nzbname=future_nzo.custom_name,
nzo_info=nzo_info,
url=future_nzo.url,
keep=False,
@@ -300,6 +299,10 @@ class URLGrabber(Thread):
# Failed fetch
msg = T("URL Fetching failed; %s") % msg
# Add RSS source
if rss_feed := nzo.nzo_info.get("RSS"):
nzo.set_unpack_info("RSS", rss_feed, unique=True)
# Mark as failed and set the info why
nzo.set_unpack_info("Source", url)
nzo.set_unpack_info("Source", msg)
@@ -313,8 +316,7 @@ class URLGrabber(Thread):
nzo.cat, _, nzo.script, _ = misc.cat_to_opts(nzo.cat, script=nzo.script)
# Add to history and run script if desired
sabnzbd.NzbQueue.remove(nzo.nzo_id)
sabnzbd.PostProcessor.process(nzo)
sabnzbd.NzbQueue.fail_to_history(nzo)
def _build_request(url: str) -> HTTPResponse:
@@ -372,11 +374,9 @@ def filename_from_content_disposition(content_disposition: str) -> Optional[str]
filename_from_content_disposition('attachment; filename=jakubroztocil-httpie-0.4.1-20-g40bd8f6.tar.gz')
should return: 'jakubroztocil-httpie-0.4.1-20-g40bd8f6.tar.gz'
"""
filename = Message(f"Content-Disposition: attachment; {content_disposition}").get_filename()
if filename:
if filename := Message(f"Content-Disposition: attachment; {content_disposition}").get_filename():
# Basic sanitation
filename = os.path.basename(filename).lstrip(".").strip()
if filename:
if filename := os.path.basename(filename).lstrip(".").strip():
return filename
@@ -385,33 +385,48 @@ def add_url(
pp: Optional[Union[int, str]] = None,
script: Optional[str] = None,
cat: Optional[str] = None,
priority: Optional[Union[int, str]] = DEFAULT_PRIORITY,
priority: Optional[Union[int, str]] = None,
nzbname: Optional[str] = None,
password: Optional[str] = None,
):
nzo_info: Optional[Dict[str, Any]] = None,
dup_check: bool = True,
) -> Tuple[AddNzbFileResult, List[str]]:
"""Add NZB based on a URL, attributes optional"""
if not url.lower().startswith("http"):
return
if not pp or pp == "-1":
pp = None
if script and script.lower() == "default":
script = None
if cat and cat.lower() == "default":
cat = None
logging.info("Fetching %s", url)
# Add feed name if it came from RSS
msg = T("Trying to fetch NZB from %s") % url
if nzbname:
msg = "%s - %s" % (nzbname, msg)
return AddNzbFileResult.NO_FILES_FOUND, []
# Generate the placeholder
future_nzo = sabnzbd.NzbQueue.generate_future(msg, pp, script, cat, url=url, priority=priority, nzbname=nzbname)
logging.debug("Creating placeholder NZO for %s", url)
msg = T("Trying to fetch NZB from %s") % url
result: AddNzbFileResult = AddNzbFileResult.OK
future_nzo = None
nzo_ids = []
try:
future_nzo = NzbObject(
filename=msg,
pp=pp,
script=script,
futuretype=True,
cat=cat,
url=url,
priority=priority,
password=password,
nzbname=nzbname,
status=Status.GRABBING,
nzo_info=nzo_info,
dup_check=dup_check,
)
except NzbRejected:
# Rejected as duplicate
result = AddNzbFileResult.ERROR
except NzbRejectToHistory as err:
# Duplicate directed to history
sabnzbd.NzbQueue.fail_to_history(err.nzo)
nzo_ids.append(err.nzo.nzo_id)
# Set password
if not future_nzo.password:
future_nzo.password = password
# Success
if future_nzo:
nzo_ids.append(sabnzbd.NzbQueue.add(future_nzo))
sabnzbd.URLGrabber.add(url, future_nzo)
# Get it!
sabnzbd.URLGrabber.add(url, future_nzo)
return future_nzo.nzo_id
return result, nzo_ids

View File

@@ -75,8 +75,8 @@ def generate_local_cert(private_key, days_valid=3560, output_file="cert.cert", L
.subject_name(subject)
.issuer_name(issuer)
.public_key(private_key.public_key())
.not_valid_before(datetime.datetime.utcnow())
.not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=days_valid))
.not_valid_before(datetime.datetime.now(datetime.timezone.utc))
.not_valid_after(datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=days_valid))
.serial_number(x509.random_serial_number())
.add_extension(x509.SubjectAlternativeName(san_list), critical=True)
.sign(private_key, hashes.SHA256(), default_backend())

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